| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226 |
- <!doctype html>
- <html lang="en">
- <head>
- <title>Code coverage report for modules/book-generator/langgraph-controller.ts</title>
- <meta charset="utf-8" />
- <link rel="stylesheet" href="../../prettify.css" />
- <link rel="stylesheet" href="../../base.css" />
- <link rel="shortcut icon" type="image/x-icon" href="../../favicon.png" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <style type='text/css'>
- .coverage-summary .sorter {
- background-image: url(../../sort-arrow-sprite.png);
- }
- </style>
- </head>
-
- <body>
- <div class='wrapper'>
- <div class='pad1'>
- <h1><a href="../../index.html">All files</a> / <a href="index.html">modules/book-generator</a> langgraph-controller.ts</h1>
- <div class='clearfix'>
-
- <div class='fl pad1y space-right2'>
- <span class="strong">0% </span>
- <span class="quiet">Statements</span>
- <span class='fraction'>0/2220</span>
- </div>
-
-
- <div class='fl pad1y space-right2'>
- <span class="strong">0% </span>
- <span class="quiet">Branches</span>
- <span class='fraction'>0/1</span>
- </div>
-
-
- <div class='fl pad1y space-right2'>
- <span class="strong">0% </span>
- <span class="quiet">Functions</span>
- <span class='fraction'>0/1</span>
- </div>
-
-
- <div class='fl pad1y space-right2'>
- <span class="strong">0% </span>
- <span class="quiet">Lines</span>
- <span class='fraction'>0/2220</span>
- </div>
-
-
- </div>
- <p class="quiet">
- Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
- </p>
- <template id="filterTemplate">
- <div class="quiet">
- Filter:
- <input type="search" id="fileSearch">
- </div>
- </template>
- </div>
- <div class='status-line low'></div>
- <pre><table class="coverage">
- <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
- <a name='L2'></a><a href='#L2'>2</a>
- <a name='L3'></a><a href='#L3'>3</a>
- <a name='L4'></a><a href='#L4'>4</a>
- <a name='L5'></a><a href='#L5'>5</a>
- <a name='L6'></a><a href='#L6'>6</a>
- <a name='L7'></a><a href='#L7'>7</a>
- <a name='L8'></a><a href='#L8'>8</a>
- <a name='L9'></a><a href='#L9'>9</a>
- <a name='L10'></a><a href='#L10'>10</a>
- <a name='L11'></a><a href='#L11'>11</a>
- <a name='L12'></a><a href='#L12'>12</a>
- <a name='L13'></a><a href='#L13'>13</a>
- <a name='L14'></a><a href='#L14'>14</a>
- <a name='L15'></a><a href='#L15'>15</a>
- <a name='L16'></a><a href='#L16'>16</a>
- <a name='L17'></a><a href='#L17'>17</a>
- <a name='L18'></a><a href='#L18'>18</a>
- <a name='L19'></a><a href='#L19'>19</a>
- <a name='L20'></a><a href='#L20'>20</a>
- <a name='L21'></a><a href='#L21'>21</a>
- <a name='L22'></a><a href='#L22'>22</a>
- <a name='L23'></a><a href='#L23'>23</a>
- <a name='L24'></a><a href='#L24'>24</a>
- <a name='L25'></a><a href='#L25'>25</a>
- <a name='L26'></a><a href='#L26'>26</a>
- <a name='L27'></a><a href='#L27'>27</a>
- <a name='L28'></a><a href='#L28'>28</a>
- <a name='L29'></a><a href='#L29'>29</a>
- <a name='L30'></a><a href='#L30'>30</a>
- <a name='L31'></a><a href='#L31'>31</a>
- <a name='L32'></a><a href='#L32'>32</a>
- <a name='L33'></a><a href='#L33'>33</a>
- <a name='L34'></a><a href='#L34'>34</a>
- <a name='L35'></a><a href='#L35'>35</a>
- <a name='L36'></a><a href='#L36'>36</a>
- <a name='L37'></a><a href='#L37'>37</a>
- <a name='L38'></a><a href='#L38'>38</a>
- <a name='L39'></a><a href='#L39'>39</a>
- <a name='L40'></a><a href='#L40'>40</a>
- <a name='L41'></a><a href='#L41'>41</a>
- <a name='L42'></a><a href='#L42'>42</a>
- <a name='L43'></a><a href='#L43'>43</a>
- <a name='L44'></a><a href='#L44'>44</a>
- <a name='L45'></a><a href='#L45'>45</a>
- <a name='L46'></a><a href='#L46'>46</a>
- <a name='L47'></a><a href='#L47'>47</a>
- <a name='L48'></a><a href='#L48'>48</a>
- <a name='L49'></a><a href='#L49'>49</a>
- <a name='L50'></a><a href='#L50'>50</a>
- <a name='L51'></a><a href='#L51'>51</a>
- <a name='L52'></a><a href='#L52'>52</a>
- <a name='L53'></a><a href='#L53'>53</a>
- <a name='L54'></a><a href='#L54'>54</a>
- <a name='L55'></a><a href='#L55'>55</a>
- <a name='L56'></a><a href='#L56'>56</a>
- <a name='L57'></a><a href='#L57'>57</a>
- <a name='L58'></a><a href='#L58'>58</a>
- <a name='L59'></a><a href='#L59'>59</a>
- <a name='L60'></a><a href='#L60'>60</a>
- <a name='L61'></a><a href='#L61'>61</a>
- <a name='L62'></a><a href='#L62'>62</a>
- <a name='L63'></a><a href='#L63'>63</a>
- <a name='L64'></a><a href='#L64'>64</a>
- <a name='L65'></a><a href='#L65'>65</a>
- <a name='L66'></a><a href='#L66'>66</a>
- <a name='L67'></a><a href='#L67'>67</a>
- <a name='L68'></a><a href='#L68'>68</a>
- <a name='L69'></a><a href='#L69'>69</a>
- <a name='L70'></a><a href='#L70'>70</a>
- <a name='L71'></a><a href='#L71'>71</a>
- <a name='L72'></a><a href='#L72'>72</a>
- <a name='L73'></a><a href='#L73'>73</a>
- <a name='L74'></a><a href='#L74'>74</a>
- <a name='L75'></a><a href='#L75'>75</a>
- <a name='L76'></a><a href='#L76'>76</a>
- <a name='L77'></a><a href='#L77'>77</a>
- <a name='L78'></a><a href='#L78'>78</a>
- <a name='L79'></a><a href='#L79'>79</a>
- <a name='L80'></a><a href='#L80'>80</a>
- <a name='L81'></a><a href='#L81'>81</a>
- <a name='L82'></a><a href='#L82'>82</a>
- <a name='L83'></a><a href='#L83'>83</a>
- <a name='L84'></a><a href='#L84'>84</a>
- <a name='L85'></a><a href='#L85'>85</a>
- <a name='L86'></a><a href='#L86'>86</a>
- <a name='L87'></a><a href='#L87'>87</a>
- <a name='L88'></a><a href='#L88'>88</a>
- <a name='L89'></a><a href='#L89'>89</a>
- <a name='L90'></a><a href='#L90'>90</a>
- <a name='L91'></a><a href='#L91'>91</a>
- <a name='L92'></a><a href='#L92'>92</a>
- <a name='L93'></a><a href='#L93'>93</a>
- <a name='L94'></a><a href='#L94'>94</a>
- <a name='L95'></a><a href='#L95'>95</a>
- <a name='L96'></a><a href='#L96'>96</a>
- <a name='L97'></a><a href='#L97'>97</a>
- <a name='L98'></a><a href='#L98'>98</a>
- <a name='L99'></a><a href='#L99'>99</a>
- <a name='L100'></a><a href='#L100'>100</a>
- <a name='L101'></a><a href='#L101'>101</a>
- <a name='L102'></a><a href='#L102'>102</a>
- <a name='L103'></a><a href='#L103'>103</a>
- <a name='L104'></a><a href='#L104'>104</a>
- <a name='L105'></a><a href='#L105'>105</a>
- <a name='L106'></a><a href='#L106'>106</a>
- <a name='L107'></a><a href='#L107'>107</a>
- <a name='L108'></a><a href='#L108'>108</a>
- <a name='L109'></a><a href='#L109'>109</a>
- <a name='L110'></a><a href='#L110'>110</a>
- <a name='L111'></a><a href='#L111'>111</a>
- <a name='L112'></a><a href='#L112'>112</a>
- <a name='L113'></a><a href='#L113'>113</a>
- <a name='L114'></a><a href='#L114'>114</a>
- <a name='L115'></a><a href='#L115'>115</a>
- <a name='L116'></a><a href='#L116'>116</a>
- <a name='L117'></a><a href='#L117'>117</a>
- <a name='L118'></a><a href='#L118'>118</a>
- <a name='L119'></a><a href='#L119'>119</a>
- <a name='L120'></a><a href='#L120'>120</a>
- <a name='L121'></a><a href='#L121'>121</a>
- <a name='L122'></a><a href='#L122'>122</a>
- <a name='L123'></a><a href='#L123'>123</a>
- <a name='L124'></a><a href='#L124'>124</a>
- <a name='L125'></a><a href='#L125'>125</a>
- <a name='L126'></a><a href='#L126'>126</a>
- <a name='L127'></a><a href='#L127'>127</a>
- <a name='L128'></a><a href='#L128'>128</a>
- <a name='L129'></a><a href='#L129'>129</a>
- <a name='L130'></a><a href='#L130'>130</a>
- <a name='L131'></a><a href='#L131'>131</a>
- <a name='L132'></a><a href='#L132'>132</a>
- <a name='L133'></a><a href='#L133'>133</a>
- <a name='L134'></a><a href='#L134'>134</a>
- <a name='L135'></a><a href='#L135'>135</a>
- <a name='L136'></a><a href='#L136'>136</a>
- <a name='L137'></a><a href='#L137'>137</a>
- <a name='L138'></a><a href='#L138'>138</a>
- <a name='L139'></a><a href='#L139'>139</a>
- <a name='L140'></a><a href='#L140'>140</a>
- <a name='L141'></a><a href='#L141'>141</a>
- <a name='L142'></a><a href='#L142'>142</a>
- <a name='L143'></a><a href='#L143'>143</a>
- <a name='L144'></a><a href='#L144'>144</a>
- <a name='L145'></a><a href='#L145'>145</a>
- <a name='L146'></a><a href='#L146'>146</a>
- <a name='L147'></a><a href='#L147'>147</a>
- <a name='L148'></a><a href='#L148'>148</a>
- <a name='L149'></a><a href='#L149'>149</a>
- <a name='L150'></a><a href='#L150'>150</a>
- <a name='L151'></a><a href='#L151'>151</a>
- <a name='L152'></a><a href='#L152'>152</a>
- <a name='L153'></a><a href='#L153'>153</a>
- <a name='L154'></a><a href='#L154'>154</a>
- <a name='L155'></a><a href='#L155'>155</a>
- <a name='L156'></a><a href='#L156'>156</a>
- <a name='L157'></a><a href='#L157'>157</a>
- <a name='L158'></a><a href='#L158'>158</a>
- <a name='L159'></a><a href='#L159'>159</a>
- <a name='L160'></a><a href='#L160'>160</a>
- <a name='L161'></a><a href='#L161'>161</a>
- <a name='L162'></a><a href='#L162'>162</a>
- <a name='L163'></a><a href='#L163'>163</a>
- <a name='L164'></a><a href='#L164'>164</a>
- <a name='L165'></a><a href='#L165'>165</a>
- <a name='L166'></a><a href='#L166'>166</a>
- <a name='L167'></a><a href='#L167'>167</a>
- <a name='L168'></a><a href='#L168'>168</a>
- <a name='L169'></a><a href='#L169'>169</a>
- <a name='L170'></a><a href='#L170'>170</a>
- <a name='L171'></a><a href='#L171'>171</a>
- <a name='L172'></a><a href='#L172'>172</a>
- <a name='L173'></a><a href='#L173'>173</a>
- <a name='L174'></a><a href='#L174'>174</a>
- <a name='L175'></a><a href='#L175'>175</a>
- <a name='L176'></a><a href='#L176'>176</a>
- <a name='L177'></a><a href='#L177'>177</a>
- <a name='L178'></a><a href='#L178'>178</a>
- <a name='L179'></a><a href='#L179'>179</a>
- <a name='L180'></a><a href='#L180'>180</a>
- <a name='L181'></a><a href='#L181'>181</a>
- <a name='L182'></a><a href='#L182'>182</a>
- <a name='L183'></a><a href='#L183'>183</a>
- <a name='L184'></a><a href='#L184'>184</a>
- <a name='L185'></a><a href='#L185'>185</a>
- <a name='L186'></a><a href='#L186'>186</a>
- <a name='L187'></a><a href='#L187'>187</a>
- <a name='L188'></a><a href='#L188'>188</a>
- <a name='L189'></a><a href='#L189'>189</a>
- <a name='L190'></a><a href='#L190'>190</a>
- <a name='L191'></a><a href='#L191'>191</a>
- <a name='L192'></a><a href='#L192'>192</a>
- <a name='L193'></a><a href='#L193'>193</a>
- <a name='L194'></a><a href='#L194'>194</a>
- <a name='L195'></a><a href='#L195'>195</a>
- <a name='L196'></a><a href='#L196'>196</a>
- <a name='L197'></a><a href='#L197'>197</a>
- <a name='L198'></a><a href='#L198'>198</a>
- <a name='L199'></a><a href='#L199'>199</a>
- <a name='L200'></a><a href='#L200'>200</a>
- <a name='L201'></a><a href='#L201'>201</a>
- <a name='L202'></a><a href='#L202'>202</a>
- <a name='L203'></a><a href='#L203'>203</a>
- <a name='L204'></a><a href='#L204'>204</a>
- <a name='L205'></a><a href='#L205'>205</a>
- <a name='L206'></a><a href='#L206'>206</a>
- <a name='L207'></a><a href='#L207'>207</a>
- <a name='L208'></a><a href='#L208'>208</a>
- <a name='L209'></a><a href='#L209'>209</a>
- <a name='L210'></a><a href='#L210'>210</a>
- <a name='L211'></a><a href='#L211'>211</a>
- <a name='L212'></a><a href='#L212'>212</a>
- <a name='L213'></a><a href='#L213'>213</a>
- <a name='L214'></a><a href='#L214'>214</a>
- <a name='L215'></a><a href='#L215'>215</a>
- <a name='L216'></a><a href='#L216'>216</a>
- <a name='L217'></a><a href='#L217'>217</a>
- <a name='L218'></a><a href='#L218'>218</a>
- <a name='L219'></a><a href='#L219'>219</a>
- <a name='L220'></a><a href='#L220'>220</a>
- <a name='L221'></a><a href='#L221'>221</a>
- <a name='L222'></a><a href='#L222'>222</a>
- <a name='L223'></a><a href='#L223'>223</a>
- <a name='L224'></a><a href='#L224'>224</a>
- <a name='L225'></a><a href='#L225'>225</a>
- <a name='L226'></a><a href='#L226'>226</a>
- <a name='L227'></a><a href='#L227'>227</a>
- <a name='L228'></a><a href='#L228'>228</a>
- <a name='L229'></a><a href='#L229'>229</a>
- <a name='L230'></a><a href='#L230'>230</a>
- <a name='L231'></a><a href='#L231'>231</a>
- <a name='L232'></a><a href='#L232'>232</a>
- <a name='L233'></a><a href='#L233'>233</a>
- <a name='L234'></a><a href='#L234'>234</a>
- <a name='L235'></a><a href='#L235'>235</a>
- <a name='L236'></a><a href='#L236'>236</a>
- <a name='L237'></a><a href='#L237'>237</a>
- <a name='L238'></a><a href='#L238'>238</a>
- <a name='L239'></a><a href='#L239'>239</a>
- <a name='L240'></a><a href='#L240'>240</a>
- <a name='L241'></a><a href='#L241'>241</a>
- <a name='L242'></a><a href='#L242'>242</a>
- <a name='L243'></a><a href='#L243'>243</a>
- <a name='L244'></a><a href='#L244'>244</a>
- <a name='L245'></a><a href='#L245'>245</a>
- <a name='L246'></a><a href='#L246'>246</a>
- <a name='L247'></a><a href='#L247'>247</a>
- <a name='L248'></a><a href='#L248'>248</a>
- <a name='L249'></a><a href='#L249'>249</a>
- <a name='L250'></a><a href='#L250'>250</a>
- <a name='L251'></a><a href='#L251'>251</a>
- <a name='L252'></a><a href='#L252'>252</a>
- <a name='L253'></a><a href='#L253'>253</a>
- <a name='L254'></a><a href='#L254'>254</a>
- <a name='L255'></a><a href='#L255'>255</a>
- <a name='L256'></a><a href='#L256'>256</a>
- <a name='L257'></a><a href='#L257'>257</a>
- <a name='L258'></a><a href='#L258'>258</a>
- <a name='L259'></a><a href='#L259'>259</a>
- <a name='L260'></a><a href='#L260'>260</a>
- <a name='L261'></a><a href='#L261'>261</a>
- <a name='L262'></a><a href='#L262'>262</a>
- <a name='L263'></a><a href='#L263'>263</a>
- <a name='L264'></a><a href='#L264'>264</a>
- <a name='L265'></a><a href='#L265'>265</a>
- <a name='L266'></a><a href='#L266'>266</a>
- <a name='L267'></a><a href='#L267'>267</a>
- <a name='L268'></a><a href='#L268'>268</a>
- <a name='L269'></a><a href='#L269'>269</a>
- <a name='L270'></a><a href='#L270'>270</a>
- <a name='L271'></a><a href='#L271'>271</a>
- <a name='L272'></a><a href='#L272'>272</a>
- <a name='L273'></a><a href='#L273'>273</a>
- <a name='L274'></a><a href='#L274'>274</a>
- <a name='L275'></a><a href='#L275'>275</a>
- <a name='L276'></a><a href='#L276'>276</a>
- <a name='L277'></a><a href='#L277'>277</a>
- <a name='L278'></a><a href='#L278'>278</a>
- <a name='L279'></a><a href='#L279'>279</a>
- <a name='L280'></a><a href='#L280'>280</a>
- <a name='L281'></a><a href='#L281'>281</a>
- <a name='L282'></a><a href='#L282'>282</a>
- <a name='L283'></a><a href='#L283'>283</a>
- <a name='L284'></a><a href='#L284'>284</a>
- <a name='L285'></a><a href='#L285'>285</a>
- <a name='L286'></a><a href='#L286'>286</a>
- <a name='L287'></a><a href='#L287'>287</a>
- <a name='L288'></a><a href='#L288'>288</a>
- <a name='L289'></a><a href='#L289'>289</a>
- <a name='L290'></a><a href='#L290'>290</a>
- <a name='L291'></a><a href='#L291'>291</a>
- <a name='L292'></a><a href='#L292'>292</a>
- <a name='L293'></a><a href='#L293'>293</a>
- <a name='L294'></a><a href='#L294'>294</a>
- <a name='L295'></a><a href='#L295'>295</a>
- <a name='L296'></a><a href='#L296'>296</a>
- <a name='L297'></a><a href='#L297'>297</a>
- <a name='L298'></a><a href='#L298'>298</a>
- <a name='L299'></a><a href='#L299'>299</a>
- <a name='L300'></a><a href='#L300'>300</a>
- <a name='L301'></a><a href='#L301'>301</a>
- <a name='L302'></a><a href='#L302'>302</a>
- <a name='L303'></a><a href='#L303'>303</a>
- <a name='L304'></a><a href='#L304'>304</a>
- <a name='L305'></a><a href='#L305'>305</a>
- <a name='L306'></a><a href='#L306'>306</a>
- <a name='L307'></a><a href='#L307'>307</a>
- <a name='L308'></a><a href='#L308'>308</a>
- <a name='L309'></a><a href='#L309'>309</a>
- <a name='L310'></a><a href='#L310'>310</a>
- <a name='L311'></a><a href='#L311'>311</a>
- <a name='L312'></a><a href='#L312'>312</a>
- <a name='L313'></a><a href='#L313'>313</a>
- <a name='L314'></a><a href='#L314'>314</a>
- <a name='L315'></a><a href='#L315'>315</a>
- <a name='L316'></a><a href='#L316'>316</a>
- <a name='L317'></a><a href='#L317'>317</a>
- <a name='L318'></a><a href='#L318'>318</a>
- <a name='L319'></a><a href='#L319'>319</a>
- <a name='L320'></a><a href='#L320'>320</a>
- <a name='L321'></a><a href='#L321'>321</a>
- <a name='L322'></a><a href='#L322'>322</a>
- <a name='L323'></a><a href='#L323'>323</a>
- <a name='L324'></a><a href='#L324'>324</a>
- <a name='L325'></a><a href='#L325'>325</a>
- <a name='L326'></a><a href='#L326'>326</a>
- <a name='L327'></a><a href='#L327'>327</a>
- <a name='L328'></a><a href='#L328'>328</a>
- <a name='L329'></a><a href='#L329'>329</a>
- <a name='L330'></a><a href='#L330'>330</a>
- <a name='L331'></a><a href='#L331'>331</a>
- <a name='L332'></a><a href='#L332'>332</a>
- <a name='L333'></a><a href='#L333'>333</a>
- <a name='L334'></a><a href='#L334'>334</a>
- <a name='L335'></a><a href='#L335'>335</a>
- <a name='L336'></a><a href='#L336'>336</a>
- <a name='L337'></a><a href='#L337'>337</a>
- <a name='L338'></a><a href='#L338'>338</a>
- <a name='L339'></a><a href='#L339'>339</a>
- <a name='L340'></a><a href='#L340'>340</a>
- <a name='L341'></a><a href='#L341'>341</a>
- <a name='L342'></a><a href='#L342'>342</a>
- <a name='L343'></a><a href='#L343'>343</a>
- <a name='L344'></a><a href='#L344'>344</a>
- <a name='L345'></a><a href='#L345'>345</a>
- <a name='L346'></a><a href='#L346'>346</a>
- <a name='L347'></a><a href='#L347'>347</a>
- <a name='L348'></a><a href='#L348'>348</a>
- <a name='L349'></a><a href='#L349'>349</a>
- <a name='L350'></a><a href='#L350'>350</a>
- <a name='L351'></a><a href='#L351'>351</a>
- <a name='L352'></a><a href='#L352'>352</a>
- <a name='L353'></a><a href='#L353'>353</a>
- <a name='L354'></a><a href='#L354'>354</a>
- <a name='L355'></a><a href='#L355'>355</a>
- <a name='L356'></a><a href='#L356'>356</a>
- <a name='L357'></a><a href='#L357'>357</a>
- <a name='L358'></a><a href='#L358'>358</a>
- <a name='L359'></a><a href='#L359'>359</a>
- <a name='L360'></a><a href='#L360'>360</a>
- <a name='L361'></a><a href='#L361'>361</a>
- <a name='L362'></a><a href='#L362'>362</a>
- <a name='L363'></a><a href='#L363'>363</a>
- <a name='L364'></a><a href='#L364'>364</a>
- <a name='L365'></a><a href='#L365'>365</a>
- <a name='L366'></a><a href='#L366'>366</a>
- <a name='L367'></a><a href='#L367'>367</a>
- <a name='L368'></a><a href='#L368'>368</a>
- <a name='L369'></a><a href='#L369'>369</a>
- <a name='L370'></a><a href='#L370'>370</a>
- <a name='L371'></a><a href='#L371'>371</a>
- <a name='L372'></a><a href='#L372'>372</a>
- <a name='L373'></a><a href='#L373'>373</a>
- <a name='L374'></a><a href='#L374'>374</a>
- <a name='L375'></a><a href='#L375'>375</a>
- <a name='L376'></a><a href='#L376'>376</a>
- <a name='L377'></a><a href='#L377'>377</a>
- <a name='L378'></a><a href='#L378'>378</a>
- <a name='L379'></a><a href='#L379'>379</a>
- <a name='L380'></a><a href='#L380'>380</a>
- <a name='L381'></a><a href='#L381'>381</a>
- <a name='L382'></a><a href='#L382'>382</a>
- <a name='L383'></a><a href='#L383'>383</a>
- <a name='L384'></a><a href='#L384'>384</a>
- <a name='L385'></a><a href='#L385'>385</a>
- <a name='L386'></a><a href='#L386'>386</a>
- <a name='L387'></a><a href='#L387'>387</a>
- <a name='L388'></a><a href='#L388'>388</a>
- <a name='L389'></a><a href='#L389'>389</a>
- <a name='L390'></a><a href='#L390'>390</a>
- <a name='L391'></a><a href='#L391'>391</a>
- <a name='L392'></a><a href='#L392'>392</a>
- <a name='L393'></a><a href='#L393'>393</a>
- <a name='L394'></a><a href='#L394'>394</a>
- <a name='L395'></a><a href='#L395'>395</a>
- <a name='L396'></a><a href='#L396'>396</a>
- <a name='L397'></a><a href='#L397'>397</a>
- <a name='L398'></a><a href='#L398'>398</a>
- <a name='L399'></a><a href='#L399'>399</a>
- <a name='L400'></a><a href='#L400'>400</a>
- <a name='L401'></a><a href='#L401'>401</a>
- <a name='L402'></a><a href='#L402'>402</a>
- <a name='L403'></a><a href='#L403'>403</a>
- <a name='L404'></a><a href='#L404'>404</a>
- <a name='L405'></a><a href='#L405'>405</a>
- <a name='L406'></a><a href='#L406'>406</a>
- <a name='L407'></a><a href='#L407'>407</a>
- <a name='L408'></a><a href='#L408'>408</a>
- <a name='L409'></a><a href='#L409'>409</a>
- <a name='L410'></a><a href='#L410'>410</a>
- <a name='L411'></a><a href='#L411'>411</a>
- <a name='L412'></a><a href='#L412'>412</a>
- <a name='L413'></a><a href='#L413'>413</a>
- <a name='L414'></a><a href='#L414'>414</a>
- <a name='L415'></a><a href='#L415'>415</a>
- <a name='L416'></a><a href='#L416'>416</a>
- <a name='L417'></a><a href='#L417'>417</a>
- <a name='L418'></a><a href='#L418'>418</a>
- <a name='L419'></a><a href='#L419'>419</a>
- <a name='L420'></a><a href='#L420'>420</a>
- <a name='L421'></a><a href='#L421'>421</a>
- <a name='L422'></a><a href='#L422'>422</a>
- <a name='L423'></a><a href='#L423'>423</a>
- <a name='L424'></a><a href='#L424'>424</a>
- <a name='L425'></a><a href='#L425'>425</a>
- <a name='L426'></a><a href='#L426'>426</a>
- <a name='L427'></a><a href='#L427'>427</a>
- <a name='L428'></a><a href='#L428'>428</a>
- <a name='L429'></a><a href='#L429'>429</a>
- <a name='L430'></a><a href='#L430'>430</a>
- <a name='L431'></a><a href='#L431'>431</a>
- <a name='L432'></a><a href='#L432'>432</a>
- <a name='L433'></a><a href='#L433'>433</a>
- <a name='L434'></a><a href='#L434'>434</a>
- <a name='L435'></a><a href='#L435'>435</a>
- <a name='L436'></a><a href='#L436'>436</a>
- <a name='L437'></a><a href='#L437'>437</a>
- <a name='L438'></a><a href='#L438'>438</a>
- <a name='L439'></a><a href='#L439'>439</a>
- <a name='L440'></a><a href='#L440'>440</a>
- <a name='L441'></a><a href='#L441'>441</a>
- <a name='L442'></a><a href='#L442'>442</a>
- <a name='L443'></a><a href='#L443'>443</a>
- <a name='L444'></a><a href='#L444'>444</a>
- <a name='L445'></a><a href='#L445'>445</a>
- <a name='L446'></a><a href='#L446'>446</a>
- <a name='L447'></a><a href='#L447'>447</a>
- <a name='L448'></a><a href='#L448'>448</a>
- <a name='L449'></a><a href='#L449'>449</a>
- <a name='L450'></a><a href='#L450'>450</a>
- <a name='L451'></a><a href='#L451'>451</a>
- <a name='L452'></a><a href='#L452'>452</a>
- <a name='L453'></a><a href='#L453'>453</a>
- <a name='L454'></a><a href='#L454'>454</a>
- <a name='L455'></a><a href='#L455'>455</a>
- <a name='L456'></a><a href='#L456'>456</a>
- <a name='L457'></a><a href='#L457'>457</a>
- <a name='L458'></a><a href='#L458'>458</a>
- <a name='L459'></a><a href='#L459'>459</a>
- <a name='L460'></a><a href='#L460'>460</a>
- <a name='L461'></a><a href='#L461'>461</a>
- <a name='L462'></a><a href='#L462'>462</a>
- <a name='L463'></a><a href='#L463'>463</a>
- <a name='L464'></a><a href='#L464'>464</a>
- <a name='L465'></a><a href='#L465'>465</a>
- <a name='L466'></a><a href='#L466'>466</a>
- <a name='L467'></a><a href='#L467'>467</a>
- <a name='L468'></a><a href='#L468'>468</a>
- <a name='L469'></a><a href='#L469'>469</a>
- <a name='L470'></a><a href='#L470'>470</a>
- <a name='L471'></a><a href='#L471'>471</a>
- <a name='L472'></a><a href='#L472'>472</a>
- <a name='L473'></a><a href='#L473'>473</a>
- <a name='L474'></a><a href='#L474'>474</a>
- <a name='L475'></a><a href='#L475'>475</a>
- <a name='L476'></a><a href='#L476'>476</a>
- <a name='L477'></a><a href='#L477'>477</a>
- <a name='L478'></a><a href='#L478'>478</a>
- <a name='L479'></a><a href='#L479'>479</a>
- <a name='L480'></a><a href='#L480'>480</a>
- <a name='L481'></a><a href='#L481'>481</a>
- <a name='L482'></a><a href='#L482'>482</a>
- <a name='L483'></a><a href='#L483'>483</a>
- <a name='L484'></a><a href='#L484'>484</a>
- <a name='L485'></a><a href='#L485'>485</a>
- <a name='L486'></a><a href='#L486'>486</a>
- <a name='L487'></a><a href='#L487'>487</a>
- <a name='L488'></a><a href='#L488'>488</a>
- <a name='L489'></a><a href='#L489'>489</a>
- <a name='L490'></a><a href='#L490'>490</a>
- <a name='L491'></a><a href='#L491'>491</a>
- <a name='L492'></a><a href='#L492'>492</a>
- <a name='L493'></a><a href='#L493'>493</a>
- <a name='L494'></a><a href='#L494'>494</a>
- <a name='L495'></a><a href='#L495'>495</a>
- <a name='L496'></a><a href='#L496'>496</a>
- <a name='L497'></a><a href='#L497'>497</a>
- <a name='L498'></a><a href='#L498'>498</a>
- <a name='L499'></a><a href='#L499'>499</a>
- <a name='L500'></a><a href='#L500'>500</a>
- <a name='L501'></a><a href='#L501'>501</a>
- <a name='L502'></a><a href='#L502'>502</a>
- <a name='L503'></a><a href='#L503'>503</a>
- <a name='L504'></a><a href='#L504'>504</a>
- <a name='L505'></a><a href='#L505'>505</a>
- <a name='L506'></a><a href='#L506'>506</a>
- <a name='L507'></a><a href='#L507'>507</a>
- <a name='L508'></a><a href='#L508'>508</a>
- <a name='L509'></a><a href='#L509'>509</a>
- <a name='L510'></a><a href='#L510'>510</a>
- <a name='L511'></a><a href='#L511'>511</a>
- <a name='L512'></a><a href='#L512'>512</a>
- <a name='L513'></a><a href='#L513'>513</a>
- <a name='L514'></a><a href='#L514'>514</a>
- <a name='L515'></a><a href='#L515'>515</a>
- <a name='L516'></a><a href='#L516'>516</a>
- <a name='L517'></a><a href='#L517'>517</a>
- <a name='L518'></a><a href='#L518'>518</a>
- <a name='L519'></a><a href='#L519'>519</a>
- <a name='L520'></a><a href='#L520'>520</a>
- <a name='L521'></a><a href='#L521'>521</a>
- <a name='L522'></a><a href='#L522'>522</a>
- <a name='L523'></a><a href='#L523'>523</a>
- <a name='L524'></a><a href='#L524'>524</a>
- <a name='L525'></a><a href='#L525'>525</a>
- <a name='L526'></a><a href='#L526'>526</a>
- <a name='L527'></a><a href='#L527'>527</a>
- <a name='L528'></a><a href='#L528'>528</a>
- <a name='L529'></a><a href='#L529'>529</a>
- <a name='L530'></a><a href='#L530'>530</a>
- <a name='L531'></a><a href='#L531'>531</a>
- <a name='L532'></a><a href='#L532'>532</a>
- <a name='L533'></a><a href='#L533'>533</a>
- <a name='L534'></a><a href='#L534'>534</a>
- <a name='L535'></a><a href='#L535'>535</a>
- <a name='L536'></a><a href='#L536'>536</a>
- <a name='L537'></a><a href='#L537'>537</a>
- <a name='L538'></a><a href='#L538'>538</a>
- <a name='L539'></a><a href='#L539'>539</a>
- <a name='L540'></a><a href='#L540'>540</a>
- <a name='L541'></a><a href='#L541'>541</a>
- <a name='L542'></a><a href='#L542'>542</a>
- <a name='L543'></a><a href='#L543'>543</a>
- <a name='L544'></a><a href='#L544'>544</a>
- <a name='L545'></a><a href='#L545'>545</a>
- <a name='L546'></a><a href='#L546'>546</a>
- <a name='L547'></a><a href='#L547'>547</a>
- <a name='L548'></a><a href='#L548'>548</a>
- <a name='L549'></a><a href='#L549'>549</a>
- <a name='L550'></a><a href='#L550'>550</a>
- <a name='L551'></a><a href='#L551'>551</a>
- <a name='L552'></a><a href='#L552'>552</a>
- <a name='L553'></a><a href='#L553'>553</a>
- <a name='L554'></a><a href='#L554'>554</a>
- <a name='L555'></a><a href='#L555'>555</a>
- <a name='L556'></a><a href='#L556'>556</a>
- <a name='L557'></a><a href='#L557'>557</a>
- <a name='L558'></a><a href='#L558'>558</a>
- <a name='L559'></a><a href='#L559'>559</a>
- <a name='L560'></a><a href='#L560'>560</a>
- <a name='L561'></a><a href='#L561'>561</a>
- <a name='L562'></a><a href='#L562'>562</a>
- <a name='L563'></a><a href='#L563'>563</a>
- <a name='L564'></a><a href='#L564'>564</a>
- <a name='L565'></a><a href='#L565'>565</a>
- <a name='L566'></a><a href='#L566'>566</a>
- <a name='L567'></a><a href='#L567'>567</a>
- <a name='L568'></a><a href='#L568'>568</a>
- <a name='L569'></a><a href='#L569'>569</a>
- <a name='L570'></a><a href='#L570'>570</a>
- <a name='L571'></a><a href='#L571'>571</a>
- <a name='L572'></a><a href='#L572'>572</a>
- <a name='L573'></a><a href='#L573'>573</a>
- <a name='L574'></a><a href='#L574'>574</a>
- <a name='L575'></a><a href='#L575'>575</a>
- <a name='L576'></a><a href='#L576'>576</a>
- <a name='L577'></a><a href='#L577'>577</a>
- <a name='L578'></a><a href='#L578'>578</a>
- <a name='L579'></a><a href='#L579'>579</a>
- <a name='L580'></a><a href='#L580'>580</a>
- <a name='L581'></a><a href='#L581'>581</a>
- <a name='L582'></a><a href='#L582'>582</a>
- <a name='L583'></a><a href='#L583'>583</a>
- <a name='L584'></a><a href='#L584'>584</a>
- <a name='L585'></a><a href='#L585'>585</a>
- <a name='L586'></a><a href='#L586'>586</a>
- <a name='L587'></a><a href='#L587'>587</a>
- <a name='L588'></a><a href='#L588'>588</a>
- <a name='L589'></a><a href='#L589'>589</a>
- <a name='L590'></a><a href='#L590'>590</a>
- <a name='L591'></a><a href='#L591'>591</a>
- <a name='L592'></a><a href='#L592'>592</a>
- <a name='L593'></a><a href='#L593'>593</a>
- <a name='L594'></a><a href='#L594'>594</a>
- <a name='L595'></a><a href='#L595'>595</a>
- <a name='L596'></a><a href='#L596'>596</a>
- <a name='L597'></a><a href='#L597'>597</a>
- <a name='L598'></a><a href='#L598'>598</a>
- <a name='L599'></a><a href='#L599'>599</a>
- <a name='L600'></a><a href='#L600'>600</a>
- <a name='L601'></a><a href='#L601'>601</a>
- <a name='L602'></a><a href='#L602'>602</a>
- <a name='L603'></a><a href='#L603'>603</a>
- <a name='L604'></a><a href='#L604'>604</a>
- <a name='L605'></a><a href='#L605'>605</a>
- <a name='L606'></a><a href='#L606'>606</a>
- <a name='L607'></a><a href='#L607'>607</a>
- <a name='L608'></a><a href='#L608'>608</a>
- <a name='L609'></a><a href='#L609'>609</a>
- <a name='L610'></a><a href='#L610'>610</a>
- <a name='L611'></a><a href='#L611'>611</a>
- <a name='L612'></a><a href='#L612'>612</a>
- <a name='L613'></a><a href='#L613'>613</a>
- <a name='L614'></a><a href='#L614'>614</a>
- <a name='L615'></a><a href='#L615'>615</a>
- <a name='L616'></a><a href='#L616'>616</a>
- <a name='L617'></a><a href='#L617'>617</a>
- <a name='L618'></a><a href='#L618'>618</a>
- <a name='L619'></a><a href='#L619'>619</a>
- <a name='L620'></a><a href='#L620'>620</a>
- <a name='L621'></a><a href='#L621'>621</a>
- <a name='L622'></a><a href='#L622'>622</a>
- <a name='L623'></a><a href='#L623'>623</a>
- <a name='L624'></a><a href='#L624'>624</a>
- <a name='L625'></a><a href='#L625'>625</a>
- <a name='L626'></a><a href='#L626'>626</a>
- <a name='L627'></a><a href='#L627'>627</a>
- <a name='L628'></a><a href='#L628'>628</a>
- <a name='L629'></a><a href='#L629'>629</a>
- <a name='L630'></a><a href='#L630'>630</a>
- <a name='L631'></a><a href='#L631'>631</a>
- <a name='L632'></a><a href='#L632'>632</a>
- <a name='L633'></a><a href='#L633'>633</a>
- <a name='L634'></a><a href='#L634'>634</a>
- <a name='L635'></a><a href='#L635'>635</a>
- <a name='L636'></a><a href='#L636'>636</a>
- <a name='L637'></a><a href='#L637'>637</a>
- <a name='L638'></a><a href='#L638'>638</a>
- <a name='L639'></a><a href='#L639'>639</a>
- <a name='L640'></a><a href='#L640'>640</a>
- <a name='L641'></a><a href='#L641'>641</a>
- <a name='L642'></a><a href='#L642'>642</a>
- <a name='L643'></a><a href='#L643'>643</a>
- <a name='L644'></a><a href='#L644'>644</a>
- <a name='L645'></a><a href='#L645'>645</a>
- <a name='L646'></a><a href='#L646'>646</a>
- <a name='L647'></a><a href='#L647'>647</a>
- <a name='L648'></a><a href='#L648'>648</a>
- <a name='L649'></a><a href='#L649'>649</a>
- <a name='L650'></a><a href='#L650'>650</a>
- <a name='L651'></a><a href='#L651'>651</a>
- <a name='L652'></a><a href='#L652'>652</a>
- <a name='L653'></a><a href='#L653'>653</a>
- <a name='L654'></a><a href='#L654'>654</a>
- <a name='L655'></a><a href='#L655'>655</a>
- <a name='L656'></a><a href='#L656'>656</a>
- <a name='L657'></a><a href='#L657'>657</a>
- <a name='L658'></a><a href='#L658'>658</a>
- <a name='L659'></a><a href='#L659'>659</a>
- <a name='L660'></a><a href='#L660'>660</a>
- <a name='L661'></a><a href='#L661'>661</a>
- <a name='L662'></a><a href='#L662'>662</a>
- <a name='L663'></a><a href='#L663'>663</a>
- <a name='L664'></a><a href='#L664'>664</a>
- <a name='L665'></a><a href='#L665'>665</a>
- <a name='L666'></a><a href='#L666'>666</a>
- <a name='L667'></a><a href='#L667'>667</a>
- <a name='L668'></a><a href='#L668'>668</a>
- <a name='L669'></a><a href='#L669'>669</a>
- <a name='L670'></a><a href='#L670'>670</a>
- <a name='L671'></a><a href='#L671'>671</a>
- <a name='L672'></a><a href='#L672'>672</a>
- <a name='L673'></a><a href='#L673'>673</a>
- <a name='L674'></a><a href='#L674'>674</a>
- <a name='L675'></a><a href='#L675'>675</a>
- <a name='L676'></a><a href='#L676'>676</a>
- <a name='L677'></a><a href='#L677'>677</a>
- <a name='L678'></a><a href='#L678'>678</a>
- <a name='L679'></a><a href='#L679'>679</a>
- <a name='L680'></a><a href='#L680'>680</a>
- <a name='L681'></a><a href='#L681'>681</a>
- <a name='L682'></a><a href='#L682'>682</a>
- <a name='L683'></a><a href='#L683'>683</a>
- <a name='L684'></a><a href='#L684'>684</a>
- <a name='L685'></a><a href='#L685'>685</a>
- <a name='L686'></a><a href='#L686'>686</a>
- <a name='L687'></a><a href='#L687'>687</a>
- <a name='L688'></a><a href='#L688'>688</a>
- <a name='L689'></a><a href='#L689'>689</a>
- <a name='L690'></a><a href='#L690'>690</a>
- <a name='L691'></a><a href='#L691'>691</a>
- <a name='L692'></a><a href='#L692'>692</a>
- <a name='L693'></a><a href='#L693'>693</a>
- <a name='L694'></a><a href='#L694'>694</a>
- <a name='L695'></a><a href='#L695'>695</a>
- <a name='L696'></a><a href='#L696'>696</a>
- <a name='L697'></a><a href='#L697'>697</a>
- <a name='L698'></a><a href='#L698'>698</a>
- <a name='L699'></a><a href='#L699'>699</a>
- <a name='L700'></a><a href='#L700'>700</a>
- <a name='L701'></a><a href='#L701'>701</a>
- <a name='L702'></a><a href='#L702'>702</a>
- <a name='L703'></a><a href='#L703'>703</a>
- <a name='L704'></a><a href='#L704'>704</a>
- <a name='L705'></a><a href='#L705'>705</a>
- <a name='L706'></a><a href='#L706'>706</a>
- <a name='L707'></a><a href='#L707'>707</a>
- <a name='L708'></a><a href='#L708'>708</a>
- <a name='L709'></a><a href='#L709'>709</a>
- <a name='L710'></a><a href='#L710'>710</a>
- <a name='L711'></a><a href='#L711'>711</a>
- <a name='L712'></a><a href='#L712'>712</a>
- <a name='L713'></a><a href='#L713'>713</a>
- <a name='L714'></a><a href='#L714'>714</a>
- <a name='L715'></a><a href='#L715'>715</a>
- <a name='L716'></a><a href='#L716'>716</a>
- <a name='L717'></a><a href='#L717'>717</a>
- <a name='L718'></a><a href='#L718'>718</a>
- <a name='L719'></a><a href='#L719'>719</a>
- <a name='L720'></a><a href='#L720'>720</a>
- <a name='L721'></a><a href='#L721'>721</a>
- <a name='L722'></a><a href='#L722'>722</a>
- <a name='L723'></a><a href='#L723'>723</a>
- <a name='L724'></a><a href='#L724'>724</a>
- <a name='L725'></a><a href='#L725'>725</a>
- <a name='L726'></a><a href='#L726'>726</a>
- <a name='L727'></a><a href='#L727'>727</a>
- <a name='L728'></a><a href='#L728'>728</a>
- <a name='L729'></a><a href='#L729'>729</a>
- <a name='L730'></a><a href='#L730'>730</a>
- <a name='L731'></a><a href='#L731'>731</a>
- <a name='L732'></a><a href='#L732'>732</a>
- <a name='L733'></a><a href='#L733'>733</a>
- <a name='L734'></a><a href='#L734'>734</a>
- <a name='L735'></a><a href='#L735'>735</a>
- <a name='L736'></a><a href='#L736'>736</a>
- <a name='L737'></a><a href='#L737'>737</a>
- <a name='L738'></a><a href='#L738'>738</a>
- <a name='L739'></a><a href='#L739'>739</a>
- <a name='L740'></a><a href='#L740'>740</a>
- <a name='L741'></a><a href='#L741'>741</a>
- <a name='L742'></a><a href='#L742'>742</a>
- <a name='L743'></a><a href='#L743'>743</a>
- <a name='L744'></a><a href='#L744'>744</a>
- <a name='L745'></a><a href='#L745'>745</a>
- <a name='L746'></a><a href='#L746'>746</a>
- <a name='L747'></a><a href='#L747'>747</a>
- <a name='L748'></a><a href='#L748'>748</a>
- <a name='L749'></a><a href='#L749'>749</a>
- <a name='L750'></a><a href='#L750'>750</a>
- <a name='L751'></a><a href='#L751'>751</a>
- <a name='L752'></a><a href='#L752'>752</a>
- <a name='L753'></a><a href='#L753'>753</a>
- <a name='L754'></a><a href='#L754'>754</a>
- <a name='L755'></a><a href='#L755'>755</a>
- <a name='L756'></a><a href='#L756'>756</a>
- <a name='L757'></a><a href='#L757'>757</a>
- <a name='L758'></a><a href='#L758'>758</a>
- <a name='L759'></a><a href='#L759'>759</a>
- <a name='L760'></a><a href='#L760'>760</a>
- <a name='L761'></a><a href='#L761'>761</a>
- <a name='L762'></a><a href='#L762'>762</a>
- <a name='L763'></a><a href='#L763'>763</a>
- <a name='L764'></a><a href='#L764'>764</a>
- <a name='L765'></a><a href='#L765'>765</a>
- <a name='L766'></a><a href='#L766'>766</a>
- <a name='L767'></a><a href='#L767'>767</a>
- <a name='L768'></a><a href='#L768'>768</a>
- <a name='L769'></a><a href='#L769'>769</a>
- <a name='L770'></a><a href='#L770'>770</a>
- <a name='L771'></a><a href='#L771'>771</a>
- <a name='L772'></a><a href='#L772'>772</a>
- <a name='L773'></a><a href='#L773'>773</a>
- <a name='L774'></a><a href='#L774'>774</a>
- <a name='L775'></a><a href='#L775'>775</a>
- <a name='L776'></a><a href='#L776'>776</a>
- <a name='L777'></a><a href='#L777'>777</a>
- <a name='L778'></a><a href='#L778'>778</a>
- <a name='L779'></a><a href='#L779'>779</a>
- <a name='L780'></a><a href='#L780'>780</a>
- <a name='L781'></a><a href='#L781'>781</a>
- <a name='L782'></a><a href='#L782'>782</a>
- <a name='L783'></a><a href='#L783'>783</a>
- <a name='L784'></a><a href='#L784'>784</a>
- <a name='L785'></a><a href='#L785'>785</a>
- <a name='L786'></a><a href='#L786'>786</a>
- <a name='L787'></a><a href='#L787'>787</a>
- <a name='L788'></a><a href='#L788'>788</a>
- <a name='L789'></a><a href='#L789'>789</a>
- <a name='L790'></a><a href='#L790'>790</a>
- <a name='L791'></a><a href='#L791'>791</a>
- <a name='L792'></a><a href='#L792'>792</a>
- <a name='L793'></a><a href='#L793'>793</a>
- <a name='L794'></a><a href='#L794'>794</a>
- <a name='L795'></a><a href='#L795'>795</a>
- <a name='L796'></a><a href='#L796'>796</a>
- <a name='L797'></a><a href='#L797'>797</a>
- <a name='L798'></a><a href='#L798'>798</a>
- <a name='L799'></a><a href='#L799'>799</a>
- <a name='L800'></a><a href='#L800'>800</a>
- <a name='L801'></a><a href='#L801'>801</a>
- <a name='L802'></a><a href='#L802'>802</a>
- <a name='L803'></a><a href='#L803'>803</a>
- <a name='L804'></a><a href='#L804'>804</a>
- <a name='L805'></a><a href='#L805'>805</a>
- <a name='L806'></a><a href='#L806'>806</a>
- <a name='L807'></a><a href='#L807'>807</a>
- <a name='L808'></a><a href='#L808'>808</a>
- <a name='L809'></a><a href='#L809'>809</a>
- <a name='L810'></a><a href='#L810'>810</a>
- <a name='L811'></a><a href='#L811'>811</a>
- <a name='L812'></a><a href='#L812'>812</a>
- <a name='L813'></a><a href='#L813'>813</a>
- <a name='L814'></a><a href='#L814'>814</a>
- <a name='L815'></a><a href='#L815'>815</a>
- <a name='L816'></a><a href='#L816'>816</a>
- <a name='L817'></a><a href='#L817'>817</a>
- <a name='L818'></a><a href='#L818'>818</a>
- <a name='L819'></a><a href='#L819'>819</a>
- <a name='L820'></a><a href='#L820'>820</a>
- <a name='L821'></a><a href='#L821'>821</a>
- <a name='L822'></a><a href='#L822'>822</a>
- <a name='L823'></a><a href='#L823'>823</a>
- <a name='L824'></a><a href='#L824'>824</a>
- <a name='L825'></a><a href='#L825'>825</a>
- <a name='L826'></a><a href='#L826'>826</a>
- <a name='L827'></a><a href='#L827'>827</a>
- <a name='L828'></a><a href='#L828'>828</a>
- <a name='L829'></a><a href='#L829'>829</a>
- <a name='L830'></a><a href='#L830'>830</a>
- <a name='L831'></a><a href='#L831'>831</a>
- <a name='L832'></a><a href='#L832'>832</a>
- <a name='L833'></a><a href='#L833'>833</a>
- <a name='L834'></a><a href='#L834'>834</a>
- <a name='L835'></a><a href='#L835'>835</a>
- <a name='L836'></a><a href='#L836'>836</a>
- <a name='L837'></a><a href='#L837'>837</a>
- <a name='L838'></a><a href='#L838'>838</a>
- <a name='L839'></a><a href='#L839'>839</a>
- <a name='L840'></a><a href='#L840'>840</a>
- <a name='L841'></a><a href='#L841'>841</a>
- <a name='L842'></a><a href='#L842'>842</a>
- <a name='L843'></a><a href='#L843'>843</a>
- <a name='L844'></a><a href='#L844'>844</a>
- <a name='L845'></a><a href='#L845'>845</a>
- <a name='L846'></a><a href='#L846'>846</a>
- <a name='L847'></a><a href='#L847'>847</a>
- <a name='L848'></a><a href='#L848'>848</a>
- <a name='L849'></a><a href='#L849'>849</a>
- <a name='L850'></a><a href='#L850'>850</a>
- <a name='L851'></a><a href='#L851'>851</a>
- <a name='L852'></a><a href='#L852'>852</a>
- <a name='L853'></a><a href='#L853'>853</a>
- <a name='L854'></a><a href='#L854'>854</a>
- <a name='L855'></a><a href='#L855'>855</a>
- <a name='L856'></a><a href='#L856'>856</a>
- <a name='L857'></a><a href='#L857'>857</a>
- <a name='L858'></a><a href='#L858'>858</a>
- <a name='L859'></a><a href='#L859'>859</a>
- <a name='L860'></a><a href='#L860'>860</a>
- <a name='L861'></a><a href='#L861'>861</a>
- <a name='L862'></a><a href='#L862'>862</a>
- <a name='L863'></a><a href='#L863'>863</a>
- <a name='L864'></a><a href='#L864'>864</a>
- <a name='L865'></a><a href='#L865'>865</a>
- <a name='L866'></a><a href='#L866'>866</a>
- <a name='L867'></a><a href='#L867'>867</a>
- <a name='L868'></a><a href='#L868'>868</a>
- <a name='L869'></a><a href='#L869'>869</a>
- <a name='L870'></a><a href='#L870'>870</a>
- <a name='L871'></a><a href='#L871'>871</a>
- <a name='L872'></a><a href='#L872'>872</a>
- <a name='L873'></a><a href='#L873'>873</a>
- <a name='L874'></a><a href='#L874'>874</a>
- <a name='L875'></a><a href='#L875'>875</a>
- <a name='L876'></a><a href='#L876'>876</a>
- <a name='L877'></a><a href='#L877'>877</a>
- <a name='L878'></a><a href='#L878'>878</a>
- <a name='L879'></a><a href='#L879'>879</a>
- <a name='L880'></a><a href='#L880'>880</a>
- <a name='L881'></a><a href='#L881'>881</a>
- <a name='L882'></a><a href='#L882'>882</a>
- <a name='L883'></a><a href='#L883'>883</a>
- <a name='L884'></a><a href='#L884'>884</a>
- <a name='L885'></a><a href='#L885'>885</a>
- <a name='L886'></a><a href='#L886'>886</a>
- <a name='L887'></a><a href='#L887'>887</a>
- <a name='L888'></a><a href='#L888'>888</a>
- <a name='L889'></a><a href='#L889'>889</a>
- <a name='L890'></a><a href='#L890'>890</a>
- <a name='L891'></a><a href='#L891'>891</a>
- <a name='L892'></a><a href='#L892'>892</a>
- <a name='L893'></a><a href='#L893'>893</a>
- <a name='L894'></a><a href='#L894'>894</a>
- <a name='L895'></a><a href='#L895'>895</a>
- <a name='L896'></a><a href='#L896'>896</a>
- <a name='L897'></a><a href='#L897'>897</a>
- <a name='L898'></a><a href='#L898'>898</a>
- <a name='L899'></a><a href='#L899'>899</a>
- <a name='L900'></a><a href='#L900'>900</a>
- <a name='L901'></a><a href='#L901'>901</a>
- <a name='L902'></a><a href='#L902'>902</a>
- <a name='L903'></a><a href='#L903'>903</a>
- <a name='L904'></a><a href='#L904'>904</a>
- <a name='L905'></a><a href='#L905'>905</a>
- <a name='L906'></a><a href='#L906'>906</a>
- <a name='L907'></a><a href='#L907'>907</a>
- <a name='L908'></a><a href='#L908'>908</a>
- <a name='L909'></a><a href='#L909'>909</a>
- <a name='L910'></a><a href='#L910'>910</a>
- <a name='L911'></a><a href='#L911'>911</a>
- <a name='L912'></a><a href='#L912'>912</a>
- <a name='L913'></a><a href='#L913'>913</a>
- <a name='L914'></a><a href='#L914'>914</a>
- <a name='L915'></a><a href='#L915'>915</a>
- <a name='L916'></a><a href='#L916'>916</a>
- <a name='L917'></a><a href='#L917'>917</a>
- <a name='L918'></a><a href='#L918'>918</a>
- <a name='L919'></a><a href='#L919'>919</a>
- <a name='L920'></a><a href='#L920'>920</a>
- <a name='L921'></a><a href='#L921'>921</a>
- <a name='L922'></a><a href='#L922'>922</a>
- <a name='L923'></a><a href='#L923'>923</a>
- <a name='L924'></a><a href='#L924'>924</a>
- <a name='L925'></a><a href='#L925'>925</a>
- <a name='L926'></a><a href='#L926'>926</a>
- <a name='L927'></a><a href='#L927'>927</a>
- <a name='L928'></a><a href='#L928'>928</a>
- <a name='L929'></a><a href='#L929'>929</a>
- <a name='L930'></a><a href='#L930'>930</a>
- <a name='L931'></a><a href='#L931'>931</a>
- <a name='L932'></a><a href='#L932'>932</a>
- <a name='L933'></a><a href='#L933'>933</a>
- <a name='L934'></a><a href='#L934'>934</a>
- <a name='L935'></a><a href='#L935'>935</a>
- <a name='L936'></a><a href='#L936'>936</a>
- <a name='L937'></a><a href='#L937'>937</a>
- <a name='L938'></a><a href='#L938'>938</a>
- <a name='L939'></a><a href='#L939'>939</a>
- <a name='L940'></a><a href='#L940'>940</a>
- <a name='L941'></a><a href='#L941'>941</a>
- <a name='L942'></a><a href='#L942'>942</a>
- <a name='L943'></a><a href='#L943'>943</a>
- <a name='L944'></a><a href='#L944'>944</a>
- <a name='L945'></a><a href='#L945'>945</a>
- <a name='L946'></a><a href='#L946'>946</a>
- <a name='L947'></a><a href='#L947'>947</a>
- <a name='L948'></a><a href='#L948'>948</a>
- <a name='L949'></a><a href='#L949'>949</a>
- <a name='L950'></a><a href='#L950'>950</a>
- <a name='L951'></a><a href='#L951'>951</a>
- <a name='L952'></a><a href='#L952'>952</a>
- <a name='L953'></a><a href='#L953'>953</a>
- <a name='L954'></a><a href='#L954'>954</a>
- <a name='L955'></a><a href='#L955'>955</a>
- <a name='L956'></a><a href='#L956'>956</a>
- <a name='L957'></a><a href='#L957'>957</a>
- <a name='L958'></a><a href='#L958'>958</a>
- <a name='L959'></a><a href='#L959'>959</a>
- <a name='L960'></a><a href='#L960'>960</a>
- <a name='L961'></a><a href='#L961'>961</a>
- <a name='L962'></a><a href='#L962'>962</a>
- <a name='L963'></a><a href='#L963'>963</a>
- <a name='L964'></a><a href='#L964'>964</a>
- <a name='L965'></a><a href='#L965'>965</a>
- <a name='L966'></a><a href='#L966'>966</a>
- <a name='L967'></a><a href='#L967'>967</a>
- <a name='L968'></a><a href='#L968'>968</a>
- <a name='L969'></a><a href='#L969'>969</a>
- <a name='L970'></a><a href='#L970'>970</a>
- <a name='L971'></a><a href='#L971'>971</a>
- <a name='L972'></a><a href='#L972'>972</a>
- <a name='L973'></a><a href='#L973'>973</a>
- <a name='L974'></a><a href='#L974'>974</a>
- <a name='L975'></a><a href='#L975'>975</a>
- <a name='L976'></a><a href='#L976'>976</a>
- <a name='L977'></a><a href='#L977'>977</a>
- <a name='L978'></a><a href='#L978'>978</a>
- <a name='L979'></a><a href='#L979'>979</a>
- <a name='L980'></a><a href='#L980'>980</a>
- <a name='L981'></a><a href='#L981'>981</a>
- <a name='L982'></a><a href='#L982'>982</a>
- <a name='L983'></a><a href='#L983'>983</a>
- <a name='L984'></a><a href='#L984'>984</a>
- <a name='L985'></a><a href='#L985'>985</a>
- <a name='L986'></a><a href='#L986'>986</a>
- <a name='L987'></a><a href='#L987'>987</a>
- <a name='L988'></a><a href='#L988'>988</a>
- <a name='L989'></a><a href='#L989'>989</a>
- <a name='L990'></a><a href='#L990'>990</a>
- <a name='L991'></a><a href='#L991'>991</a>
- <a name='L992'></a><a href='#L992'>992</a>
- <a name='L993'></a><a href='#L993'>993</a>
- <a name='L994'></a><a href='#L994'>994</a>
- <a name='L995'></a><a href='#L995'>995</a>
- <a name='L996'></a><a href='#L996'>996</a>
- <a name='L997'></a><a href='#L997'>997</a>
- <a name='L998'></a><a href='#L998'>998</a>
- <a name='L999'></a><a href='#L999'>999</a>
- <a name='L1000'></a><a href='#L1000'>1000</a>
- <a name='L1001'></a><a href='#L1001'>1001</a>
- <a name='L1002'></a><a href='#L1002'>1002</a>
- <a name='L1003'></a><a href='#L1003'>1003</a>
- <a name='L1004'></a><a href='#L1004'>1004</a>
- <a name='L1005'></a><a href='#L1005'>1005</a>
- <a name='L1006'></a><a href='#L1006'>1006</a>
- <a name='L1007'></a><a href='#L1007'>1007</a>
- <a name='L1008'></a><a href='#L1008'>1008</a>
- <a name='L1009'></a><a href='#L1009'>1009</a>
- <a name='L1010'></a><a href='#L1010'>1010</a>
- <a name='L1011'></a><a href='#L1011'>1011</a>
- <a name='L1012'></a><a href='#L1012'>1012</a>
- <a name='L1013'></a><a href='#L1013'>1013</a>
- <a name='L1014'></a><a href='#L1014'>1014</a>
- <a name='L1015'></a><a href='#L1015'>1015</a>
- <a name='L1016'></a><a href='#L1016'>1016</a>
- <a name='L1017'></a><a href='#L1017'>1017</a>
- <a name='L1018'></a><a href='#L1018'>1018</a>
- <a name='L1019'></a><a href='#L1019'>1019</a>
- <a name='L1020'></a><a href='#L1020'>1020</a>
- <a name='L1021'></a><a href='#L1021'>1021</a>
- <a name='L1022'></a><a href='#L1022'>1022</a>
- <a name='L1023'></a><a href='#L1023'>1023</a>
- <a name='L1024'></a><a href='#L1024'>1024</a>
- <a name='L1025'></a><a href='#L1025'>1025</a>
- <a name='L1026'></a><a href='#L1026'>1026</a>
- <a name='L1027'></a><a href='#L1027'>1027</a>
- <a name='L1028'></a><a href='#L1028'>1028</a>
- <a name='L1029'></a><a href='#L1029'>1029</a>
- <a name='L1030'></a><a href='#L1030'>1030</a>
- <a name='L1031'></a><a href='#L1031'>1031</a>
- <a name='L1032'></a><a href='#L1032'>1032</a>
- <a name='L1033'></a><a href='#L1033'>1033</a>
- <a name='L1034'></a><a href='#L1034'>1034</a>
- <a name='L1035'></a><a href='#L1035'>1035</a>
- <a name='L1036'></a><a href='#L1036'>1036</a>
- <a name='L1037'></a><a href='#L1037'>1037</a>
- <a name='L1038'></a><a href='#L1038'>1038</a>
- <a name='L1039'></a><a href='#L1039'>1039</a>
- <a name='L1040'></a><a href='#L1040'>1040</a>
- <a name='L1041'></a><a href='#L1041'>1041</a>
- <a name='L1042'></a><a href='#L1042'>1042</a>
- <a name='L1043'></a><a href='#L1043'>1043</a>
- <a name='L1044'></a><a href='#L1044'>1044</a>
- <a name='L1045'></a><a href='#L1045'>1045</a>
- <a name='L1046'></a><a href='#L1046'>1046</a>
- <a name='L1047'></a><a href='#L1047'>1047</a>
- <a name='L1048'></a><a href='#L1048'>1048</a>
- <a name='L1049'></a><a href='#L1049'>1049</a>
- <a name='L1050'></a><a href='#L1050'>1050</a>
- <a name='L1051'></a><a href='#L1051'>1051</a>
- <a name='L1052'></a><a href='#L1052'>1052</a>
- <a name='L1053'></a><a href='#L1053'>1053</a>
- <a name='L1054'></a><a href='#L1054'>1054</a>
- <a name='L1055'></a><a href='#L1055'>1055</a>
- <a name='L1056'></a><a href='#L1056'>1056</a>
- <a name='L1057'></a><a href='#L1057'>1057</a>
- <a name='L1058'></a><a href='#L1058'>1058</a>
- <a name='L1059'></a><a href='#L1059'>1059</a>
- <a name='L1060'></a><a href='#L1060'>1060</a>
- <a name='L1061'></a><a href='#L1061'>1061</a>
- <a name='L1062'></a><a href='#L1062'>1062</a>
- <a name='L1063'></a><a href='#L1063'>1063</a>
- <a name='L1064'></a><a href='#L1064'>1064</a>
- <a name='L1065'></a><a href='#L1065'>1065</a>
- <a name='L1066'></a><a href='#L1066'>1066</a>
- <a name='L1067'></a><a href='#L1067'>1067</a>
- <a name='L1068'></a><a href='#L1068'>1068</a>
- <a name='L1069'></a><a href='#L1069'>1069</a>
- <a name='L1070'></a><a href='#L1070'>1070</a>
- <a name='L1071'></a><a href='#L1071'>1071</a>
- <a name='L1072'></a><a href='#L1072'>1072</a>
- <a name='L1073'></a><a href='#L1073'>1073</a>
- <a name='L1074'></a><a href='#L1074'>1074</a>
- <a name='L1075'></a><a href='#L1075'>1075</a>
- <a name='L1076'></a><a href='#L1076'>1076</a>
- <a name='L1077'></a><a href='#L1077'>1077</a>
- <a name='L1078'></a><a href='#L1078'>1078</a>
- <a name='L1079'></a><a href='#L1079'>1079</a>
- <a name='L1080'></a><a href='#L1080'>1080</a>
- <a name='L1081'></a><a href='#L1081'>1081</a>
- <a name='L1082'></a><a href='#L1082'>1082</a>
- <a name='L1083'></a><a href='#L1083'>1083</a>
- <a name='L1084'></a><a href='#L1084'>1084</a>
- <a name='L1085'></a><a href='#L1085'>1085</a>
- <a name='L1086'></a><a href='#L1086'>1086</a>
- <a name='L1087'></a><a href='#L1087'>1087</a>
- <a name='L1088'></a><a href='#L1088'>1088</a>
- <a name='L1089'></a><a href='#L1089'>1089</a>
- <a name='L1090'></a><a href='#L1090'>1090</a>
- <a name='L1091'></a><a href='#L1091'>1091</a>
- <a name='L1092'></a><a href='#L1092'>1092</a>
- <a name='L1093'></a><a href='#L1093'>1093</a>
- <a name='L1094'></a><a href='#L1094'>1094</a>
- <a name='L1095'></a><a href='#L1095'>1095</a>
- <a name='L1096'></a><a href='#L1096'>1096</a>
- <a name='L1097'></a><a href='#L1097'>1097</a>
- <a name='L1098'></a><a href='#L1098'>1098</a>
- <a name='L1099'></a><a href='#L1099'>1099</a>
- <a name='L1100'></a><a href='#L1100'>1100</a>
- <a name='L1101'></a><a href='#L1101'>1101</a>
- <a name='L1102'></a><a href='#L1102'>1102</a>
- <a name='L1103'></a><a href='#L1103'>1103</a>
- <a name='L1104'></a><a href='#L1104'>1104</a>
- <a name='L1105'></a><a href='#L1105'>1105</a>
- <a name='L1106'></a><a href='#L1106'>1106</a>
- <a name='L1107'></a><a href='#L1107'>1107</a>
- <a name='L1108'></a><a href='#L1108'>1108</a>
- <a name='L1109'></a><a href='#L1109'>1109</a>
- <a name='L1110'></a><a href='#L1110'>1110</a>
- <a name='L1111'></a><a href='#L1111'>1111</a>
- <a name='L1112'></a><a href='#L1112'>1112</a>
- <a name='L1113'></a><a href='#L1113'>1113</a>
- <a name='L1114'></a><a href='#L1114'>1114</a>
- <a name='L1115'></a><a href='#L1115'>1115</a>
- <a name='L1116'></a><a href='#L1116'>1116</a>
- <a name='L1117'></a><a href='#L1117'>1117</a>
- <a name='L1118'></a><a href='#L1118'>1118</a>
- <a name='L1119'></a><a href='#L1119'>1119</a>
- <a name='L1120'></a><a href='#L1120'>1120</a>
- <a name='L1121'></a><a href='#L1121'>1121</a>
- <a name='L1122'></a><a href='#L1122'>1122</a>
- <a name='L1123'></a><a href='#L1123'>1123</a>
- <a name='L1124'></a><a href='#L1124'>1124</a>
- <a name='L1125'></a><a href='#L1125'>1125</a>
- <a name='L1126'></a><a href='#L1126'>1126</a>
- <a name='L1127'></a><a href='#L1127'>1127</a>
- <a name='L1128'></a><a href='#L1128'>1128</a>
- <a name='L1129'></a><a href='#L1129'>1129</a>
- <a name='L1130'></a><a href='#L1130'>1130</a>
- <a name='L1131'></a><a href='#L1131'>1131</a>
- <a name='L1132'></a><a href='#L1132'>1132</a>
- <a name='L1133'></a><a href='#L1133'>1133</a>
- <a name='L1134'></a><a href='#L1134'>1134</a>
- <a name='L1135'></a><a href='#L1135'>1135</a>
- <a name='L1136'></a><a href='#L1136'>1136</a>
- <a name='L1137'></a><a href='#L1137'>1137</a>
- <a name='L1138'></a><a href='#L1138'>1138</a>
- <a name='L1139'></a><a href='#L1139'>1139</a>
- <a name='L1140'></a><a href='#L1140'>1140</a>
- <a name='L1141'></a><a href='#L1141'>1141</a>
- <a name='L1142'></a><a href='#L1142'>1142</a>
- <a name='L1143'></a><a href='#L1143'>1143</a>
- <a name='L1144'></a><a href='#L1144'>1144</a>
- <a name='L1145'></a><a href='#L1145'>1145</a>
- <a name='L1146'></a><a href='#L1146'>1146</a>
- <a name='L1147'></a><a href='#L1147'>1147</a>
- <a name='L1148'></a><a href='#L1148'>1148</a>
- <a name='L1149'></a><a href='#L1149'>1149</a>
- <a name='L1150'></a><a href='#L1150'>1150</a>
- <a name='L1151'></a><a href='#L1151'>1151</a>
- <a name='L1152'></a><a href='#L1152'>1152</a>
- <a name='L1153'></a><a href='#L1153'>1153</a>
- <a name='L1154'></a><a href='#L1154'>1154</a>
- <a name='L1155'></a><a href='#L1155'>1155</a>
- <a name='L1156'></a><a href='#L1156'>1156</a>
- <a name='L1157'></a><a href='#L1157'>1157</a>
- <a name='L1158'></a><a href='#L1158'>1158</a>
- <a name='L1159'></a><a href='#L1159'>1159</a>
- <a name='L1160'></a><a href='#L1160'>1160</a>
- <a name='L1161'></a><a href='#L1161'>1161</a>
- <a name='L1162'></a><a href='#L1162'>1162</a>
- <a name='L1163'></a><a href='#L1163'>1163</a>
- <a name='L1164'></a><a href='#L1164'>1164</a>
- <a name='L1165'></a><a href='#L1165'>1165</a>
- <a name='L1166'></a><a href='#L1166'>1166</a>
- <a name='L1167'></a><a href='#L1167'>1167</a>
- <a name='L1168'></a><a href='#L1168'>1168</a>
- <a name='L1169'></a><a href='#L1169'>1169</a>
- <a name='L1170'></a><a href='#L1170'>1170</a>
- <a name='L1171'></a><a href='#L1171'>1171</a>
- <a name='L1172'></a><a href='#L1172'>1172</a>
- <a name='L1173'></a><a href='#L1173'>1173</a>
- <a name='L1174'></a><a href='#L1174'>1174</a>
- <a name='L1175'></a><a href='#L1175'>1175</a>
- <a name='L1176'></a><a href='#L1176'>1176</a>
- <a name='L1177'></a><a href='#L1177'>1177</a>
- <a name='L1178'></a><a href='#L1178'>1178</a>
- <a name='L1179'></a><a href='#L1179'>1179</a>
- <a name='L1180'></a><a href='#L1180'>1180</a>
- <a name='L1181'></a><a href='#L1181'>1181</a>
- <a name='L1182'></a><a href='#L1182'>1182</a>
- <a name='L1183'></a><a href='#L1183'>1183</a>
- <a name='L1184'></a><a href='#L1184'>1184</a>
- <a name='L1185'></a><a href='#L1185'>1185</a>
- <a name='L1186'></a><a href='#L1186'>1186</a>
- <a name='L1187'></a><a href='#L1187'>1187</a>
- <a name='L1188'></a><a href='#L1188'>1188</a>
- <a name='L1189'></a><a href='#L1189'>1189</a>
- <a name='L1190'></a><a href='#L1190'>1190</a>
- <a name='L1191'></a><a href='#L1191'>1191</a>
- <a name='L1192'></a><a href='#L1192'>1192</a>
- <a name='L1193'></a><a href='#L1193'>1193</a>
- <a name='L1194'></a><a href='#L1194'>1194</a>
- <a name='L1195'></a><a href='#L1195'>1195</a>
- <a name='L1196'></a><a href='#L1196'>1196</a>
- <a name='L1197'></a><a href='#L1197'>1197</a>
- <a name='L1198'></a><a href='#L1198'>1198</a>
- <a name='L1199'></a><a href='#L1199'>1199</a>
- <a name='L1200'></a><a href='#L1200'>1200</a>
- <a name='L1201'></a><a href='#L1201'>1201</a>
- <a name='L1202'></a><a href='#L1202'>1202</a>
- <a name='L1203'></a><a href='#L1203'>1203</a>
- <a name='L1204'></a><a href='#L1204'>1204</a>
- <a name='L1205'></a><a href='#L1205'>1205</a>
- <a name='L1206'></a><a href='#L1206'>1206</a>
- <a name='L1207'></a><a href='#L1207'>1207</a>
- <a name='L1208'></a><a href='#L1208'>1208</a>
- <a name='L1209'></a><a href='#L1209'>1209</a>
- <a name='L1210'></a><a href='#L1210'>1210</a>
- <a name='L1211'></a><a href='#L1211'>1211</a>
- <a name='L1212'></a><a href='#L1212'>1212</a>
- <a name='L1213'></a><a href='#L1213'>1213</a>
- <a name='L1214'></a><a href='#L1214'>1214</a>
- <a name='L1215'></a><a href='#L1215'>1215</a>
- <a name='L1216'></a><a href='#L1216'>1216</a>
- <a name='L1217'></a><a href='#L1217'>1217</a>
- <a name='L1218'></a><a href='#L1218'>1218</a>
- <a name='L1219'></a><a href='#L1219'>1219</a>
- <a name='L1220'></a><a href='#L1220'>1220</a>
- <a name='L1221'></a><a href='#L1221'>1221</a>
- <a name='L1222'></a><a href='#L1222'>1222</a>
- <a name='L1223'></a><a href='#L1223'>1223</a>
- <a name='L1224'></a><a href='#L1224'>1224</a>
- <a name='L1225'></a><a href='#L1225'>1225</a>
- <a name='L1226'></a><a href='#L1226'>1226</a>
- <a name='L1227'></a><a href='#L1227'>1227</a>
- <a name='L1228'></a><a href='#L1228'>1228</a>
- <a name='L1229'></a><a href='#L1229'>1229</a>
- <a name='L1230'></a><a href='#L1230'>1230</a>
- <a name='L1231'></a><a href='#L1231'>1231</a>
- <a name='L1232'></a><a href='#L1232'>1232</a>
- <a name='L1233'></a><a href='#L1233'>1233</a>
- <a name='L1234'></a><a href='#L1234'>1234</a>
- <a name='L1235'></a><a href='#L1235'>1235</a>
- <a name='L1236'></a><a href='#L1236'>1236</a>
- <a name='L1237'></a><a href='#L1237'>1237</a>
- <a name='L1238'></a><a href='#L1238'>1238</a>
- <a name='L1239'></a><a href='#L1239'>1239</a>
- <a name='L1240'></a><a href='#L1240'>1240</a>
- <a name='L1241'></a><a href='#L1241'>1241</a>
- <a name='L1242'></a><a href='#L1242'>1242</a>
- <a name='L1243'></a><a href='#L1243'>1243</a>
- <a name='L1244'></a><a href='#L1244'>1244</a>
- <a name='L1245'></a><a href='#L1245'>1245</a>
- <a name='L1246'></a><a href='#L1246'>1246</a>
- <a name='L1247'></a><a href='#L1247'>1247</a>
- <a name='L1248'></a><a href='#L1248'>1248</a>
- <a name='L1249'></a><a href='#L1249'>1249</a>
- <a name='L1250'></a><a href='#L1250'>1250</a>
- <a name='L1251'></a><a href='#L1251'>1251</a>
- <a name='L1252'></a><a href='#L1252'>1252</a>
- <a name='L1253'></a><a href='#L1253'>1253</a>
- <a name='L1254'></a><a href='#L1254'>1254</a>
- <a name='L1255'></a><a href='#L1255'>1255</a>
- <a name='L1256'></a><a href='#L1256'>1256</a>
- <a name='L1257'></a><a href='#L1257'>1257</a>
- <a name='L1258'></a><a href='#L1258'>1258</a>
- <a name='L1259'></a><a href='#L1259'>1259</a>
- <a name='L1260'></a><a href='#L1260'>1260</a>
- <a name='L1261'></a><a href='#L1261'>1261</a>
- <a name='L1262'></a><a href='#L1262'>1262</a>
- <a name='L1263'></a><a href='#L1263'>1263</a>
- <a name='L1264'></a><a href='#L1264'>1264</a>
- <a name='L1265'></a><a href='#L1265'>1265</a>
- <a name='L1266'></a><a href='#L1266'>1266</a>
- <a name='L1267'></a><a href='#L1267'>1267</a>
- <a name='L1268'></a><a href='#L1268'>1268</a>
- <a name='L1269'></a><a href='#L1269'>1269</a>
- <a name='L1270'></a><a href='#L1270'>1270</a>
- <a name='L1271'></a><a href='#L1271'>1271</a>
- <a name='L1272'></a><a href='#L1272'>1272</a>
- <a name='L1273'></a><a href='#L1273'>1273</a>
- <a name='L1274'></a><a href='#L1274'>1274</a>
- <a name='L1275'></a><a href='#L1275'>1275</a>
- <a name='L1276'></a><a href='#L1276'>1276</a>
- <a name='L1277'></a><a href='#L1277'>1277</a>
- <a name='L1278'></a><a href='#L1278'>1278</a>
- <a name='L1279'></a><a href='#L1279'>1279</a>
- <a name='L1280'></a><a href='#L1280'>1280</a>
- <a name='L1281'></a><a href='#L1281'>1281</a>
- <a name='L1282'></a><a href='#L1282'>1282</a>
- <a name='L1283'></a><a href='#L1283'>1283</a>
- <a name='L1284'></a><a href='#L1284'>1284</a>
- <a name='L1285'></a><a href='#L1285'>1285</a>
- <a name='L1286'></a><a href='#L1286'>1286</a>
- <a name='L1287'></a><a href='#L1287'>1287</a>
- <a name='L1288'></a><a href='#L1288'>1288</a>
- <a name='L1289'></a><a href='#L1289'>1289</a>
- <a name='L1290'></a><a href='#L1290'>1290</a>
- <a name='L1291'></a><a href='#L1291'>1291</a>
- <a name='L1292'></a><a href='#L1292'>1292</a>
- <a name='L1293'></a><a href='#L1293'>1293</a>
- <a name='L1294'></a><a href='#L1294'>1294</a>
- <a name='L1295'></a><a href='#L1295'>1295</a>
- <a name='L1296'></a><a href='#L1296'>1296</a>
- <a name='L1297'></a><a href='#L1297'>1297</a>
- <a name='L1298'></a><a href='#L1298'>1298</a>
- <a name='L1299'></a><a href='#L1299'>1299</a>
- <a name='L1300'></a><a href='#L1300'>1300</a>
- <a name='L1301'></a><a href='#L1301'>1301</a>
- <a name='L1302'></a><a href='#L1302'>1302</a>
- <a name='L1303'></a><a href='#L1303'>1303</a>
- <a name='L1304'></a><a href='#L1304'>1304</a>
- <a name='L1305'></a><a href='#L1305'>1305</a>
- <a name='L1306'></a><a href='#L1306'>1306</a>
- <a name='L1307'></a><a href='#L1307'>1307</a>
- <a name='L1308'></a><a href='#L1308'>1308</a>
- <a name='L1309'></a><a href='#L1309'>1309</a>
- <a name='L1310'></a><a href='#L1310'>1310</a>
- <a name='L1311'></a><a href='#L1311'>1311</a>
- <a name='L1312'></a><a href='#L1312'>1312</a>
- <a name='L1313'></a><a href='#L1313'>1313</a>
- <a name='L1314'></a><a href='#L1314'>1314</a>
- <a name='L1315'></a><a href='#L1315'>1315</a>
- <a name='L1316'></a><a href='#L1316'>1316</a>
- <a name='L1317'></a><a href='#L1317'>1317</a>
- <a name='L1318'></a><a href='#L1318'>1318</a>
- <a name='L1319'></a><a href='#L1319'>1319</a>
- <a name='L1320'></a><a href='#L1320'>1320</a>
- <a name='L1321'></a><a href='#L1321'>1321</a>
- <a name='L1322'></a><a href='#L1322'>1322</a>
- <a name='L1323'></a><a href='#L1323'>1323</a>
- <a name='L1324'></a><a href='#L1324'>1324</a>
- <a name='L1325'></a><a href='#L1325'>1325</a>
- <a name='L1326'></a><a href='#L1326'>1326</a>
- <a name='L1327'></a><a href='#L1327'>1327</a>
- <a name='L1328'></a><a href='#L1328'>1328</a>
- <a name='L1329'></a><a href='#L1329'>1329</a>
- <a name='L1330'></a><a href='#L1330'>1330</a>
- <a name='L1331'></a><a href='#L1331'>1331</a>
- <a name='L1332'></a><a href='#L1332'>1332</a>
- <a name='L1333'></a><a href='#L1333'>1333</a>
- <a name='L1334'></a><a href='#L1334'>1334</a>
- <a name='L1335'></a><a href='#L1335'>1335</a>
- <a name='L1336'></a><a href='#L1336'>1336</a>
- <a name='L1337'></a><a href='#L1337'>1337</a>
- <a name='L1338'></a><a href='#L1338'>1338</a>
- <a name='L1339'></a><a href='#L1339'>1339</a>
- <a name='L1340'></a><a href='#L1340'>1340</a>
- <a name='L1341'></a><a href='#L1341'>1341</a>
- <a name='L1342'></a><a href='#L1342'>1342</a>
- <a name='L1343'></a><a href='#L1343'>1343</a>
- <a name='L1344'></a><a href='#L1344'>1344</a>
- <a name='L1345'></a><a href='#L1345'>1345</a>
- <a name='L1346'></a><a href='#L1346'>1346</a>
- <a name='L1347'></a><a href='#L1347'>1347</a>
- <a name='L1348'></a><a href='#L1348'>1348</a>
- <a name='L1349'></a><a href='#L1349'>1349</a>
- <a name='L1350'></a><a href='#L1350'>1350</a>
- <a name='L1351'></a><a href='#L1351'>1351</a>
- <a name='L1352'></a><a href='#L1352'>1352</a>
- <a name='L1353'></a><a href='#L1353'>1353</a>
- <a name='L1354'></a><a href='#L1354'>1354</a>
- <a name='L1355'></a><a href='#L1355'>1355</a>
- <a name='L1356'></a><a href='#L1356'>1356</a>
- <a name='L1357'></a><a href='#L1357'>1357</a>
- <a name='L1358'></a><a href='#L1358'>1358</a>
- <a name='L1359'></a><a href='#L1359'>1359</a>
- <a name='L1360'></a><a href='#L1360'>1360</a>
- <a name='L1361'></a><a href='#L1361'>1361</a>
- <a name='L1362'></a><a href='#L1362'>1362</a>
- <a name='L1363'></a><a href='#L1363'>1363</a>
- <a name='L1364'></a><a href='#L1364'>1364</a>
- <a name='L1365'></a><a href='#L1365'>1365</a>
- <a name='L1366'></a><a href='#L1366'>1366</a>
- <a name='L1367'></a><a href='#L1367'>1367</a>
- <a name='L1368'></a><a href='#L1368'>1368</a>
- <a name='L1369'></a><a href='#L1369'>1369</a>
- <a name='L1370'></a><a href='#L1370'>1370</a>
- <a name='L1371'></a><a href='#L1371'>1371</a>
- <a name='L1372'></a><a href='#L1372'>1372</a>
- <a name='L1373'></a><a href='#L1373'>1373</a>
- <a name='L1374'></a><a href='#L1374'>1374</a>
- <a name='L1375'></a><a href='#L1375'>1375</a>
- <a name='L1376'></a><a href='#L1376'>1376</a>
- <a name='L1377'></a><a href='#L1377'>1377</a>
- <a name='L1378'></a><a href='#L1378'>1378</a>
- <a name='L1379'></a><a href='#L1379'>1379</a>
- <a name='L1380'></a><a href='#L1380'>1380</a>
- <a name='L1381'></a><a href='#L1381'>1381</a>
- <a name='L1382'></a><a href='#L1382'>1382</a>
- <a name='L1383'></a><a href='#L1383'>1383</a>
- <a name='L1384'></a><a href='#L1384'>1384</a>
- <a name='L1385'></a><a href='#L1385'>1385</a>
- <a name='L1386'></a><a href='#L1386'>1386</a>
- <a name='L1387'></a><a href='#L1387'>1387</a>
- <a name='L1388'></a><a href='#L1388'>1388</a>
- <a name='L1389'></a><a href='#L1389'>1389</a>
- <a name='L1390'></a><a href='#L1390'>1390</a>
- <a name='L1391'></a><a href='#L1391'>1391</a>
- <a name='L1392'></a><a href='#L1392'>1392</a>
- <a name='L1393'></a><a href='#L1393'>1393</a>
- <a name='L1394'></a><a href='#L1394'>1394</a>
- <a name='L1395'></a><a href='#L1395'>1395</a>
- <a name='L1396'></a><a href='#L1396'>1396</a>
- <a name='L1397'></a><a href='#L1397'>1397</a>
- <a name='L1398'></a><a href='#L1398'>1398</a>
- <a name='L1399'></a><a href='#L1399'>1399</a>
- <a name='L1400'></a><a href='#L1400'>1400</a>
- <a name='L1401'></a><a href='#L1401'>1401</a>
- <a name='L1402'></a><a href='#L1402'>1402</a>
- <a name='L1403'></a><a href='#L1403'>1403</a>
- <a name='L1404'></a><a href='#L1404'>1404</a>
- <a name='L1405'></a><a href='#L1405'>1405</a>
- <a name='L1406'></a><a href='#L1406'>1406</a>
- <a name='L1407'></a><a href='#L1407'>1407</a>
- <a name='L1408'></a><a href='#L1408'>1408</a>
- <a name='L1409'></a><a href='#L1409'>1409</a>
- <a name='L1410'></a><a href='#L1410'>1410</a>
- <a name='L1411'></a><a href='#L1411'>1411</a>
- <a name='L1412'></a><a href='#L1412'>1412</a>
- <a name='L1413'></a><a href='#L1413'>1413</a>
- <a name='L1414'></a><a href='#L1414'>1414</a>
- <a name='L1415'></a><a href='#L1415'>1415</a>
- <a name='L1416'></a><a href='#L1416'>1416</a>
- <a name='L1417'></a><a href='#L1417'>1417</a>
- <a name='L1418'></a><a href='#L1418'>1418</a>
- <a name='L1419'></a><a href='#L1419'>1419</a>
- <a name='L1420'></a><a href='#L1420'>1420</a>
- <a name='L1421'></a><a href='#L1421'>1421</a>
- <a name='L1422'></a><a href='#L1422'>1422</a>
- <a name='L1423'></a><a href='#L1423'>1423</a>
- <a name='L1424'></a><a href='#L1424'>1424</a>
- <a name='L1425'></a><a href='#L1425'>1425</a>
- <a name='L1426'></a><a href='#L1426'>1426</a>
- <a name='L1427'></a><a href='#L1427'>1427</a>
- <a name='L1428'></a><a href='#L1428'>1428</a>
- <a name='L1429'></a><a href='#L1429'>1429</a>
- <a name='L1430'></a><a href='#L1430'>1430</a>
- <a name='L1431'></a><a href='#L1431'>1431</a>
- <a name='L1432'></a><a href='#L1432'>1432</a>
- <a name='L1433'></a><a href='#L1433'>1433</a>
- <a name='L1434'></a><a href='#L1434'>1434</a>
- <a name='L1435'></a><a href='#L1435'>1435</a>
- <a name='L1436'></a><a href='#L1436'>1436</a>
- <a name='L1437'></a><a href='#L1437'>1437</a>
- <a name='L1438'></a><a href='#L1438'>1438</a>
- <a name='L1439'></a><a href='#L1439'>1439</a>
- <a name='L1440'></a><a href='#L1440'>1440</a>
- <a name='L1441'></a><a href='#L1441'>1441</a>
- <a name='L1442'></a><a href='#L1442'>1442</a>
- <a name='L1443'></a><a href='#L1443'>1443</a>
- <a name='L1444'></a><a href='#L1444'>1444</a>
- <a name='L1445'></a><a href='#L1445'>1445</a>
- <a name='L1446'></a><a href='#L1446'>1446</a>
- <a name='L1447'></a><a href='#L1447'>1447</a>
- <a name='L1448'></a><a href='#L1448'>1448</a>
- <a name='L1449'></a><a href='#L1449'>1449</a>
- <a name='L1450'></a><a href='#L1450'>1450</a>
- <a name='L1451'></a><a href='#L1451'>1451</a>
- <a name='L1452'></a><a href='#L1452'>1452</a>
- <a name='L1453'></a><a href='#L1453'>1453</a>
- <a name='L1454'></a><a href='#L1454'>1454</a>
- <a name='L1455'></a><a href='#L1455'>1455</a>
- <a name='L1456'></a><a href='#L1456'>1456</a>
- <a name='L1457'></a><a href='#L1457'>1457</a>
- <a name='L1458'></a><a href='#L1458'>1458</a>
- <a name='L1459'></a><a href='#L1459'>1459</a>
- <a name='L1460'></a><a href='#L1460'>1460</a>
- <a name='L1461'></a><a href='#L1461'>1461</a>
- <a name='L1462'></a><a href='#L1462'>1462</a>
- <a name='L1463'></a><a href='#L1463'>1463</a>
- <a name='L1464'></a><a href='#L1464'>1464</a>
- <a name='L1465'></a><a href='#L1465'>1465</a>
- <a name='L1466'></a><a href='#L1466'>1466</a>
- <a name='L1467'></a><a href='#L1467'>1467</a>
- <a name='L1468'></a><a href='#L1468'>1468</a>
- <a name='L1469'></a><a href='#L1469'>1469</a>
- <a name='L1470'></a><a href='#L1470'>1470</a>
- <a name='L1471'></a><a href='#L1471'>1471</a>
- <a name='L1472'></a><a href='#L1472'>1472</a>
- <a name='L1473'></a><a href='#L1473'>1473</a>
- <a name='L1474'></a><a href='#L1474'>1474</a>
- <a name='L1475'></a><a href='#L1475'>1475</a>
- <a name='L1476'></a><a href='#L1476'>1476</a>
- <a name='L1477'></a><a href='#L1477'>1477</a>
- <a name='L1478'></a><a href='#L1478'>1478</a>
- <a name='L1479'></a><a href='#L1479'>1479</a>
- <a name='L1480'></a><a href='#L1480'>1480</a>
- <a name='L1481'></a><a href='#L1481'>1481</a>
- <a name='L1482'></a><a href='#L1482'>1482</a>
- <a name='L1483'></a><a href='#L1483'>1483</a>
- <a name='L1484'></a><a href='#L1484'>1484</a>
- <a name='L1485'></a><a href='#L1485'>1485</a>
- <a name='L1486'></a><a href='#L1486'>1486</a>
- <a name='L1487'></a><a href='#L1487'>1487</a>
- <a name='L1488'></a><a href='#L1488'>1488</a>
- <a name='L1489'></a><a href='#L1489'>1489</a>
- <a name='L1490'></a><a href='#L1490'>1490</a>
- <a name='L1491'></a><a href='#L1491'>1491</a>
- <a name='L1492'></a><a href='#L1492'>1492</a>
- <a name='L1493'></a><a href='#L1493'>1493</a>
- <a name='L1494'></a><a href='#L1494'>1494</a>
- <a name='L1495'></a><a href='#L1495'>1495</a>
- <a name='L1496'></a><a href='#L1496'>1496</a>
- <a name='L1497'></a><a href='#L1497'>1497</a>
- <a name='L1498'></a><a href='#L1498'>1498</a>
- <a name='L1499'></a><a href='#L1499'>1499</a>
- <a name='L1500'></a><a href='#L1500'>1500</a>
- <a name='L1501'></a><a href='#L1501'>1501</a>
- <a name='L1502'></a><a href='#L1502'>1502</a>
- <a name='L1503'></a><a href='#L1503'>1503</a>
- <a name='L1504'></a><a href='#L1504'>1504</a>
- <a name='L1505'></a><a href='#L1505'>1505</a>
- <a name='L1506'></a><a href='#L1506'>1506</a>
- <a name='L1507'></a><a href='#L1507'>1507</a>
- <a name='L1508'></a><a href='#L1508'>1508</a>
- <a name='L1509'></a><a href='#L1509'>1509</a>
- <a name='L1510'></a><a href='#L1510'>1510</a>
- <a name='L1511'></a><a href='#L1511'>1511</a>
- <a name='L1512'></a><a href='#L1512'>1512</a>
- <a name='L1513'></a><a href='#L1513'>1513</a>
- <a name='L1514'></a><a href='#L1514'>1514</a>
- <a name='L1515'></a><a href='#L1515'>1515</a>
- <a name='L1516'></a><a href='#L1516'>1516</a>
- <a name='L1517'></a><a href='#L1517'>1517</a>
- <a name='L1518'></a><a href='#L1518'>1518</a>
- <a name='L1519'></a><a href='#L1519'>1519</a>
- <a name='L1520'></a><a href='#L1520'>1520</a>
- <a name='L1521'></a><a href='#L1521'>1521</a>
- <a name='L1522'></a><a href='#L1522'>1522</a>
- <a name='L1523'></a><a href='#L1523'>1523</a>
- <a name='L1524'></a><a href='#L1524'>1524</a>
- <a name='L1525'></a><a href='#L1525'>1525</a>
- <a name='L1526'></a><a href='#L1526'>1526</a>
- <a name='L1527'></a><a href='#L1527'>1527</a>
- <a name='L1528'></a><a href='#L1528'>1528</a>
- <a name='L1529'></a><a href='#L1529'>1529</a>
- <a name='L1530'></a><a href='#L1530'>1530</a>
- <a name='L1531'></a><a href='#L1531'>1531</a>
- <a name='L1532'></a><a href='#L1532'>1532</a>
- <a name='L1533'></a><a href='#L1533'>1533</a>
- <a name='L1534'></a><a href='#L1534'>1534</a>
- <a name='L1535'></a><a href='#L1535'>1535</a>
- <a name='L1536'></a><a href='#L1536'>1536</a>
- <a name='L1537'></a><a href='#L1537'>1537</a>
- <a name='L1538'></a><a href='#L1538'>1538</a>
- <a name='L1539'></a><a href='#L1539'>1539</a>
- <a name='L1540'></a><a href='#L1540'>1540</a>
- <a name='L1541'></a><a href='#L1541'>1541</a>
- <a name='L1542'></a><a href='#L1542'>1542</a>
- <a name='L1543'></a><a href='#L1543'>1543</a>
- <a name='L1544'></a><a href='#L1544'>1544</a>
- <a name='L1545'></a><a href='#L1545'>1545</a>
- <a name='L1546'></a><a href='#L1546'>1546</a>
- <a name='L1547'></a><a href='#L1547'>1547</a>
- <a name='L1548'></a><a href='#L1548'>1548</a>
- <a name='L1549'></a><a href='#L1549'>1549</a>
- <a name='L1550'></a><a href='#L1550'>1550</a>
- <a name='L1551'></a><a href='#L1551'>1551</a>
- <a name='L1552'></a><a href='#L1552'>1552</a>
- <a name='L1553'></a><a href='#L1553'>1553</a>
- <a name='L1554'></a><a href='#L1554'>1554</a>
- <a name='L1555'></a><a href='#L1555'>1555</a>
- <a name='L1556'></a><a href='#L1556'>1556</a>
- <a name='L1557'></a><a href='#L1557'>1557</a>
- <a name='L1558'></a><a href='#L1558'>1558</a>
- <a name='L1559'></a><a href='#L1559'>1559</a>
- <a name='L1560'></a><a href='#L1560'>1560</a>
- <a name='L1561'></a><a href='#L1561'>1561</a>
- <a name='L1562'></a><a href='#L1562'>1562</a>
- <a name='L1563'></a><a href='#L1563'>1563</a>
- <a name='L1564'></a><a href='#L1564'>1564</a>
- <a name='L1565'></a><a href='#L1565'>1565</a>
- <a name='L1566'></a><a href='#L1566'>1566</a>
- <a name='L1567'></a><a href='#L1567'>1567</a>
- <a name='L1568'></a><a href='#L1568'>1568</a>
- <a name='L1569'></a><a href='#L1569'>1569</a>
- <a name='L1570'></a><a href='#L1570'>1570</a>
- <a name='L1571'></a><a href='#L1571'>1571</a>
- <a name='L1572'></a><a href='#L1572'>1572</a>
- <a name='L1573'></a><a href='#L1573'>1573</a>
- <a name='L1574'></a><a href='#L1574'>1574</a>
- <a name='L1575'></a><a href='#L1575'>1575</a>
- <a name='L1576'></a><a href='#L1576'>1576</a>
- <a name='L1577'></a><a href='#L1577'>1577</a>
- <a name='L1578'></a><a href='#L1578'>1578</a>
- <a name='L1579'></a><a href='#L1579'>1579</a>
- <a name='L1580'></a><a href='#L1580'>1580</a>
- <a name='L1581'></a><a href='#L1581'>1581</a>
- <a name='L1582'></a><a href='#L1582'>1582</a>
- <a name='L1583'></a><a href='#L1583'>1583</a>
- <a name='L1584'></a><a href='#L1584'>1584</a>
- <a name='L1585'></a><a href='#L1585'>1585</a>
- <a name='L1586'></a><a href='#L1586'>1586</a>
- <a name='L1587'></a><a href='#L1587'>1587</a>
- <a name='L1588'></a><a href='#L1588'>1588</a>
- <a name='L1589'></a><a href='#L1589'>1589</a>
- <a name='L1590'></a><a href='#L1590'>1590</a>
- <a name='L1591'></a><a href='#L1591'>1591</a>
- <a name='L1592'></a><a href='#L1592'>1592</a>
- <a name='L1593'></a><a href='#L1593'>1593</a>
- <a name='L1594'></a><a href='#L1594'>1594</a>
- <a name='L1595'></a><a href='#L1595'>1595</a>
- <a name='L1596'></a><a href='#L1596'>1596</a>
- <a name='L1597'></a><a href='#L1597'>1597</a>
- <a name='L1598'></a><a href='#L1598'>1598</a>
- <a name='L1599'></a><a href='#L1599'>1599</a>
- <a name='L1600'></a><a href='#L1600'>1600</a>
- <a name='L1601'></a><a href='#L1601'>1601</a>
- <a name='L1602'></a><a href='#L1602'>1602</a>
- <a name='L1603'></a><a href='#L1603'>1603</a>
- <a name='L1604'></a><a href='#L1604'>1604</a>
- <a name='L1605'></a><a href='#L1605'>1605</a>
- <a name='L1606'></a><a href='#L1606'>1606</a>
- <a name='L1607'></a><a href='#L1607'>1607</a>
- <a name='L1608'></a><a href='#L1608'>1608</a>
- <a name='L1609'></a><a href='#L1609'>1609</a>
- <a name='L1610'></a><a href='#L1610'>1610</a>
- <a name='L1611'></a><a href='#L1611'>1611</a>
- <a name='L1612'></a><a href='#L1612'>1612</a>
- <a name='L1613'></a><a href='#L1613'>1613</a>
- <a name='L1614'></a><a href='#L1614'>1614</a>
- <a name='L1615'></a><a href='#L1615'>1615</a>
- <a name='L1616'></a><a href='#L1616'>1616</a>
- <a name='L1617'></a><a href='#L1617'>1617</a>
- <a name='L1618'></a><a href='#L1618'>1618</a>
- <a name='L1619'></a><a href='#L1619'>1619</a>
- <a name='L1620'></a><a href='#L1620'>1620</a>
- <a name='L1621'></a><a href='#L1621'>1621</a>
- <a name='L1622'></a><a href='#L1622'>1622</a>
- <a name='L1623'></a><a href='#L1623'>1623</a>
- <a name='L1624'></a><a href='#L1624'>1624</a>
- <a name='L1625'></a><a href='#L1625'>1625</a>
- <a name='L1626'></a><a href='#L1626'>1626</a>
- <a name='L1627'></a><a href='#L1627'>1627</a>
- <a name='L1628'></a><a href='#L1628'>1628</a>
- <a name='L1629'></a><a href='#L1629'>1629</a>
- <a name='L1630'></a><a href='#L1630'>1630</a>
- <a name='L1631'></a><a href='#L1631'>1631</a>
- <a name='L1632'></a><a href='#L1632'>1632</a>
- <a name='L1633'></a><a href='#L1633'>1633</a>
- <a name='L1634'></a><a href='#L1634'>1634</a>
- <a name='L1635'></a><a href='#L1635'>1635</a>
- <a name='L1636'></a><a href='#L1636'>1636</a>
- <a name='L1637'></a><a href='#L1637'>1637</a>
- <a name='L1638'></a><a href='#L1638'>1638</a>
- <a name='L1639'></a><a href='#L1639'>1639</a>
- <a name='L1640'></a><a href='#L1640'>1640</a>
- <a name='L1641'></a><a href='#L1641'>1641</a>
- <a name='L1642'></a><a href='#L1642'>1642</a>
- <a name='L1643'></a><a href='#L1643'>1643</a>
- <a name='L1644'></a><a href='#L1644'>1644</a>
- <a name='L1645'></a><a href='#L1645'>1645</a>
- <a name='L1646'></a><a href='#L1646'>1646</a>
- <a name='L1647'></a><a href='#L1647'>1647</a>
- <a name='L1648'></a><a href='#L1648'>1648</a>
- <a name='L1649'></a><a href='#L1649'>1649</a>
- <a name='L1650'></a><a href='#L1650'>1650</a>
- <a name='L1651'></a><a href='#L1651'>1651</a>
- <a name='L1652'></a><a href='#L1652'>1652</a>
- <a name='L1653'></a><a href='#L1653'>1653</a>
- <a name='L1654'></a><a href='#L1654'>1654</a>
- <a name='L1655'></a><a href='#L1655'>1655</a>
- <a name='L1656'></a><a href='#L1656'>1656</a>
- <a name='L1657'></a><a href='#L1657'>1657</a>
- <a name='L1658'></a><a href='#L1658'>1658</a>
- <a name='L1659'></a><a href='#L1659'>1659</a>
- <a name='L1660'></a><a href='#L1660'>1660</a>
- <a name='L1661'></a><a href='#L1661'>1661</a>
- <a name='L1662'></a><a href='#L1662'>1662</a>
- <a name='L1663'></a><a href='#L1663'>1663</a>
- <a name='L1664'></a><a href='#L1664'>1664</a>
- <a name='L1665'></a><a href='#L1665'>1665</a>
- <a name='L1666'></a><a href='#L1666'>1666</a>
- <a name='L1667'></a><a href='#L1667'>1667</a>
- <a name='L1668'></a><a href='#L1668'>1668</a>
- <a name='L1669'></a><a href='#L1669'>1669</a>
- <a name='L1670'></a><a href='#L1670'>1670</a>
- <a name='L1671'></a><a href='#L1671'>1671</a>
- <a name='L1672'></a><a href='#L1672'>1672</a>
- <a name='L1673'></a><a href='#L1673'>1673</a>
- <a name='L1674'></a><a href='#L1674'>1674</a>
- <a name='L1675'></a><a href='#L1675'>1675</a>
- <a name='L1676'></a><a href='#L1676'>1676</a>
- <a name='L1677'></a><a href='#L1677'>1677</a>
- <a name='L1678'></a><a href='#L1678'>1678</a>
- <a name='L1679'></a><a href='#L1679'>1679</a>
- <a name='L1680'></a><a href='#L1680'>1680</a>
- <a name='L1681'></a><a href='#L1681'>1681</a>
- <a name='L1682'></a><a href='#L1682'>1682</a>
- <a name='L1683'></a><a href='#L1683'>1683</a>
- <a name='L1684'></a><a href='#L1684'>1684</a>
- <a name='L1685'></a><a href='#L1685'>1685</a>
- <a name='L1686'></a><a href='#L1686'>1686</a>
- <a name='L1687'></a><a href='#L1687'>1687</a>
- <a name='L1688'></a><a href='#L1688'>1688</a>
- <a name='L1689'></a><a href='#L1689'>1689</a>
- <a name='L1690'></a><a href='#L1690'>1690</a>
- <a name='L1691'></a><a href='#L1691'>1691</a>
- <a name='L1692'></a><a href='#L1692'>1692</a>
- <a name='L1693'></a><a href='#L1693'>1693</a>
- <a name='L1694'></a><a href='#L1694'>1694</a>
- <a name='L1695'></a><a href='#L1695'>1695</a>
- <a name='L1696'></a><a href='#L1696'>1696</a>
- <a name='L1697'></a><a href='#L1697'>1697</a>
- <a name='L1698'></a><a href='#L1698'>1698</a>
- <a name='L1699'></a><a href='#L1699'>1699</a>
- <a name='L1700'></a><a href='#L1700'>1700</a>
- <a name='L1701'></a><a href='#L1701'>1701</a>
- <a name='L1702'></a><a href='#L1702'>1702</a>
- <a name='L1703'></a><a href='#L1703'>1703</a>
- <a name='L1704'></a><a href='#L1704'>1704</a>
- <a name='L1705'></a><a href='#L1705'>1705</a>
- <a name='L1706'></a><a href='#L1706'>1706</a>
- <a name='L1707'></a><a href='#L1707'>1707</a>
- <a name='L1708'></a><a href='#L1708'>1708</a>
- <a name='L1709'></a><a href='#L1709'>1709</a>
- <a name='L1710'></a><a href='#L1710'>1710</a>
- <a name='L1711'></a><a href='#L1711'>1711</a>
- <a name='L1712'></a><a href='#L1712'>1712</a>
- <a name='L1713'></a><a href='#L1713'>1713</a>
- <a name='L1714'></a><a href='#L1714'>1714</a>
- <a name='L1715'></a><a href='#L1715'>1715</a>
- <a name='L1716'></a><a href='#L1716'>1716</a>
- <a name='L1717'></a><a href='#L1717'>1717</a>
- <a name='L1718'></a><a href='#L1718'>1718</a>
- <a name='L1719'></a><a href='#L1719'>1719</a>
- <a name='L1720'></a><a href='#L1720'>1720</a>
- <a name='L1721'></a><a href='#L1721'>1721</a>
- <a name='L1722'></a><a href='#L1722'>1722</a>
- <a name='L1723'></a><a href='#L1723'>1723</a>
- <a name='L1724'></a><a href='#L1724'>1724</a>
- <a name='L1725'></a><a href='#L1725'>1725</a>
- <a name='L1726'></a><a href='#L1726'>1726</a>
- <a name='L1727'></a><a href='#L1727'>1727</a>
- <a name='L1728'></a><a href='#L1728'>1728</a>
- <a name='L1729'></a><a href='#L1729'>1729</a>
- <a name='L1730'></a><a href='#L1730'>1730</a>
- <a name='L1731'></a><a href='#L1731'>1731</a>
- <a name='L1732'></a><a href='#L1732'>1732</a>
- <a name='L1733'></a><a href='#L1733'>1733</a>
- <a name='L1734'></a><a href='#L1734'>1734</a>
- <a name='L1735'></a><a href='#L1735'>1735</a>
- <a name='L1736'></a><a href='#L1736'>1736</a>
- <a name='L1737'></a><a href='#L1737'>1737</a>
- <a name='L1738'></a><a href='#L1738'>1738</a>
- <a name='L1739'></a><a href='#L1739'>1739</a>
- <a name='L1740'></a><a href='#L1740'>1740</a>
- <a name='L1741'></a><a href='#L1741'>1741</a>
- <a name='L1742'></a><a href='#L1742'>1742</a>
- <a name='L1743'></a><a href='#L1743'>1743</a>
- <a name='L1744'></a><a href='#L1744'>1744</a>
- <a name='L1745'></a><a href='#L1745'>1745</a>
- <a name='L1746'></a><a href='#L1746'>1746</a>
- <a name='L1747'></a><a href='#L1747'>1747</a>
- <a name='L1748'></a><a href='#L1748'>1748</a>
- <a name='L1749'></a><a href='#L1749'>1749</a>
- <a name='L1750'></a><a href='#L1750'>1750</a>
- <a name='L1751'></a><a href='#L1751'>1751</a>
- <a name='L1752'></a><a href='#L1752'>1752</a>
- <a name='L1753'></a><a href='#L1753'>1753</a>
- <a name='L1754'></a><a href='#L1754'>1754</a>
- <a name='L1755'></a><a href='#L1755'>1755</a>
- <a name='L1756'></a><a href='#L1756'>1756</a>
- <a name='L1757'></a><a href='#L1757'>1757</a>
- <a name='L1758'></a><a href='#L1758'>1758</a>
- <a name='L1759'></a><a href='#L1759'>1759</a>
- <a name='L1760'></a><a href='#L1760'>1760</a>
- <a name='L1761'></a><a href='#L1761'>1761</a>
- <a name='L1762'></a><a href='#L1762'>1762</a>
- <a name='L1763'></a><a href='#L1763'>1763</a>
- <a name='L1764'></a><a href='#L1764'>1764</a>
- <a name='L1765'></a><a href='#L1765'>1765</a>
- <a name='L1766'></a><a href='#L1766'>1766</a>
- <a name='L1767'></a><a href='#L1767'>1767</a>
- <a name='L1768'></a><a href='#L1768'>1768</a>
- <a name='L1769'></a><a href='#L1769'>1769</a>
- <a name='L1770'></a><a href='#L1770'>1770</a>
- <a name='L1771'></a><a href='#L1771'>1771</a>
- <a name='L1772'></a><a href='#L1772'>1772</a>
- <a name='L1773'></a><a href='#L1773'>1773</a>
- <a name='L1774'></a><a href='#L1774'>1774</a>
- <a name='L1775'></a><a href='#L1775'>1775</a>
- <a name='L1776'></a><a href='#L1776'>1776</a>
- <a name='L1777'></a><a href='#L1777'>1777</a>
- <a name='L1778'></a><a href='#L1778'>1778</a>
- <a name='L1779'></a><a href='#L1779'>1779</a>
- <a name='L1780'></a><a href='#L1780'>1780</a>
- <a name='L1781'></a><a href='#L1781'>1781</a>
- <a name='L1782'></a><a href='#L1782'>1782</a>
- <a name='L1783'></a><a href='#L1783'>1783</a>
- <a name='L1784'></a><a href='#L1784'>1784</a>
- <a name='L1785'></a><a href='#L1785'>1785</a>
- <a name='L1786'></a><a href='#L1786'>1786</a>
- <a name='L1787'></a><a href='#L1787'>1787</a>
- <a name='L1788'></a><a href='#L1788'>1788</a>
- <a name='L1789'></a><a href='#L1789'>1789</a>
- <a name='L1790'></a><a href='#L1790'>1790</a>
- <a name='L1791'></a><a href='#L1791'>1791</a>
- <a name='L1792'></a><a href='#L1792'>1792</a>
- <a name='L1793'></a><a href='#L1793'>1793</a>
- <a name='L1794'></a><a href='#L1794'>1794</a>
- <a name='L1795'></a><a href='#L1795'>1795</a>
- <a name='L1796'></a><a href='#L1796'>1796</a>
- <a name='L1797'></a><a href='#L1797'>1797</a>
- <a name='L1798'></a><a href='#L1798'>1798</a>
- <a name='L1799'></a><a href='#L1799'>1799</a>
- <a name='L1800'></a><a href='#L1800'>1800</a>
- <a name='L1801'></a><a href='#L1801'>1801</a>
- <a name='L1802'></a><a href='#L1802'>1802</a>
- <a name='L1803'></a><a href='#L1803'>1803</a>
- <a name='L1804'></a><a href='#L1804'>1804</a>
- <a name='L1805'></a><a href='#L1805'>1805</a>
- <a name='L1806'></a><a href='#L1806'>1806</a>
- <a name='L1807'></a><a href='#L1807'>1807</a>
- <a name='L1808'></a><a href='#L1808'>1808</a>
- <a name='L1809'></a><a href='#L1809'>1809</a>
- <a name='L1810'></a><a href='#L1810'>1810</a>
- <a name='L1811'></a><a href='#L1811'>1811</a>
- <a name='L1812'></a><a href='#L1812'>1812</a>
- <a name='L1813'></a><a href='#L1813'>1813</a>
- <a name='L1814'></a><a href='#L1814'>1814</a>
- <a name='L1815'></a><a href='#L1815'>1815</a>
- <a name='L1816'></a><a href='#L1816'>1816</a>
- <a name='L1817'></a><a href='#L1817'>1817</a>
- <a name='L1818'></a><a href='#L1818'>1818</a>
- <a name='L1819'></a><a href='#L1819'>1819</a>
- <a name='L1820'></a><a href='#L1820'>1820</a>
- <a name='L1821'></a><a href='#L1821'>1821</a>
- <a name='L1822'></a><a href='#L1822'>1822</a>
- <a name='L1823'></a><a href='#L1823'>1823</a>
- <a name='L1824'></a><a href='#L1824'>1824</a>
- <a name='L1825'></a><a href='#L1825'>1825</a>
- <a name='L1826'></a><a href='#L1826'>1826</a>
- <a name='L1827'></a><a href='#L1827'>1827</a>
- <a name='L1828'></a><a href='#L1828'>1828</a>
- <a name='L1829'></a><a href='#L1829'>1829</a>
- <a name='L1830'></a><a href='#L1830'>1830</a>
- <a name='L1831'></a><a href='#L1831'>1831</a>
- <a name='L1832'></a><a href='#L1832'>1832</a>
- <a name='L1833'></a><a href='#L1833'>1833</a>
- <a name='L1834'></a><a href='#L1834'>1834</a>
- <a name='L1835'></a><a href='#L1835'>1835</a>
- <a name='L1836'></a><a href='#L1836'>1836</a>
- <a name='L1837'></a><a href='#L1837'>1837</a>
- <a name='L1838'></a><a href='#L1838'>1838</a>
- <a name='L1839'></a><a href='#L1839'>1839</a>
- <a name='L1840'></a><a href='#L1840'>1840</a>
- <a name='L1841'></a><a href='#L1841'>1841</a>
- <a name='L1842'></a><a href='#L1842'>1842</a>
- <a name='L1843'></a><a href='#L1843'>1843</a>
- <a name='L1844'></a><a href='#L1844'>1844</a>
- <a name='L1845'></a><a href='#L1845'>1845</a>
- <a name='L1846'></a><a href='#L1846'>1846</a>
- <a name='L1847'></a><a href='#L1847'>1847</a>
- <a name='L1848'></a><a href='#L1848'>1848</a>
- <a name='L1849'></a><a href='#L1849'>1849</a>
- <a name='L1850'></a><a href='#L1850'>1850</a>
- <a name='L1851'></a><a href='#L1851'>1851</a>
- <a name='L1852'></a><a href='#L1852'>1852</a>
- <a name='L1853'></a><a href='#L1853'>1853</a>
- <a name='L1854'></a><a href='#L1854'>1854</a>
- <a name='L1855'></a><a href='#L1855'>1855</a>
- <a name='L1856'></a><a href='#L1856'>1856</a>
- <a name='L1857'></a><a href='#L1857'>1857</a>
- <a name='L1858'></a><a href='#L1858'>1858</a>
- <a name='L1859'></a><a href='#L1859'>1859</a>
- <a name='L1860'></a><a href='#L1860'>1860</a>
- <a name='L1861'></a><a href='#L1861'>1861</a>
- <a name='L1862'></a><a href='#L1862'>1862</a>
- <a name='L1863'></a><a href='#L1863'>1863</a>
- <a name='L1864'></a><a href='#L1864'>1864</a>
- <a name='L1865'></a><a href='#L1865'>1865</a>
- <a name='L1866'></a><a href='#L1866'>1866</a>
- <a name='L1867'></a><a href='#L1867'>1867</a>
- <a name='L1868'></a><a href='#L1868'>1868</a>
- <a name='L1869'></a><a href='#L1869'>1869</a>
- <a name='L1870'></a><a href='#L1870'>1870</a>
- <a name='L1871'></a><a href='#L1871'>1871</a>
- <a name='L1872'></a><a href='#L1872'>1872</a>
- <a name='L1873'></a><a href='#L1873'>1873</a>
- <a name='L1874'></a><a href='#L1874'>1874</a>
- <a name='L1875'></a><a href='#L1875'>1875</a>
- <a name='L1876'></a><a href='#L1876'>1876</a>
- <a name='L1877'></a><a href='#L1877'>1877</a>
- <a name='L1878'></a><a href='#L1878'>1878</a>
- <a name='L1879'></a><a href='#L1879'>1879</a>
- <a name='L1880'></a><a href='#L1880'>1880</a>
- <a name='L1881'></a><a href='#L1881'>1881</a>
- <a name='L1882'></a><a href='#L1882'>1882</a>
- <a name='L1883'></a><a href='#L1883'>1883</a>
- <a name='L1884'></a><a href='#L1884'>1884</a>
- <a name='L1885'></a><a href='#L1885'>1885</a>
- <a name='L1886'></a><a href='#L1886'>1886</a>
- <a name='L1887'></a><a href='#L1887'>1887</a>
- <a name='L1888'></a><a href='#L1888'>1888</a>
- <a name='L1889'></a><a href='#L1889'>1889</a>
- <a name='L1890'></a><a href='#L1890'>1890</a>
- <a name='L1891'></a><a href='#L1891'>1891</a>
- <a name='L1892'></a><a href='#L1892'>1892</a>
- <a name='L1893'></a><a href='#L1893'>1893</a>
- <a name='L1894'></a><a href='#L1894'>1894</a>
- <a name='L1895'></a><a href='#L1895'>1895</a>
- <a name='L1896'></a><a href='#L1896'>1896</a>
- <a name='L1897'></a><a href='#L1897'>1897</a>
- <a name='L1898'></a><a href='#L1898'>1898</a>
- <a name='L1899'></a><a href='#L1899'>1899</a>
- <a name='L1900'></a><a href='#L1900'>1900</a>
- <a name='L1901'></a><a href='#L1901'>1901</a>
- <a name='L1902'></a><a href='#L1902'>1902</a>
- <a name='L1903'></a><a href='#L1903'>1903</a>
- <a name='L1904'></a><a href='#L1904'>1904</a>
- <a name='L1905'></a><a href='#L1905'>1905</a>
- <a name='L1906'></a><a href='#L1906'>1906</a>
- <a name='L1907'></a><a href='#L1907'>1907</a>
- <a name='L1908'></a><a href='#L1908'>1908</a>
- <a name='L1909'></a><a href='#L1909'>1909</a>
- <a name='L1910'></a><a href='#L1910'>1910</a>
- <a name='L1911'></a><a href='#L1911'>1911</a>
- <a name='L1912'></a><a href='#L1912'>1912</a>
- <a name='L1913'></a><a href='#L1913'>1913</a>
- <a name='L1914'></a><a href='#L1914'>1914</a>
- <a name='L1915'></a><a href='#L1915'>1915</a>
- <a name='L1916'></a><a href='#L1916'>1916</a>
- <a name='L1917'></a><a href='#L1917'>1917</a>
- <a name='L1918'></a><a href='#L1918'>1918</a>
- <a name='L1919'></a><a href='#L1919'>1919</a>
- <a name='L1920'></a><a href='#L1920'>1920</a>
- <a name='L1921'></a><a href='#L1921'>1921</a>
- <a name='L1922'></a><a href='#L1922'>1922</a>
- <a name='L1923'></a><a href='#L1923'>1923</a>
- <a name='L1924'></a><a href='#L1924'>1924</a>
- <a name='L1925'></a><a href='#L1925'>1925</a>
- <a name='L1926'></a><a href='#L1926'>1926</a>
- <a name='L1927'></a><a href='#L1927'>1927</a>
- <a name='L1928'></a><a href='#L1928'>1928</a>
- <a name='L1929'></a><a href='#L1929'>1929</a>
- <a name='L1930'></a><a href='#L1930'>1930</a>
- <a name='L1931'></a><a href='#L1931'>1931</a>
- <a name='L1932'></a><a href='#L1932'>1932</a>
- <a name='L1933'></a><a href='#L1933'>1933</a>
- <a name='L1934'></a><a href='#L1934'>1934</a>
- <a name='L1935'></a><a href='#L1935'>1935</a>
- <a name='L1936'></a><a href='#L1936'>1936</a>
- <a name='L1937'></a><a href='#L1937'>1937</a>
- <a name='L1938'></a><a href='#L1938'>1938</a>
- <a name='L1939'></a><a href='#L1939'>1939</a>
- <a name='L1940'></a><a href='#L1940'>1940</a>
- <a name='L1941'></a><a href='#L1941'>1941</a>
- <a name='L1942'></a><a href='#L1942'>1942</a>
- <a name='L1943'></a><a href='#L1943'>1943</a>
- <a name='L1944'></a><a href='#L1944'>1944</a>
- <a name='L1945'></a><a href='#L1945'>1945</a>
- <a name='L1946'></a><a href='#L1946'>1946</a>
- <a name='L1947'></a><a href='#L1947'>1947</a>
- <a name='L1948'></a><a href='#L1948'>1948</a>
- <a name='L1949'></a><a href='#L1949'>1949</a>
- <a name='L1950'></a><a href='#L1950'>1950</a>
- <a name='L1951'></a><a href='#L1951'>1951</a>
- <a name='L1952'></a><a href='#L1952'>1952</a>
- <a name='L1953'></a><a href='#L1953'>1953</a>
- <a name='L1954'></a><a href='#L1954'>1954</a>
- <a name='L1955'></a><a href='#L1955'>1955</a>
- <a name='L1956'></a><a href='#L1956'>1956</a>
- <a name='L1957'></a><a href='#L1957'>1957</a>
- <a name='L1958'></a><a href='#L1958'>1958</a>
- <a name='L1959'></a><a href='#L1959'>1959</a>
- <a name='L1960'></a><a href='#L1960'>1960</a>
- <a name='L1961'></a><a href='#L1961'>1961</a>
- <a name='L1962'></a><a href='#L1962'>1962</a>
- <a name='L1963'></a><a href='#L1963'>1963</a>
- <a name='L1964'></a><a href='#L1964'>1964</a>
- <a name='L1965'></a><a href='#L1965'>1965</a>
- <a name='L1966'></a><a href='#L1966'>1966</a>
- <a name='L1967'></a><a href='#L1967'>1967</a>
- <a name='L1968'></a><a href='#L1968'>1968</a>
- <a name='L1969'></a><a href='#L1969'>1969</a>
- <a name='L1970'></a><a href='#L1970'>1970</a>
- <a name='L1971'></a><a href='#L1971'>1971</a>
- <a name='L1972'></a><a href='#L1972'>1972</a>
- <a name='L1973'></a><a href='#L1973'>1973</a>
- <a name='L1974'></a><a href='#L1974'>1974</a>
- <a name='L1975'></a><a href='#L1975'>1975</a>
- <a name='L1976'></a><a href='#L1976'>1976</a>
- <a name='L1977'></a><a href='#L1977'>1977</a>
- <a name='L1978'></a><a href='#L1978'>1978</a>
- <a name='L1979'></a><a href='#L1979'>1979</a>
- <a name='L1980'></a><a href='#L1980'>1980</a>
- <a name='L1981'></a><a href='#L1981'>1981</a>
- <a name='L1982'></a><a href='#L1982'>1982</a>
- <a name='L1983'></a><a href='#L1983'>1983</a>
- <a name='L1984'></a><a href='#L1984'>1984</a>
- <a name='L1985'></a><a href='#L1985'>1985</a>
- <a name='L1986'></a><a href='#L1986'>1986</a>
- <a name='L1987'></a><a href='#L1987'>1987</a>
- <a name='L1988'></a><a href='#L1988'>1988</a>
- <a name='L1989'></a><a href='#L1989'>1989</a>
- <a name='L1990'></a><a href='#L1990'>1990</a>
- <a name='L1991'></a><a href='#L1991'>1991</a>
- <a name='L1992'></a><a href='#L1992'>1992</a>
- <a name='L1993'></a><a href='#L1993'>1993</a>
- <a name='L1994'></a><a href='#L1994'>1994</a>
- <a name='L1995'></a><a href='#L1995'>1995</a>
- <a name='L1996'></a><a href='#L1996'>1996</a>
- <a name='L1997'></a><a href='#L1997'>1997</a>
- <a name='L1998'></a><a href='#L1998'>1998</a>
- <a name='L1999'></a><a href='#L1999'>1999</a>
- <a name='L2000'></a><a href='#L2000'>2000</a>
- <a name='L2001'></a><a href='#L2001'>2001</a>
- <a name='L2002'></a><a href='#L2002'>2002</a>
- <a name='L2003'></a><a href='#L2003'>2003</a>
- <a name='L2004'></a><a href='#L2004'>2004</a>
- <a name='L2005'></a><a href='#L2005'>2005</a>
- <a name='L2006'></a><a href='#L2006'>2006</a>
- <a name='L2007'></a><a href='#L2007'>2007</a>
- <a name='L2008'></a><a href='#L2008'>2008</a>
- <a name='L2009'></a><a href='#L2009'>2009</a>
- <a name='L2010'></a><a href='#L2010'>2010</a>
- <a name='L2011'></a><a href='#L2011'>2011</a>
- <a name='L2012'></a><a href='#L2012'>2012</a>
- <a name='L2013'></a><a href='#L2013'>2013</a>
- <a name='L2014'></a><a href='#L2014'>2014</a>
- <a name='L2015'></a><a href='#L2015'>2015</a>
- <a name='L2016'></a><a href='#L2016'>2016</a>
- <a name='L2017'></a><a href='#L2017'>2017</a>
- <a name='L2018'></a><a href='#L2018'>2018</a>
- <a name='L2019'></a><a href='#L2019'>2019</a>
- <a name='L2020'></a><a href='#L2020'>2020</a>
- <a name='L2021'></a><a href='#L2021'>2021</a>
- <a name='L2022'></a><a href='#L2022'>2022</a>
- <a name='L2023'></a><a href='#L2023'>2023</a>
- <a name='L2024'></a><a href='#L2024'>2024</a>
- <a name='L2025'></a><a href='#L2025'>2025</a>
- <a name='L2026'></a><a href='#L2026'>2026</a>
- <a name='L2027'></a><a href='#L2027'>2027</a>
- <a name='L2028'></a><a href='#L2028'>2028</a>
- <a name='L2029'></a><a href='#L2029'>2029</a>
- <a name='L2030'></a><a href='#L2030'>2030</a>
- <a name='L2031'></a><a href='#L2031'>2031</a>
- <a name='L2032'></a><a href='#L2032'>2032</a>
- <a name='L2033'></a><a href='#L2033'>2033</a>
- <a name='L2034'></a><a href='#L2034'>2034</a>
- <a name='L2035'></a><a href='#L2035'>2035</a>
- <a name='L2036'></a><a href='#L2036'>2036</a>
- <a name='L2037'></a><a href='#L2037'>2037</a>
- <a name='L2038'></a><a href='#L2038'>2038</a>
- <a name='L2039'></a><a href='#L2039'>2039</a>
- <a name='L2040'></a><a href='#L2040'>2040</a>
- <a name='L2041'></a><a href='#L2041'>2041</a>
- <a name='L2042'></a><a href='#L2042'>2042</a>
- <a name='L2043'></a><a href='#L2043'>2043</a>
- <a name='L2044'></a><a href='#L2044'>2044</a>
- <a name='L2045'></a><a href='#L2045'>2045</a>
- <a name='L2046'></a><a href='#L2046'>2046</a>
- <a name='L2047'></a><a href='#L2047'>2047</a>
- <a name='L2048'></a><a href='#L2048'>2048</a>
- <a name='L2049'></a><a href='#L2049'>2049</a>
- <a name='L2050'></a><a href='#L2050'>2050</a>
- <a name='L2051'></a><a href='#L2051'>2051</a>
- <a name='L2052'></a><a href='#L2052'>2052</a>
- <a name='L2053'></a><a href='#L2053'>2053</a>
- <a name='L2054'></a><a href='#L2054'>2054</a>
- <a name='L2055'></a><a href='#L2055'>2055</a>
- <a name='L2056'></a><a href='#L2056'>2056</a>
- <a name='L2057'></a><a href='#L2057'>2057</a>
- <a name='L2058'></a><a href='#L2058'>2058</a>
- <a name='L2059'></a><a href='#L2059'>2059</a>
- <a name='L2060'></a><a href='#L2060'>2060</a>
- <a name='L2061'></a><a href='#L2061'>2061</a>
- <a name='L2062'></a><a href='#L2062'>2062</a>
- <a name='L2063'></a><a href='#L2063'>2063</a>
- <a name='L2064'></a><a href='#L2064'>2064</a>
- <a name='L2065'></a><a href='#L2065'>2065</a>
- <a name='L2066'></a><a href='#L2066'>2066</a>
- <a name='L2067'></a><a href='#L2067'>2067</a>
- <a name='L2068'></a><a href='#L2068'>2068</a>
- <a name='L2069'></a><a href='#L2069'>2069</a>
- <a name='L2070'></a><a href='#L2070'>2070</a>
- <a name='L2071'></a><a href='#L2071'>2071</a>
- <a name='L2072'></a><a href='#L2072'>2072</a>
- <a name='L2073'></a><a href='#L2073'>2073</a>
- <a name='L2074'></a><a href='#L2074'>2074</a>
- <a name='L2075'></a><a href='#L2075'>2075</a>
- <a name='L2076'></a><a href='#L2076'>2076</a>
- <a name='L2077'></a><a href='#L2077'>2077</a>
- <a name='L2078'></a><a href='#L2078'>2078</a>
- <a name='L2079'></a><a href='#L2079'>2079</a>
- <a name='L2080'></a><a href='#L2080'>2080</a>
- <a name='L2081'></a><a href='#L2081'>2081</a>
- <a name='L2082'></a><a href='#L2082'>2082</a>
- <a name='L2083'></a><a href='#L2083'>2083</a>
- <a name='L2084'></a><a href='#L2084'>2084</a>
- <a name='L2085'></a><a href='#L2085'>2085</a>
- <a name='L2086'></a><a href='#L2086'>2086</a>
- <a name='L2087'></a><a href='#L2087'>2087</a>
- <a name='L2088'></a><a href='#L2088'>2088</a>
- <a name='L2089'></a><a href='#L2089'>2089</a>
- <a name='L2090'></a><a href='#L2090'>2090</a>
- <a name='L2091'></a><a href='#L2091'>2091</a>
- <a name='L2092'></a><a href='#L2092'>2092</a>
- <a name='L2093'></a><a href='#L2093'>2093</a>
- <a name='L2094'></a><a href='#L2094'>2094</a>
- <a name='L2095'></a><a href='#L2095'>2095</a>
- <a name='L2096'></a><a href='#L2096'>2096</a>
- <a name='L2097'></a><a href='#L2097'>2097</a>
- <a name='L2098'></a><a href='#L2098'>2098</a>
- <a name='L2099'></a><a href='#L2099'>2099</a>
- <a name='L2100'></a><a href='#L2100'>2100</a>
- <a name='L2101'></a><a href='#L2101'>2101</a>
- <a name='L2102'></a><a href='#L2102'>2102</a>
- <a name='L2103'></a><a href='#L2103'>2103</a>
- <a name='L2104'></a><a href='#L2104'>2104</a>
- <a name='L2105'></a><a href='#L2105'>2105</a>
- <a name='L2106'></a><a href='#L2106'>2106</a>
- <a name='L2107'></a><a href='#L2107'>2107</a>
- <a name='L2108'></a><a href='#L2108'>2108</a>
- <a name='L2109'></a><a href='#L2109'>2109</a>
- <a name='L2110'></a><a href='#L2110'>2110</a>
- <a name='L2111'></a><a href='#L2111'>2111</a>
- <a name='L2112'></a><a href='#L2112'>2112</a>
- <a name='L2113'></a><a href='#L2113'>2113</a>
- <a name='L2114'></a><a href='#L2114'>2114</a>
- <a name='L2115'></a><a href='#L2115'>2115</a>
- <a name='L2116'></a><a href='#L2116'>2116</a>
- <a name='L2117'></a><a href='#L2117'>2117</a>
- <a name='L2118'></a><a href='#L2118'>2118</a>
- <a name='L2119'></a><a href='#L2119'>2119</a>
- <a name='L2120'></a><a href='#L2120'>2120</a>
- <a name='L2121'></a><a href='#L2121'>2121</a>
- <a name='L2122'></a><a href='#L2122'>2122</a>
- <a name='L2123'></a><a href='#L2123'>2123</a>
- <a name='L2124'></a><a href='#L2124'>2124</a>
- <a name='L2125'></a><a href='#L2125'>2125</a>
- <a name='L2126'></a><a href='#L2126'>2126</a>
- <a name='L2127'></a><a href='#L2127'>2127</a>
- <a name='L2128'></a><a href='#L2128'>2128</a>
- <a name='L2129'></a><a href='#L2129'>2129</a>
- <a name='L2130'></a><a href='#L2130'>2130</a>
- <a name='L2131'></a><a href='#L2131'>2131</a>
- <a name='L2132'></a><a href='#L2132'>2132</a>
- <a name='L2133'></a><a href='#L2133'>2133</a>
- <a name='L2134'></a><a href='#L2134'>2134</a>
- <a name='L2135'></a><a href='#L2135'>2135</a>
- <a name='L2136'></a><a href='#L2136'>2136</a>
- <a name='L2137'></a><a href='#L2137'>2137</a>
- <a name='L2138'></a><a href='#L2138'>2138</a>
- <a name='L2139'></a><a href='#L2139'>2139</a>
- <a name='L2140'></a><a href='#L2140'>2140</a>
- <a name='L2141'></a><a href='#L2141'>2141</a>
- <a name='L2142'></a><a href='#L2142'>2142</a>
- <a name='L2143'></a><a href='#L2143'>2143</a>
- <a name='L2144'></a><a href='#L2144'>2144</a>
- <a name='L2145'></a><a href='#L2145'>2145</a>
- <a name='L2146'></a><a href='#L2146'>2146</a>
- <a name='L2147'></a><a href='#L2147'>2147</a>
- <a name='L2148'></a><a href='#L2148'>2148</a>
- <a name='L2149'></a><a href='#L2149'>2149</a>
- <a name='L2150'></a><a href='#L2150'>2150</a>
- <a name='L2151'></a><a href='#L2151'>2151</a>
- <a name='L2152'></a><a href='#L2152'>2152</a>
- <a name='L2153'></a><a href='#L2153'>2153</a>
- <a name='L2154'></a><a href='#L2154'>2154</a>
- <a name='L2155'></a><a href='#L2155'>2155</a>
- <a name='L2156'></a><a href='#L2156'>2156</a>
- <a name='L2157'></a><a href='#L2157'>2157</a>
- <a name='L2158'></a><a href='#L2158'>2158</a>
- <a name='L2159'></a><a href='#L2159'>2159</a>
- <a name='L2160'></a><a href='#L2160'>2160</a>
- <a name='L2161'></a><a href='#L2161'>2161</a>
- <a name='L2162'></a><a href='#L2162'>2162</a>
- <a name='L2163'></a><a href='#L2163'>2163</a>
- <a name='L2164'></a><a href='#L2164'>2164</a>
- <a name='L2165'></a><a href='#L2165'>2165</a>
- <a name='L2166'></a><a href='#L2166'>2166</a>
- <a name='L2167'></a><a href='#L2167'>2167</a>
- <a name='L2168'></a><a href='#L2168'>2168</a>
- <a name='L2169'></a><a href='#L2169'>2169</a>
- <a name='L2170'></a><a href='#L2170'>2170</a>
- <a name='L2171'></a><a href='#L2171'>2171</a>
- <a name='L2172'></a><a href='#L2172'>2172</a>
- <a name='L2173'></a><a href='#L2173'>2173</a>
- <a name='L2174'></a><a href='#L2174'>2174</a>
- <a name='L2175'></a><a href='#L2175'>2175</a>
- <a name='L2176'></a><a href='#L2176'>2176</a>
- <a name='L2177'></a><a href='#L2177'>2177</a>
- <a name='L2178'></a><a href='#L2178'>2178</a>
- <a name='L2179'></a><a href='#L2179'>2179</a>
- <a name='L2180'></a><a href='#L2180'>2180</a>
- <a name='L2181'></a><a href='#L2181'>2181</a>
- <a name='L2182'></a><a href='#L2182'>2182</a>
- <a name='L2183'></a><a href='#L2183'>2183</a>
- <a name='L2184'></a><a href='#L2184'>2184</a>
- <a name='L2185'></a><a href='#L2185'>2185</a>
- <a name='L2186'></a><a href='#L2186'>2186</a>
- <a name='L2187'></a><a href='#L2187'>2187</a>
- <a name='L2188'></a><a href='#L2188'>2188</a>
- <a name='L2189'></a><a href='#L2189'>2189</a>
- <a name='L2190'></a><a href='#L2190'>2190</a>
- <a name='L2191'></a><a href='#L2191'>2191</a>
- <a name='L2192'></a><a href='#L2192'>2192</a>
- <a name='L2193'></a><a href='#L2193'>2193</a>
- <a name='L2194'></a><a href='#L2194'>2194</a>
- <a name='L2195'></a><a href='#L2195'>2195</a>
- <a name='L2196'></a><a href='#L2196'>2196</a>
- <a name='L2197'></a><a href='#L2197'>2197</a>
- <a name='L2198'></a><a href='#L2198'>2198</a>
- <a name='L2199'></a><a href='#L2199'>2199</a>
- <a name='L2200'></a><a href='#L2200'>2200</a>
- <a name='L2201'></a><a href='#L2201'>2201</a>
- <a name='L2202'></a><a href='#L2202'>2202</a>
- <a name='L2203'></a><a href='#L2203'>2203</a>
- <a name='L2204'></a><a href='#L2204'>2204</a>
- <a name='L2205'></a><a href='#L2205'>2205</a>
- <a name='L2206'></a><a href='#L2206'>2206</a>
- <a name='L2207'></a><a href='#L2207'>2207</a>
- <a name='L2208'></a><a href='#L2208'>2208</a>
- <a name='L2209'></a><a href='#L2209'>2209</a>
- <a name='L2210'></a><a href='#L2210'>2210</a>
- <a name='L2211'></a><a href='#L2211'>2211</a>
- <a name='L2212'></a><a href='#L2212'>2212</a>
- <a name='L2213'></a><a href='#L2213'>2213</a>
- <a name='L2214'></a><a href='#L2214'>2214</a>
- <a name='L2215'></a><a href='#L2215'>2215</a>
- <a name='L2216'></a><a href='#L2216'>2216</a>
- <a name='L2217'></a><a href='#L2217'>2217</a>
- <a name='L2218'></a><a href='#L2218'>2218</a>
- <a name='L2219'></a><a href='#L2219'>2219</a>
- <a name='L2220'></a><a href='#L2220'>2220</a>
- <a name='L2221'></a><a href='#L2221'>2221</a>
- <a name='L2222'></a><a href='#L2222'>2222</a>
- <a name='L2223'></a><a href='#L2223'>2223</a>
- <a name='L2224'></a><a href='#L2224'>2224</a>
- <a name='L2225'></a><a href='#L2225'>2225</a>
- <a name='L2226'></a><a href='#L2226'>2226</a>
- <a name='L2227'></a><a href='#L2227'>2227</a>
- <a name='L2228'></a><a href='#L2228'>2228</a>
- <a name='L2229'></a><a href='#L2229'>2229</a>
- <a name='L2230'></a><a href='#L2230'>2230</a>
- <a name='L2231'></a><a href='#L2231'>2231</a>
- <a name='L2232'></a><a href='#L2232'>2232</a>
- <a name='L2233'></a><a href='#L2233'>2233</a>
- <a name='L2234'></a><a href='#L2234'>2234</a>
- <a name='L2235'></a><a href='#L2235'>2235</a>
- <a name='L2236'></a><a href='#L2236'>2236</a>
- <a name='L2237'></a><a href='#L2237'>2237</a>
- <a name='L2238'></a><a href='#L2238'>2238</a>
- <a name='L2239'></a><a href='#L2239'>2239</a>
- <a name='L2240'></a><a href='#L2240'>2240</a>
- <a name='L2241'></a><a href='#L2241'>2241</a>
- <a name='L2242'></a><a href='#L2242'>2242</a>
- <a name='L2243'></a><a href='#L2243'>2243</a>
- <a name='L2244'></a><a href='#L2244'>2244</a>
- <a name='L2245'></a><a href='#L2245'>2245</a>
- <a name='L2246'></a><a href='#L2246'>2246</a>
- <a name='L2247'></a><a href='#L2247'>2247</a>
- <a name='L2248'></a><a href='#L2248'>2248</a>
- <a name='L2249'></a><a href='#L2249'>2249</a>
- <a name='L2250'></a><a href='#L2250'>2250</a>
- <a name='L2251'></a><a href='#L2251'>2251</a>
- <a name='L2252'></a><a href='#L2252'>2252</a>
- <a name='L2253'></a><a href='#L2253'>2253</a>
- <a name='L2254'></a><a href='#L2254'>2254</a>
- <a name='L2255'></a><a href='#L2255'>2255</a>
- <a name='L2256'></a><a href='#L2256'>2256</a>
- <a name='L2257'></a><a href='#L2257'>2257</a>
- <a name='L2258'></a><a href='#L2258'>2258</a>
- <a name='L2259'></a><a href='#L2259'>2259</a>
- <a name='L2260'></a><a href='#L2260'>2260</a>
- <a name='L2261'></a><a href='#L2261'>2261</a>
- <a name='L2262'></a><a href='#L2262'>2262</a>
- <a name='L2263'></a><a href='#L2263'>2263</a>
- <a name='L2264'></a><a href='#L2264'>2264</a>
- <a name='L2265'></a><a href='#L2265'>2265</a>
- <a name='L2266'></a><a href='#L2266'>2266</a>
- <a name='L2267'></a><a href='#L2267'>2267</a>
- <a name='L2268'></a><a href='#L2268'>2268</a>
- <a name='L2269'></a><a href='#L2269'>2269</a>
- <a name='L2270'></a><a href='#L2270'>2270</a>
- <a name='L2271'></a><a href='#L2271'>2271</a>
- <a name='L2272'></a><a href='#L2272'>2272</a>
- <a name='L2273'></a><a href='#L2273'>2273</a>
- <a name='L2274'></a><a href='#L2274'>2274</a>
- <a name='L2275'></a><a href='#L2275'>2275</a>
- <a name='L2276'></a><a href='#L2276'>2276</a>
- <a name='L2277'></a><a href='#L2277'>2277</a>
- <a name='L2278'></a><a href='#L2278'>2278</a>
- <a name='L2279'></a><a href='#L2279'>2279</a>
- <a name='L2280'></a><a href='#L2280'>2280</a>
- <a name='L2281'></a><a href='#L2281'>2281</a>
- <a name='L2282'></a><a href='#L2282'>2282</a>
- <a name='L2283'></a><a href='#L2283'>2283</a>
- <a name='L2284'></a><a href='#L2284'>2284</a>
- <a name='L2285'></a><a href='#L2285'>2285</a>
- <a name='L2286'></a><a href='#L2286'>2286</a>
- <a name='L2287'></a><a href='#L2287'>2287</a>
- <a name='L2288'></a><a href='#L2288'>2288</a>
- <a name='L2289'></a><a href='#L2289'>2289</a>
- <a name='L2290'></a><a href='#L2290'>2290</a>
- <a name='L2291'></a><a href='#L2291'>2291</a>
- <a name='L2292'></a><a href='#L2292'>2292</a>
- <a name='L2293'></a><a href='#L2293'>2293</a>
- <a name='L2294'></a><a href='#L2294'>2294</a>
- <a name='L2295'></a><a href='#L2295'>2295</a>
- <a name='L2296'></a><a href='#L2296'>2296</a>
- <a name='L2297'></a><a href='#L2297'>2297</a>
- <a name='L2298'></a><a href='#L2298'>2298</a>
- <a name='L2299'></a><a href='#L2299'>2299</a>
- <a name='L2300'></a><a href='#L2300'>2300</a>
- <a name='L2301'></a><a href='#L2301'>2301</a>
- <a name='L2302'></a><a href='#L2302'>2302</a>
- <a name='L2303'></a><a href='#L2303'>2303</a>
- <a name='L2304'></a><a href='#L2304'>2304</a>
- <a name='L2305'></a><a href='#L2305'>2305</a>
- <a name='L2306'></a><a href='#L2306'>2306</a>
- <a name='L2307'></a><a href='#L2307'>2307</a>
- <a name='L2308'></a><a href='#L2308'>2308</a>
- <a name='L2309'></a><a href='#L2309'>2309</a>
- <a name='L2310'></a><a href='#L2310'>2310</a>
- <a name='L2311'></a><a href='#L2311'>2311</a>
- <a name='L2312'></a><a href='#L2312'>2312</a>
- <a name='L2313'></a><a href='#L2313'>2313</a>
- <a name='L2314'></a><a href='#L2314'>2314</a>
- <a name='L2315'></a><a href='#L2315'>2315</a>
- <a name='L2316'></a><a href='#L2316'>2316</a>
- <a name='L2317'></a><a href='#L2317'>2317</a>
- <a name='L2318'></a><a href='#L2318'>2318</a>
- <a name='L2319'></a><a href='#L2319'>2319</a>
- <a name='L2320'></a><a href='#L2320'>2320</a>
- <a name='L2321'></a><a href='#L2321'>2321</a>
- <a name='L2322'></a><a href='#L2322'>2322</a>
- <a name='L2323'></a><a href='#L2323'>2323</a>
- <a name='L2324'></a><a href='#L2324'>2324</a>
- <a name='L2325'></a><a href='#L2325'>2325</a>
- <a name='L2326'></a><a href='#L2326'>2326</a>
- <a name='L2327'></a><a href='#L2327'>2327</a>
- <a name='L2328'></a><a href='#L2328'>2328</a>
- <a name='L2329'></a><a href='#L2329'>2329</a>
- <a name='L2330'></a><a href='#L2330'>2330</a>
- <a name='L2331'></a><a href='#L2331'>2331</a>
- <a name='L2332'></a><a href='#L2332'>2332</a>
- <a name='L2333'></a><a href='#L2333'>2333</a>
- <a name='L2334'></a><a href='#L2334'>2334</a>
- <a name='L2335'></a><a href='#L2335'>2335</a>
- <a name='L2336'></a><a href='#L2336'>2336</a>
- <a name='L2337'></a><a href='#L2337'>2337</a>
- <a name='L2338'></a><a href='#L2338'>2338</a>
- <a name='L2339'></a><a href='#L2339'>2339</a>
- <a name='L2340'></a><a href='#L2340'>2340</a>
- <a name='L2341'></a><a href='#L2341'>2341</a>
- <a name='L2342'></a><a href='#L2342'>2342</a>
- <a name='L2343'></a><a href='#L2343'>2343</a>
- <a name='L2344'></a><a href='#L2344'>2344</a>
- <a name='L2345'></a><a href='#L2345'>2345</a>
- <a name='L2346'></a><a href='#L2346'>2346</a>
- <a name='L2347'></a><a href='#L2347'>2347</a>
- <a name='L2348'></a><a href='#L2348'>2348</a>
- <a name='L2349'></a><a href='#L2349'>2349</a>
- <a name='L2350'></a><a href='#L2350'>2350</a>
- <a name='L2351'></a><a href='#L2351'>2351</a>
- <a name='L2352'></a><a href='#L2352'>2352</a>
- <a name='L2353'></a><a href='#L2353'>2353</a>
- <a name='L2354'></a><a href='#L2354'>2354</a>
- <a name='L2355'></a><a href='#L2355'>2355</a>
- <a name='L2356'></a><a href='#L2356'>2356</a>
- <a name='L2357'></a><a href='#L2357'>2357</a>
- <a name='L2358'></a><a href='#L2358'>2358</a>
- <a name='L2359'></a><a href='#L2359'>2359</a>
- <a name='L2360'></a><a href='#L2360'>2360</a>
- <a name='L2361'></a><a href='#L2361'>2361</a>
- <a name='L2362'></a><a href='#L2362'>2362</a>
- <a name='L2363'></a><a href='#L2363'>2363</a>
- <a name='L2364'></a><a href='#L2364'>2364</a>
- <a name='L2365'></a><a href='#L2365'>2365</a>
- <a name='L2366'></a><a href='#L2366'>2366</a>
- <a name='L2367'></a><a href='#L2367'>2367</a>
- <a name='L2368'></a><a href='#L2368'>2368</a>
- <a name='L2369'></a><a href='#L2369'>2369</a>
- <a name='L2370'></a><a href='#L2370'>2370</a>
- <a name='L2371'></a><a href='#L2371'>2371</a>
- <a name='L2372'></a><a href='#L2372'>2372</a>
- <a name='L2373'></a><a href='#L2373'>2373</a>
- <a name='L2374'></a><a href='#L2374'>2374</a>
- <a name='L2375'></a><a href='#L2375'>2375</a>
- <a name='L2376'></a><a href='#L2376'>2376</a>
- <a name='L2377'></a><a href='#L2377'>2377</a>
- <a name='L2378'></a><a href='#L2378'>2378</a>
- <a name='L2379'></a><a href='#L2379'>2379</a>
- <a name='L2380'></a><a href='#L2380'>2380</a>
- <a name='L2381'></a><a href='#L2381'>2381</a>
- <a name='L2382'></a><a href='#L2382'>2382</a>
- <a name='L2383'></a><a href='#L2383'>2383</a>
- <a name='L2384'></a><a href='#L2384'>2384</a>
- <a name='L2385'></a><a href='#L2385'>2385</a>
- <a name='L2386'></a><a href='#L2386'>2386</a>
- <a name='L2387'></a><a href='#L2387'>2387</a>
- <a name='L2388'></a><a href='#L2388'>2388</a>
- <a name='L2389'></a><a href='#L2389'>2389</a>
- <a name='L2390'></a><a href='#L2390'>2390</a>
- <a name='L2391'></a><a href='#L2391'>2391</a>
- <a name='L2392'></a><a href='#L2392'>2392</a>
- <a name='L2393'></a><a href='#L2393'>2393</a>
- <a name='L2394'></a><a href='#L2394'>2394</a>
- <a name='L2395'></a><a href='#L2395'>2395</a>
- <a name='L2396'></a><a href='#L2396'>2396</a>
- <a name='L2397'></a><a href='#L2397'>2397</a>
- <a name='L2398'></a><a href='#L2398'>2398</a>
- <a name='L2399'></a><a href='#L2399'>2399</a>
- <a name='L2400'></a><a href='#L2400'>2400</a>
- <a name='L2401'></a><a href='#L2401'>2401</a>
- <a name='L2402'></a><a href='#L2402'>2402</a>
- <a name='L2403'></a><a href='#L2403'>2403</a>
- <a name='L2404'></a><a href='#L2404'>2404</a>
- <a name='L2405'></a><a href='#L2405'>2405</a>
- <a name='L2406'></a><a href='#L2406'>2406</a>
- <a name='L2407'></a><a href='#L2407'>2407</a>
- <a name='L2408'></a><a href='#L2408'>2408</a>
- <a name='L2409'></a><a href='#L2409'>2409</a>
- <a name='L2410'></a><a href='#L2410'>2410</a>
- <a name='L2411'></a><a href='#L2411'>2411</a>
- <a name='L2412'></a><a href='#L2412'>2412</a>
- <a name='L2413'></a><a href='#L2413'>2413</a>
- <a name='L2414'></a><a href='#L2414'>2414</a>
- <a name='L2415'></a><a href='#L2415'>2415</a>
- <a name='L2416'></a><a href='#L2416'>2416</a>
- <a name='L2417'></a><a href='#L2417'>2417</a>
- <a name='L2418'></a><a href='#L2418'>2418</a>
- <a name='L2419'></a><a href='#L2419'>2419</a>
- <a name='L2420'></a><a href='#L2420'>2420</a>
- <a name='L2421'></a><a href='#L2421'>2421</a>
- <a name='L2422'></a><a href='#L2422'>2422</a>
- <a name='L2423'></a><a href='#L2423'>2423</a>
- <a name='L2424'></a><a href='#L2424'>2424</a>
- <a name='L2425'></a><a href='#L2425'>2425</a>
- <a name='L2426'></a><a href='#L2426'>2426</a>
- <a name='L2427'></a><a href='#L2427'>2427</a>
- <a name='L2428'></a><a href='#L2428'>2428</a>
- <a name='L2429'></a><a href='#L2429'>2429</a>
- <a name='L2430'></a><a href='#L2430'>2430</a>
- <a name='L2431'></a><a href='#L2431'>2431</a>
- <a name='L2432'></a><a href='#L2432'>2432</a>
- <a name='L2433'></a><a href='#L2433'>2433</a>
- <a name='L2434'></a><a href='#L2434'>2434</a>
- <a name='L2435'></a><a href='#L2435'>2435</a>
- <a name='L2436'></a><a href='#L2436'>2436</a>
- <a name='L2437'></a><a href='#L2437'>2437</a>
- <a name='L2438'></a><a href='#L2438'>2438</a>
- <a name='L2439'></a><a href='#L2439'>2439</a>
- <a name='L2440'></a><a href='#L2440'>2440</a>
- <a name='L2441'></a><a href='#L2441'>2441</a>
- <a name='L2442'></a><a href='#L2442'>2442</a>
- <a name='L2443'></a><a href='#L2443'>2443</a>
- <a name='L2444'></a><a href='#L2444'>2444</a>
- <a name='L2445'></a><a href='#L2445'>2445</a>
- <a name='L2446'></a><a href='#L2446'>2446</a>
- <a name='L2447'></a><a href='#L2447'>2447</a>
- <a name='L2448'></a><a href='#L2448'>2448</a>
- <a name='L2449'></a><a href='#L2449'>2449</a>
- <a name='L2450'></a><a href='#L2450'>2450</a>
- <a name='L2451'></a><a href='#L2451'>2451</a>
- <a name='L2452'></a><a href='#L2452'>2452</a>
- <a name='L2453'></a><a href='#L2453'>2453</a>
- <a name='L2454'></a><a href='#L2454'>2454</a>
- <a name='L2455'></a><a href='#L2455'>2455</a>
- <a name='L2456'></a><a href='#L2456'>2456</a>
- <a name='L2457'></a><a href='#L2457'>2457</a>
- <a name='L2458'></a><a href='#L2458'>2458</a>
- <a name='L2459'></a><a href='#L2459'>2459</a>
- <a name='L2460'></a><a href='#L2460'>2460</a>
- <a name='L2461'></a><a href='#L2461'>2461</a>
- <a name='L2462'></a><a href='#L2462'>2462</a>
- <a name='L2463'></a><a href='#L2463'>2463</a>
- <a name='L2464'></a><a href='#L2464'>2464</a>
- <a name='L2465'></a><a href='#L2465'>2465</a>
- <a name='L2466'></a><a href='#L2466'>2466</a>
- <a name='L2467'></a><a href='#L2467'>2467</a>
- <a name='L2468'></a><a href='#L2468'>2468</a>
- <a name='L2469'></a><a href='#L2469'>2469</a>
- <a name='L2470'></a><a href='#L2470'>2470</a>
- <a name='L2471'></a><a href='#L2471'>2471</a>
- <a name='L2472'></a><a href='#L2472'>2472</a>
- <a name='L2473'></a><a href='#L2473'>2473</a>
- <a name='L2474'></a><a href='#L2474'>2474</a>
- <a name='L2475'></a><a href='#L2475'>2475</a>
- <a name='L2476'></a><a href='#L2476'>2476</a>
- <a name='L2477'></a><a href='#L2477'>2477</a>
- <a name='L2478'></a><a href='#L2478'>2478</a>
- <a name='L2479'></a><a href='#L2479'>2479</a>
- <a name='L2480'></a><a href='#L2480'>2480</a>
- <a name='L2481'></a><a href='#L2481'>2481</a>
- <a name='L2482'></a><a href='#L2482'>2482</a>
- <a name='L2483'></a><a href='#L2483'>2483</a>
- <a name='L2484'></a><a href='#L2484'>2484</a>
- <a name='L2485'></a><a href='#L2485'>2485</a>
- <a name='L2486'></a><a href='#L2486'>2486</a>
- <a name='L2487'></a><a href='#L2487'>2487</a>
- <a name='L2488'></a><a href='#L2488'>2488</a>
- <a name='L2489'></a><a href='#L2489'>2489</a>
- <a name='L2490'></a><a href='#L2490'>2490</a>
- <a name='L2491'></a><a href='#L2491'>2491</a>
- <a name='L2492'></a><a href='#L2492'>2492</a>
- <a name='L2493'></a><a href='#L2493'>2493</a>
- <a name='L2494'></a><a href='#L2494'>2494</a>
- <a name='L2495'></a><a href='#L2495'>2495</a>
- <a name='L2496'></a><a href='#L2496'>2496</a>
- <a name='L2497'></a><a href='#L2497'>2497</a>
- <a name='L2498'></a><a href='#L2498'>2498</a>
- <a name='L2499'></a><a href='#L2499'>2499</a>
- <a name='L2500'></a><a href='#L2500'>2500</a>
- <a name='L2501'></a><a href='#L2501'>2501</a>
- <a name='L2502'></a><a href='#L2502'>2502</a>
- <a name='L2503'></a><a href='#L2503'>2503</a>
- <a name='L2504'></a><a href='#L2504'>2504</a>
- <a name='L2505'></a><a href='#L2505'>2505</a>
- <a name='L2506'></a><a href='#L2506'>2506</a>
- <a name='L2507'></a><a href='#L2507'>2507</a>
- <a name='L2508'></a><a href='#L2508'>2508</a>
- <a name='L2509'></a><a href='#L2509'>2509</a>
- <a name='L2510'></a><a href='#L2510'>2510</a>
- <a name='L2511'></a><a href='#L2511'>2511</a>
- <a name='L2512'></a><a href='#L2512'>2512</a>
- <a name='L2513'></a><a href='#L2513'>2513</a>
- <a name='L2514'></a><a href='#L2514'>2514</a>
- <a name='L2515'></a><a href='#L2515'>2515</a>
- <a name='L2516'></a><a href='#L2516'>2516</a>
- <a name='L2517'></a><a href='#L2517'>2517</a>
- <a name='L2518'></a><a href='#L2518'>2518</a>
- <a name='L2519'></a><a href='#L2519'>2519</a>
- <a name='L2520'></a><a href='#L2520'>2520</a>
- <a name='L2521'></a><a href='#L2521'>2521</a>
- <a name='L2522'></a><a href='#L2522'>2522</a>
- <a name='L2523'></a><a href='#L2523'>2523</a>
- <a name='L2524'></a><a href='#L2524'>2524</a>
- <a name='L2525'></a><a href='#L2525'>2525</a>
- <a name='L2526'></a><a href='#L2526'>2526</a>
- <a name='L2527'></a><a href='#L2527'>2527</a>
- <a name='L2528'></a><a href='#L2528'>2528</a>
- <a name='L2529'></a><a href='#L2529'>2529</a>
- <a name='L2530'></a><a href='#L2530'>2530</a>
- <a name='L2531'></a><a href='#L2531'>2531</a>
- <a name='L2532'></a><a href='#L2532'>2532</a>
- <a name='L2533'></a><a href='#L2533'>2533</a>
- <a name='L2534'></a><a href='#L2534'>2534</a>
- <a name='L2535'></a><a href='#L2535'>2535</a>
- <a name='L2536'></a><a href='#L2536'>2536</a>
- <a name='L2537'></a><a href='#L2537'>2537</a>
- <a name='L2538'></a><a href='#L2538'>2538</a>
- <a name='L2539'></a><a href='#L2539'>2539</a>
- <a name='L2540'></a><a href='#L2540'>2540</a>
- <a name='L2541'></a><a href='#L2541'>2541</a>
- <a name='L2542'></a><a href='#L2542'>2542</a>
- <a name='L2543'></a><a href='#L2543'>2543</a>
- <a name='L2544'></a><a href='#L2544'>2544</a>
- <a name='L2545'></a><a href='#L2545'>2545</a>
- <a name='L2546'></a><a href='#L2546'>2546</a>
- <a name='L2547'></a><a href='#L2547'>2547</a>
- <a name='L2548'></a><a href='#L2548'>2548</a>
- <a name='L2549'></a><a href='#L2549'>2549</a>
- <a name='L2550'></a><a href='#L2550'>2550</a>
- <a name='L2551'></a><a href='#L2551'>2551</a>
- <a name='L2552'></a><a href='#L2552'>2552</a>
- <a name='L2553'></a><a href='#L2553'>2553</a>
- <a name='L2554'></a><a href='#L2554'>2554</a>
- <a name='L2555'></a><a href='#L2555'>2555</a>
- <a name='L2556'></a><a href='#L2556'>2556</a>
- <a name='L2557'></a><a href='#L2557'>2557</a>
- <a name='L2558'></a><a href='#L2558'>2558</a>
- <a name='L2559'></a><a href='#L2559'>2559</a>
- <a name='L2560'></a><a href='#L2560'>2560</a>
- <a name='L2561'></a><a href='#L2561'>2561</a>
- <a name='L2562'></a><a href='#L2562'>2562</a>
- <a name='L2563'></a><a href='#L2563'>2563</a>
- <a name='L2564'></a><a href='#L2564'>2564</a>
- <a name='L2565'></a><a href='#L2565'>2565</a>
- <a name='L2566'></a><a href='#L2566'>2566</a>
- <a name='L2567'></a><a href='#L2567'>2567</a>
- <a name='L2568'></a><a href='#L2568'>2568</a>
- <a name='L2569'></a><a href='#L2569'>2569</a>
- <a name='L2570'></a><a href='#L2570'>2570</a>
- <a name='L2571'></a><a href='#L2571'>2571</a>
- <a name='L2572'></a><a href='#L2572'>2572</a>
- <a name='L2573'></a><a href='#L2573'>2573</a>
- <a name='L2574'></a><a href='#L2574'>2574</a>
- <a name='L2575'></a><a href='#L2575'>2575</a>
- <a name='L2576'></a><a href='#L2576'>2576</a>
- <a name='L2577'></a><a href='#L2577'>2577</a>
- <a name='L2578'></a><a href='#L2578'>2578</a>
- <a name='L2579'></a><a href='#L2579'>2579</a>
- <a name='L2580'></a><a href='#L2580'>2580</a>
- <a name='L2581'></a><a href='#L2581'>2581</a>
- <a name='L2582'></a><a href='#L2582'>2582</a>
- <a name='L2583'></a><a href='#L2583'>2583</a>
- <a name='L2584'></a><a href='#L2584'>2584</a>
- <a name='L2585'></a><a href='#L2585'>2585</a>
- <a name='L2586'></a><a href='#L2586'>2586</a>
- <a name='L2587'></a><a href='#L2587'>2587</a>
- <a name='L2588'></a><a href='#L2588'>2588</a>
- <a name='L2589'></a><a href='#L2589'>2589</a>
- <a name='L2590'></a><a href='#L2590'>2590</a>
- <a name='L2591'></a><a href='#L2591'>2591</a>
- <a name='L2592'></a><a href='#L2592'>2592</a>
- <a name='L2593'></a><a href='#L2593'>2593</a>
- <a name='L2594'></a><a href='#L2594'>2594</a>
- <a name='L2595'></a><a href='#L2595'>2595</a>
- <a name='L2596'></a><a href='#L2596'>2596</a>
- <a name='L2597'></a><a href='#L2597'>2597</a>
- <a name='L2598'></a><a href='#L2598'>2598</a>
- <a name='L2599'></a><a href='#L2599'>2599</a>
- <a name='L2600'></a><a href='#L2600'>2600</a>
- <a name='L2601'></a><a href='#L2601'>2601</a>
- <a name='L2602'></a><a href='#L2602'>2602</a>
- <a name='L2603'></a><a href='#L2603'>2603</a>
- <a name='L2604'></a><a href='#L2604'>2604</a>
- <a name='L2605'></a><a href='#L2605'>2605</a>
- <a name='L2606'></a><a href='#L2606'>2606</a>
- <a name='L2607'></a><a href='#L2607'>2607</a>
- <a name='L2608'></a><a href='#L2608'>2608</a>
- <a name='L2609'></a><a href='#L2609'>2609</a>
- <a name='L2610'></a><a href='#L2610'>2610</a>
- <a name='L2611'></a><a href='#L2611'>2611</a>
- <a name='L2612'></a><a href='#L2612'>2612</a>
- <a name='L2613'></a><a href='#L2613'>2613</a>
- <a name='L2614'></a><a href='#L2614'>2614</a>
- <a name='L2615'></a><a href='#L2615'>2615</a>
- <a name='L2616'></a><a href='#L2616'>2616</a>
- <a name='L2617'></a><a href='#L2617'>2617</a>
- <a name='L2618'></a><a href='#L2618'>2618</a>
- <a name='L2619'></a><a href='#L2619'>2619</a>
- <a name='L2620'></a><a href='#L2620'>2620</a>
- <a name='L2621'></a><a href='#L2621'>2621</a>
- <a name='L2622'></a><a href='#L2622'>2622</a>
- <a name='L2623'></a><a href='#L2623'>2623</a>
- <a name='L2624'></a><a href='#L2624'>2624</a>
- <a name='L2625'></a><a href='#L2625'>2625</a>
- <a name='L2626'></a><a href='#L2626'>2626</a>
- <a name='L2627'></a><a href='#L2627'>2627</a>
- <a name='L2628'></a><a href='#L2628'>2628</a>
- <a name='L2629'></a><a href='#L2629'>2629</a>
- <a name='L2630'></a><a href='#L2630'>2630</a>
- <a name='L2631'></a><a href='#L2631'>2631</a>
- <a name='L2632'></a><a href='#L2632'>2632</a>
- <a name='L2633'></a><a href='#L2633'>2633</a>
- <a name='L2634'></a><a href='#L2634'>2634</a>
- <a name='L2635'></a><a href='#L2635'>2635</a>
- <a name='L2636'></a><a href='#L2636'>2636</a>
- <a name='L2637'></a><a href='#L2637'>2637</a>
- <a name='L2638'></a><a href='#L2638'>2638</a>
- <a name='L2639'></a><a href='#L2639'>2639</a>
- <a name='L2640'></a><a href='#L2640'>2640</a>
- <a name='L2641'></a><a href='#L2641'>2641</a>
- <a name='L2642'></a><a href='#L2642'>2642</a>
- <a name='L2643'></a><a href='#L2643'>2643</a>
- <a name='L2644'></a><a href='#L2644'>2644</a>
- <a name='L2645'></a><a href='#L2645'>2645</a>
- <a name='L2646'></a><a href='#L2646'>2646</a>
- <a name='L2647'></a><a href='#L2647'>2647</a>
- <a name='L2648'></a><a href='#L2648'>2648</a>
- <a name='L2649'></a><a href='#L2649'>2649</a>
- <a name='L2650'></a><a href='#L2650'>2650</a>
- <a name='L2651'></a><a href='#L2651'>2651</a>
- <a name='L2652'></a><a href='#L2652'>2652</a>
- <a name='L2653'></a><a href='#L2653'>2653</a>
- <a name='L2654'></a><a href='#L2654'>2654</a>
- <a name='L2655'></a><a href='#L2655'>2655</a>
- <a name='L2656'></a><a href='#L2656'>2656</a>
- <a name='L2657'></a><a href='#L2657'>2657</a>
- <a name='L2658'></a><a href='#L2658'>2658</a>
- <a name='L2659'></a><a href='#L2659'>2659</a>
- <a name='L2660'></a><a href='#L2660'>2660</a>
- <a name='L2661'></a><a href='#L2661'>2661</a>
- <a name='L2662'></a><a href='#L2662'>2662</a>
- <a name='L2663'></a><a href='#L2663'>2663</a>
- <a name='L2664'></a><a href='#L2664'>2664</a>
- <a name='L2665'></a><a href='#L2665'>2665</a>
- <a name='L2666'></a><a href='#L2666'>2666</a>
- <a name='L2667'></a><a href='#L2667'>2667</a>
- <a name='L2668'></a><a href='#L2668'>2668</a>
- <a name='L2669'></a><a href='#L2669'>2669</a>
- <a name='L2670'></a><a href='#L2670'>2670</a>
- <a name='L2671'></a><a href='#L2671'>2671</a>
- <a name='L2672'></a><a href='#L2672'>2672</a>
- <a name='L2673'></a><a href='#L2673'>2673</a>
- <a name='L2674'></a><a href='#L2674'>2674</a>
- <a name='L2675'></a><a href='#L2675'>2675</a>
- <a name='L2676'></a><a href='#L2676'>2676</a>
- <a name='L2677'></a><a href='#L2677'>2677</a>
- <a name='L2678'></a><a href='#L2678'>2678</a>
- <a name='L2679'></a><a href='#L2679'>2679</a>
- <a name='L2680'></a><a href='#L2680'>2680</a>
- <a name='L2681'></a><a href='#L2681'>2681</a>
- <a name='L2682'></a><a href='#L2682'>2682</a>
- <a name='L2683'></a><a href='#L2683'>2683</a>
- <a name='L2684'></a><a href='#L2684'>2684</a>
- <a name='L2685'></a><a href='#L2685'>2685</a>
- <a name='L2686'></a><a href='#L2686'>2686</a>
- <a name='L2687'></a><a href='#L2687'>2687</a>
- <a name='L2688'></a><a href='#L2688'>2688</a>
- <a name='L2689'></a><a href='#L2689'>2689</a>
- <a name='L2690'></a><a href='#L2690'>2690</a>
- <a name='L2691'></a><a href='#L2691'>2691</a>
- <a name='L2692'></a><a href='#L2692'>2692</a>
- <a name='L2693'></a><a href='#L2693'>2693</a>
- <a name='L2694'></a><a href='#L2694'>2694</a>
- <a name='L2695'></a><a href='#L2695'>2695</a>
- <a name='L2696'></a><a href='#L2696'>2696</a>
- <a name='L2697'></a><a href='#L2697'>2697</a>
- <a name='L2698'></a><a href='#L2698'>2698</a>
- <a name='L2699'></a><a href='#L2699'>2699</a>
- <a name='L2700'></a><a href='#L2700'>2700</a>
- <a name='L2701'></a><a href='#L2701'>2701</a>
- <a name='L2702'></a><a href='#L2702'>2702</a>
- <a name='L2703'></a><a href='#L2703'>2703</a>
- <a name='L2704'></a><a href='#L2704'>2704</a>
- <a name='L2705'></a><a href='#L2705'>2705</a>
- <a name='L2706'></a><a href='#L2706'>2706</a>
- <a name='L2707'></a><a href='#L2707'>2707</a>
- <a name='L2708'></a><a href='#L2708'>2708</a>
- <a name='L2709'></a><a href='#L2709'>2709</a>
- <a name='L2710'></a><a href='#L2710'>2710</a>
- <a name='L2711'></a><a href='#L2711'>2711</a>
- <a name='L2712'></a><a href='#L2712'>2712</a>
- <a name='L2713'></a><a href='#L2713'>2713</a>
- <a name='L2714'></a><a href='#L2714'>2714</a>
- <a name='L2715'></a><a href='#L2715'>2715</a>
- <a name='L2716'></a><a href='#L2716'>2716</a>
- <a name='L2717'></a><a href='#L2717'>2717</a>
- <a name='L2718'></a><a href='#L2718'>2718</a>
- <a name='L2719'></a><a href='#L2719'>2719</a>
- <a name='L2720'></a><a href='#L2720'>2720</a>
- <a name='L2721'></a><a href='#L2721'>2721</a>
- <a name='L2722'></a><a href='#L2722'>2722</a>
- <a name='L2723'></a><a href='#L2723'>2723</a>
- <a name='L2724'></a><a href='#L2724'>2724</a>
- <a name='L2725'></a><a href='#L2725'>2725</a>
- <a name='L2726'></a><a href='#L2726'>2726</a>
- <a name='L2727'></a><a href='#L2727'>2727</a>
- <a name='L2728'></a><a href='#L2728'>2728</a>
- <a name='L2729'></a><a href='#L2729'>2729</a>
- <a name='L2730'></a><a href='#L2730'>2730</a>
- <a name='L2731'></a><a href='#L2731'>2731</a>
- <a name='L2732'></a><a href='#L2732'>2732</a>
- <a name='L2733'></a><a href='#L2733'>2733</a>
- <a name='L2734'></a><a href='#L2734'>2734</a>
- <a name='L2735'></a><a href='#L2735'>2735</a>
- <a name='L2736'></a><a href='#L2736'>2736</a>
- <a name='L2737'></a><a href='#L2737'>2737</a>
- <a name='L2738'></a><a href='#L2738'>2738</a>
- <a name='L2739'></a><a href='#L2739'>2739</a>
- <a name='L2740'></a><a href='#L2740'>2740</a>
- <a name='L2741'></a><a href='#L2741'>2741</a>
- <a name='L2742'></a><a href='#L2742'>2742</a>
- <a name='L2743'></a><a href='#L2743'>2743</a>
- <a name='L2744'></a><a href='#L2744'>2744</a>
- <a name='L2745'></a><a href='#L2745'>2745</a>
- <a name='L2746'></a><a href='#L2746'>2746</a>
- <a name='L2747'></a><a href='#L2747'>2747</a>
- <a name='L2748'></a><a href='#L2748'>2748</a>
- <a name='L2749'></a><a href='#L2749'>2749</a>
- <a name='L2750'></a><a href='#L2750'>2750</a>
- <a name='L2751'></a><a href='#L2751'>2751</a>
- <a name='L2752'></a><a href='#L2752'>2752</a>
- <a name='L2753'></a><a href='#L2753'>2753</a>
- <a name='L2754'></a><a href='#L2754'>2754</a>
- <a name='L2755'></a><a href='#L2755'>2755</a>
- <a name='L2756'></a><a href='#L2756'>2756</a>
- <a name='L2757'></a><a href='#L2757'>2757</a>
- <a name='L2758'></a><a href='#L2758'>2758</a>
- <a name='L2759'></a><a href='#L2759'>2759</a>
- <a name='L2760'></a><a href='#L2760'>2760</a>
- <a name='L2761'></a><a href='#L2761'>2761</a>
- <a name='L2762'></a><a href='#L2762'>2762</a>
- <a name='L2763'></a><a href='#L2763'>2763</a>
- <a name='L2764'></a><a href='#L2764'>2764</a>
- <a name='L2765'></a><a href='#L2765'>2765</a>
- <a name='L2766'></a><a href='#L2766'>2766</a>
- <a name='L2767'></a><a href='#L2767'>2767</a>
- <a name='L2768'></a><a href='#L2768'>2768</a>
- <a name='L2769'></a><a href='#L2769'>2769</a>
- <a name='L2770'></a><a href='#L2770'>2770</a>
- <a name='L2771'></a><a href='#L2771'>2771</a>
- <a name='L2772'></a><a href='#L2772'>2772</a>
- <a name='L2773'></a><a href='#L2773'>2773</a>
- <a name='L2774'></a><a href='#L2774'>2774</a>
- <a name='L2775'></a><a href='#L2775'>2775</a>
- <a name='L2776'></a><a href='#L2776'>2776</a>
- <a name='L2777'></a><a href='#L2777'>2777</a>
- <a name='L2778'></a><a href='#L2778'>2778</a>
- <a name='L2779'></a><a href='#L2779'>2779</a>
- <a name='L2780'></a><a href='#L2780'>2780</a>
- <a name='L2781'></a><a href='#L2781'>2781</a>
- <a name='L2782'></a><a href='#L2782'>2782</a>
- <a name='L2783'></a><a href='#L2783'>2783</a>
- <a name='L2784'></a><a href='#L2784'>2784</a>
- <a name='L2785'></a><a href='#L2785'>2785</a>
- <a name='L2786'></a><a href='#L2786'>2786</a>
- <a name='L2787'></a><a href='#L2787'>2787</a>
- <a name='L2788'></a><a href='#L2788'>2788</a>
- <a name='L2789'></a><a href='#L2789'>2789</a>
- <a name='L2790'></a><a href='#L2790'>2790</a>
- <a name='L2791'></a><a href='#L2791'>2791</a>
- <a name='L2792'></a><a href='#L2792'>2792</a>
- <a name='L2793'></a><a href='#L2793'>2793</a>
- <a name='L2794'></a><a href='#L2794'>2794</a>
- <a name='L2795'></a><a href='#L2795'>2795</a>
- <a name='L2796'></a><a href='#L2796'>2796</a>
- <a name='L2797'></a><a href='#L2797'>2797</a>
- <a name='L2798'></a><a href='#L2798'>2798</a>
- <a name='L2799'></a><a href='#L2799'>2799</a>
- <a name='L2800'></a><a href='#L2800'>2800</a>
- <a name='L2801'></a><a href='#L2801'>2801</a>
- <a name='L2802'></a><a href='#L2802'>2802</a>
- <a name='L2803'></a><a href='#L2803'>2803</a>
- <a name='L2804'></a><a href='#L2804'>2804</a>
- <a name='L2805'></a><a href='#L2805'>2805</a>
- <a name='L2806'></a><a href='#L2806'>2806</a>
- <a name='L2807'></a><a href='#L2807'>2807</a>
- <a name='L2808'></a><a href='#L2808'>2808</a>
- <a name='L2809'></a><a href='#L2809'>2809</a>
- <a name='L2810'></a><a href='#L2810'>2810</a>
- <a name='L2811'></a><a href='#L2811'>2811</a>
- <a name='L2812'></a><a href='#L2812'>2812</a>
- <a name='L2813'></a><a href='#L2813'>2813</a>
- <a name='L2814'></a><a href='#L2814'>2814</a>
- <a name='L2815'></a><a href='#L2815'>2815</a>
- <a name='L2816'></a><a href='#L2816'>2816</a>
- <a name='L2817'></a><a href='#L2817'>2817</a>
- <a name='L2818'></a><a href='#L2818'>2818</a>
- <a name='L2819'></a><a href='#L2819'>2819</a>
- <a name='L2820'></a><a href='#L2820'>2820</a>
- <a name='L2821'></a><a href='#L2821'>2821</a>
- <a name='L2822'></a><a href='#L2822'>2822</a>
- <a name='L2823'></a><a href='#L2823'>2823</a>
- <a name='L2824'></a><a href='#L2824'>2824</a>
- <a name='L2825'></a><a href='#L2825'>2825</a>
- <a name='L2826'></a><a href='#L2826'>2826</a>
- <a name='L2827'></a><a href='#L2827'>2827</a>
- <a name='L2828'></a><a href='#L2828'>2828</a>
- <a name='L2829'></a><a href='#L2829'>2829</a>
- <a name='L2830'></a><a href='#L2830'>2830</a>
- <a name='L2831'></a><a href='#L2831'>2831</a>
- <a name='L2832'></a><a href='#L2832'>2832</a>
- <a name='L2833'></a><a href='#L2833'>2833</a>
- <a name='L2834'></a><a href='#L2834'>2834</a>
- <a name='L2835'></a><a href='#L2835'>2835</a>
- <a name='L2836'></a><a href='#L2836'>2836</a>
- <a name='L2837'></a><a href='#L2837'>2837</a>
- <a name='L2838'></a><a href='#L2838'>2838</a>
- <a name='L2839'></a><a href='#L2839'>2839</a>
- <a name='L2840'></a><a href='#L2840'>2840</a>
- <a name='L2841'></a><a href='#L2841'>2841</a>
- <a name='L2842'></a><a href='#L2842'>2842</a>
- <a name='L2843'></a><a href='#L2843'>2843</a>
- <a name='L2844'></a><a href='#L2844'>2844</a>
- <a name='L2845'></a><a href='#L2845'>2845</a>
- <a name='L2846'></a><a href='#L2846'>2846</a>
- <a name='L2847'></a><a href='#L2847'>2847</a>
- <a name='L2848'></a><a href='#L2848'>2848</a>
- <a name='L2849'></a><a href='#L2849'>2849</a>
- <a name='L2850'></a><a href='#L2850'>2850</a>
- <a name='L2851'></a><a href='#L2851'>2851</a>
- <a name='L2852'></a><a href='#L2852'>2852</a>
- <a name='L2853'></a><a href='#L2853'>2853</a>
- <a name='L2854'></a><a href='#L2854'>2854</a>
- <a name='L2855'></a><a href='#L2855'>2855</a>
- <a name='L2856'></a><a href='#L2856'>2856</a>
- <a name='L2857'></a><a href='#L2857'>2857</a>
- <a name='L2858'></a><a href='#L2858'>2858</a>
- <a name='L2859'></a><a href='#L2859'>2859</a>
- <a name='L2860'></a><a href='#L2860'>2860</a>
- <a name='L2861'></a><a href='#L2861'>2861</a>
- <a name='L2862'></a><a href='#L2862'>2862</a>
- <a name='L2863'></a><a href='#L2863'>2863</a>
- <a name='L2864'></a><a href='#L2864'>2864</a>
- <a name='L2865'></a><a href='#L2865'>2865</a>
- <a name='L2866'></a><a href='#L2866'>2866</a>
- <a name='L2867'></a><a href='#L2867'>2867</a>
- <a name='L2868'></a><a href='#L2868'>2868</a>
- <a name='L2869'></a><a href='#L2869'>2869</a>
- <a name='L2870'></a><a href='#L2870'>2870</a>
- <a name='L2871'></a><a href='#L2871'>2871</a>
- <a name='L2872'></a><a href='#L2872'>2872</a>
- <a name='L2873'></a><a href='#L2873'>2873</a>
- <a name='L2874'></a><a href='#L2874'>2874</a>
- <a name='L2875'></a><a href='#L2875'>2875</a>
- <a name='L2876'></a><a href='#L2876'>2876</a>
- <a name='L2877'></a><a href='#L2877'>2877</a>
- <a name='L2878'></a><a href='#L2878'>2878</a>
- <a name='L2879'></a><a href='#L2879'>2879</a>
- <a name='L2880'></a><a href='#L2880'>2880</a>
- <a name='L2881'></a><a href='#L2881'>2881</a>
- <a name='L2882'></a><a href='#L2882'>2882</a>
- <a name='L2883'></a><a href='#L2883'>2883</a>
- <a name='L2884'></a><a href='#L2884'>2884</a>
- <a name='L2885'></a><a href='#L2885'>2885</a>
- <a name='L2886'></a><a href='#L2886'>2886</a>
- <a name='L2887'></a><a href='#L2887'>2887</a>
- <a name='L2888'></a><a href='#L2888'>2888</a>
- <a name='L2889'></a><a href='#L2889'>2889</a>
- <a name='L2890'></a><a href='#L2890'>2890</a>
- <a name='L2891'></a><a href='#L2891'>2891</a>
- <a name='L2892'></a><a href='#L2892'>2892</a>
- <a name='L2893'></a><a href='#L2893'>2893</a>
- <a name='L2894'></a><a href='#L2894'>2894</a>
- <a name='L2895'></a><a href='#L2895'>2895</a>
- <a name='L2896'></a><a href='#L2896'>2896</a>
- <a name='L2897'></a><a href='#L2897'>2897</a>
- <a name='L2898'></a><a href='#L2898'>2898</a>
- <a name='L2899'></a><a href='#L2899'>2899</a>
- <a name='L2900'></a><a href='#L2900'>2900</a>
- <a name='L2901'></a><a href='#L2901'>2901</a>
- <a name='L2902'></a><a href='#L2902'>2902</a>
- <a name='L2903'></a><a href='#L2903'>2903</a>
- <a name='L2904'></a><a href='#L2904'>2904</a>
- <a name='L2905'></a><a href='#L2905'>2905</a>
- <a name='L2906'></a><a href='#L2906'>2906</a>
- <a name='L2907'></a><a href='#L2907'>2907</a>
- <a name='L2908'></a><a href='#L2908'>2908</a>
- <a name='L2909'></a><a href='#L2909'>2909</a>
- <a name='L2910'></a><a href='#L2910'>2910</a>
- <a name='L2911'></a><a href='#L2911'>2911</a>
- <a name='L2912'></a><a href='#L2912'>2912</a>
- <a name='L2913'></a><a href='#L2913'>2913</a>
- <a name='L2914'></a><a href='#L2914'>2914</a>
- <a name='L2915'></a><a href='#L2915'>2915</a>
- <a name='L2916'></a><a href='#L2916'>2916</a>
- <a name='L2917'></a><a href='#L2917'>2917</a>
- <a name='L2918'></a><a href='#L2918'>2918</a>
- <a name='L2919'></a><a href='#L2919'>2919</a>
- <a name='L2920'></a><a href='#L2920'>2920</a>
- <a name='L2921'></a><a href='#L2921'>2921</a>
- <a name='L2922'></a><a href='#L2922'>2922</a>
- <a name='L2923'></a><a href='#L2923'>2923</a>
- <a name='L2924'></a><a href='#L2924'>2924</a>
- <a name='L2925'></a><a href='#L2925'>2925</a>
- <a name='L2926'></a><a href='#L2926'>2926</a>
- <a name='L2927'></a><a href='#L2927'>2927</a>
- <a name='L2928'></a><a href='#L2928'>2928</a>
- <a name='L2929'></a><a href='#L2929'>2929</a>
- <a name='L2930'></a><a href='#L2930'>2930</a>
- <a name='L2931'></a><a href='#L2931'>2931</a>
- <a name='L2932'></a><a href='#L2932'>2932</a>
- <a name='L2933'></a><a href='#L2933'>2933</a>
- <a name='L2934'></a><a href='#L2934'>2934</a>
- <a name='L2935'></a><a href='#L2935'>2935</a>
- <a name='L2936'></a><a href='#L2936'>2936</a>
- <a name='L2937'></a><a href='#L2937'>2937</a>
- <a name='L2938'></a><a href='#L2938'>2938</a>
- <a name='L2939'></a><a href='#L2939'>2939</a>
- <a name='L2940'></a><a href='#L2940'>2940</a>
- <a name='L2941'></a><a href='#L2941'>2941</a>
- <a name='L2942'></a><a href='#L2942'>2942</a>
- <a name='L2943'></a><a href='#L2943'>2943</a>
- <a name='L2944'></a><a href='#L2944'>2944</a>
- <a name='L2945'></a><a href='#L2945'>2945</a>
- <a name='L2946'></a><a href='#L2946'>2946</a>
- <a name='L2947'></a><a href='#L2947'>2947</a>
- <a name='L2948'></a><a href='#L2948'>2948</a>
- <a name='L2949'></a><a href='#L2949'>2949</a>
- <a name='L2950'></a><a href='#L2950'>2950</a>
- <a name='L2951'></a><a href='#L2951'>2951</a>
- <a name='L2952'></a><a href='#L2952'>2952</a>
- <a name='L2953'></a><a href='#L2953'>2953</a>
- <a name='L2954'></a><a href='#L2954'>2954</a>
- <a name='L2955'></a><a href='#L2955'>2955</a>
- <a name='L2956'></a><a href='#L2956'>2956</a>
- <a name='L2957'></a><a href='#L2957'>2957</a>
- <a name='L2958'></a><a href='#L2958'>2958</a>
- <a name='L2959'></a><a href='#L2959'>2959</a>
- <a name='L2960'></a><a href='#L2960'>2960</a>
- <a name='L2961'></a><a href='#L2961'>2961</a>
- <a name='L2962'></a><a href='#L2962'>2962</a>
- <a name='L2963'></a><a href='#L2963'>2963</a>
- <a name='L2964'></a><a href='#L2964'>2964</a>
- <a name='L2965'></a><a href='#L2965'>2965</a>
- <a name='L2966'></a><a href='#L2966'>2966</a>
- <a name='L2967'></a><a href='#L2967'>2967</a>
- <a name='L2968'></a><a href='#L2968'>2968</a>
- <a name='L2969'></a><a href='#L2969'>2969</a>
- <a name='L2970'></a><a href='#L2970'>2970</a>
- <a name='L2971'></a><a href='#L2971'>2971</a>
- <a name='L2972'></a><a href='#L2972'>2972</a>
- <a name='L2973'></a><a href='#L2973'>2973</a>
- <a name='L2974'></a><a href='#L2974'>2974</a>
- <a name='L2975'></a><a href='#L2975'>2975</a>
- <a name='L2976'></a><a href='#L2976'>2976</a>
- <a name='L2977'></a><a href='#L2977'>2977</a>
- <a name='L2978'></a><a href='#L2978'>2978</a>
- <a name='L2979'></a><a href='#L2979'>2979</a>
- <a name='L2980'></a><a href='#L2980'>2980</a>
- <a name='L2981'></a><a href='#L2981'>2981</a>
- <a name='L2982'></a><a href='#L2982'>2982</a>
- <a name='L2983'></a><a href='#L2983'>2983</a>
- <a name='L2984'></a><a href='#L2984'>2984</a>
- <a name='L2985'></a><a href='#L2985'>2985</a>
- <a name='L2986'></a><a href='#L2986'>2986</a>
- <a name='L2987'></a><a href='#L2987'>2987</a>
- <a name='L2988'></a><a href='#L2988'>2988</a>
- <a name='L2989'></a><a href='#L2989'>2989</a>
- <a name='L2990'></a><a href='#L2990'>2990</a>
- <a name='L2991'></a><a href='#L2991'>2991</a>
- <a name='L2992'></a><a href='#L2992'>2992</a>
- <a name='L2993'></a><a href='#L2993'>2993</a>
- <a name='L2994'></a><a href='#L2994'>2994</a>
- <a name='L2995'></a><a href='#L2995'>2995</a>
- <a name='L2996'></a><a href='#L2996'>2996</a>
- <a name='L2997'></a><a href='#L2997'>2997</a>
- <a name='L2998'></a><a href='#L2998'>2998</a>
- <a name='L2999'></a><a href='#L2999'>2999</a>
- <a name='L3000'></a><a href='#L3000'>3000</a>
- <a name='L3001'></a><a href='#L3001'>3001</a>
- <a name='L3002'></a><a href='#L3002'>3002</a>
- <a name='L3003'></a><a href='#L3003'>3003</a>
- <a name='L3004'></a><a href='#L3004'>3004</a>
- <a name='L3005'></a><a href='#L3005'>3005</a>
- <a name='L3006'></a><a href='#L3006'>3006</a>
- <a name='L3007'></a><a href='#L3007'>3007</a>
- <a name='L3008'></a><a href='#L3008'>3008</a>
- <a name='L3009'></a><a href='#L3009'>3009</a>
- <a name='L3010'></a><a href='#L3010'>3010</a>
- <a name='L3011'></a><a href='#L3011'>3011</a>
- <a name='L3012'></a><a href='#L3012'>3012</a>
- <a name='L3013'></a><a href='#L3013'>3013</a>
- <a name='L3014'></a><a href='#L3014'>3014</a>
- <a name='L3015'></a><a href='#L3015'>3015</a>
- <a name='L3016'></a><a href='#L3016'>3016</a>
- <a name='L3017'></a><a href='#L3017'>3017</a>
- <a name='L3018'></a><a href='#L3018'>3018</a>
- <a name='L3019'></a><a href='#L3019'>3019</a>
- <a name='L3020'></a><a href='#L3020'>3020</a>
- <a name='L3021'></a><a href='#L3021'>3021</a>
- <a name='L3022'></a><a href='#L3022'>3022</a>
- <a name='L3023'></a><a href='#L3023'>3023</a>
- <a name='L3024'></a><a href='#L3024'>3024</a>
- <a name='L3025'></a><a href='#L3025'>3025</a>
- <a name='L3026'></a><a href='#L3026'>3026</a>
- <a name='L3027'></a><a href='#L3027'>3027</a>
- <a name='L3028'></a><a href='#L3028'>3028</a>
- <a name='L3029'></a><a href='#L3029'>3029</a>
- <a name='L3030'></a><a href='#L3030'>3030</a>
- <a name='L3031'></a><a href='#L3031'>3031</a>
- <a name='L3032'></a><a href='#L3032'>3032</a>
- <a name='L3033'></a><a href='#L3033'>3033</a>
- <a name='L3034'></a><a href='#L3034'>3034</a>
- <a name='L3035'></a><a href='#L3035'>3035</a>
- <a name='L3036'></a><a href='#L3036'>3036</a>
- <a name='L3037'></a><a href='#L3037'>3037</a>
- <a name='L3038'></a><a href='#L3038'>3038</a>
- <a name='L3039'></a><a href='#L3039'>3039</a>
- <a name='L3040'></a><a href='#L3040'>3040</a>
- <a name='L3041'></a><a href='#L3041'>3041</a>
- <a name='L3042'></a><a href='#L3042'>3042</a>
- <a name='L3043'></a><a href='#L3043'>3043</a>
- <a name='L3044'></a><a href='#L3044'>3044</a>
- <a name='L3045'></a><a href='#L3045'>3045</a>
- <a name='L3046'></a><a href='#L3046'>3046</a>
- <a name='L3047'></a><a href='#L3047'>3047</a>
- <a name='L3048'></a><a href='#L3048'>3048</a></td><td class="line-coverage quiet"><span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span>
- <span class="cline-any cline-no"> </span>
- <span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" >/**<span class="fstat-no" title="function not covered" ><span class="branch-0 cbranch-no" title="branch not covered" ></span></span></span>
- * LangGraph 书籍生成 - API 路由
- * 支持书籍创建时的预估显示
- */
-
- <span class="cstat-no" title="statement not covered" >import Router from '@koa/router';</span>
- import { Context } from 'koa';
- <span class="cstat-no" title="statement not covered" >import { langGraphGenerator, getScaleConfig, resolveGenLevel, mapBookTypeToGenLevel } from './index';</span>
- <span class="cstat-no" title="statement not covered" >import { bookStore, cancelAudioGeneration } from './book-generator.store';</span>
- <span class="cstat-no" title="statement not covered" >import { prisma } from '../../models';</span>
- <span class="cstat-no" title="statement not covered" >import { estimateBookWords, estimateAudioMinutesFromWords, checkBookGenerationQuota, checkAudioQuota } from '../subscription/subscription.service';</span>
- <span class="cstat-no" title="statement not covered" >import { optionalAuth } from '../../middleware/auth';</span>
- <span class="cstat-no" title="statement not covered" >import { getAllBookTypes, getDetectableTypes, getBookTypeConfig, BOOK_TYPE_CONFIG, DETECTABLE_TYPES } from './book-type-config';</span>
- <span class="cstat-no" title="statement not covered" >import { callLLMWithMessages, callLLM, ChatMessage } from '../../services/llm';</span>
- <span class="cstat-no" title="statement not covered" >import { cleanLlmShortText, extractJsonFromResponse } from '../../services/llm/response-cleaner';</span>
- <span class="cstat-no" title="statement not covered" >import { createVideoProjectFromBook, generateVideoForProject } from '../video-generator/video-generator.service';</span>
- <span class="cstat-no" title="statement not covered" >import { mergeChapterAudios } from '../player/player.service';</span>
- <span class="cstat-no" title="statement not covered" >import { exec } from 'child_process';</span>
- <span class="cstat-no" title="statement not covered" >import { promisify } from 'util';</span>
- <span class="cstat-no" title="statement not covered" >import fs from 'fs/promises';</span>
- <span class="cstat-no" title="statement not covered" >import path from 'path';</span>
- <span class="cstat-no" title="statement not covered" >import { advanceChapter, regenerateChapter } from './stage-manager';</span>
- <span class="cstat-no" title="statement not covered" >import { deepPlanBookNode } from './nodes/deep-plan.node';</span>
- <span class="cstat-no" title="statement not covered" >import { richOutlineNode } from './nodes/rich-outline.node';</span>
- <span class="cstat-no" title="statement not covered" >import { writeChaptersParallelNode } from './nodes/content.node';</span>
- <span class="cstat-no" title="statement not covered" >import { continuityEditNode } from './nodes/continuity-edit.node';</span>
- import { GraphState } from './graph';
-
- <span class="cstat-no" title="statement not covered" >const execPromise = promisify(exec);</span>
-
- // 开发环境测试用户ID
- <span class="cstat-no" title="statement not covered" >const TEST_USER_ID = '1';</span>
-
- <span class="cstat-no" title="statement not covered" >const router = new Router();</span>
-
- /**
- * GET /api/book-generator/langgraph/estimate
- * 获取书籍规模预估信息
- */
- <span class="cstat-no" title="statement not covered" >router.get('/estimate', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > const { scale, userId, bookType } = ctx.query as { scale?: string; userId?: string; bookType?: string };</span>
-
- <span class="cstat-no" title="statement not covered" > if (!scale) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '请提供书籍规模' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const scaleConfig = getScaleConfig(scale);</span>
- <span class="cstat-no" title="statement not covered" > const totalWords = scaleConfig.totalWords;</span>
- <span class="cstat-no" title="statement not covered" > const audioMinutes = estimateAudioMinutesFromWords(totalWords);</span>
-
- // 章节数
- <span class="cstat-no" title="statement not covered" > const estimatedChapters = scaleConfig.isShortArticle ? 1 : scaleConfig.chapters;</span>
-
- // 大纲层级(优先使用书籍类型映射)
- <span class="cstat-no" title="statement not covered" > const genLevel = bookType && bookType !== 'auto'</span>
- <span class="cstat-no" title="statement not covered" > ? mapBookTypeToGenLevel(bookType)</span>
- <span class="cstat-no" title="statement not covered" > : resolveGenLevel(scale);</span>
- <span class="cstat-no" title="statement not covered" > const genLevelDescriptions: Record<number, { label: string; desc: string }> = {</span>
- <span class="cstat-no" title="statement not covered" > 1: { label: '仅章', desc: '无节和小节,适合短文、小说' },</span>
- <span class="cstat-no" title="statement not covered" > 2: { label: '章→节', desc: '有节无小节,适合科普、商业书' },</span>
- <span class="cstat-no" title="statement not covered" > 3: { label: '章→节→小节', desc: '完整三级结构,适合教材、技术书' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- <span class="cstat-no" title="statement not covered" > const result: any = {</span>
- <span class="cstat-no" title="statement not covered" > scale,</span>
- <span class="cstat-no" title="statement not covered" > scaleConfig,</span>
- <span class="cstat-no" title="statement not covered" > audioMinutes: {</span>
- <span class="cstat-no" title="statement not covered" > min: estimateAudioMinutesFromWords(Math.round(totalWords * 0.8)),</span>
- <span class="cstat-no" title="statement not covered" > max: estimateAudioMinutesFromWords(Math.round(totalWords * 1.2)),</span>
- <span class="cstat-no" title="statement not covered" > avg: audioMinutes</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > estimatedChapters,</span>
- <span class="cstat-no" title="statement not covered" > defaultGenLevel: genLevel,</span>
- <span class="cstat-no" title="statement not covered" > genLevelInfo: genLevelDescriptions[genLevel] || { label: '章→节', desc: '' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- // 如果提供了 userId,同时检查用户配额
- <span class="cstat-no" title="statement not covered" > if (userId) {</span>
- <span class="cstat-no" title="statement not covered" > const quotaCheck = await checkBookGenerationQuota(parseInt(userId), scale);</span>
- <span class="cstat-no" title="statement not covered" > result.quotaCheck = quotaCheck;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: result</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/detect-scale
- * AI 预览检测书籍规模(创建前调用,让用户看到检测结果)
- */
- <span class="cstat-no" title="statement not covered" >router.post('/detect-scale', async (ctx) => {</span>
- <span class="cstat-no" title="statement not covered" > const { description } = ctx.request.body as { description?: string };</span>
- <span class="cstat-no" title="statement not covered" > if (!description) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '缺少 description' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > const scale = await autoDetectBookType('', description);</span>
- <span class="cstat-no" title="statement not covered" > const config = getScaleConfig(scale);</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookScale: scale,</span>
- <span class="cstat-no" title="statement not covered" > totalWords: config.totalWords,</span>
- <span class="cstat-no" title="statement not covered" > chapters: config.chapters,</span>
- <span class="cstat-no" title="statement not covered" > isShortArticle: config.isShortArticle,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/book-types
- * 获取所有书籍类型配置(供前端显示)
- */
- <span class="cstat-no" title="statement not covered" >router.get('/book-types', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > const types = getAllBookTypes().map(t => ({</span>
- <span class="cstat-no" title="statement not covered" > key: t.key,</span>
- <span class="cstat-no" title="statement not covered" > label: t.label,</span>
- <span class="cstat-no" title="statement not covered" > description: t.description,</span>
- <span class="cstat-no" title="statement not covered" > chapters: t.chapters,</span>
- <span class="cstat-no" title="statement not covered" > totalWords: t.totalWords,</span>
- <span class="cstat-no" title="statement not covered" > audioMinutes: t.audioMinutes,</span>
- <span class="cstat-no" title="statement not covered" > chapterWords: t.chapterWords,</span>
- <span class="cstat-no" title="statement not covered" > structureFormat: t.structureFormat,</span>
- <span class="cstat-no" title="statement not covered" > readingDifficulty: t.readingDifficulty,</span>
- <span class="cstat-no" title="statement not covered" > isShortArticle: t.isShortArticle,</span>
- <span class="cstat-no" title="statement not covered" > }));</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: types,</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/detect-book-type
- * AI 自动检测书籍类型
- */
- <span class="cstat-no" title="statement not covered" >router.post('/detect-book-type', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > const { title, description } = ctx.request.body as {</span>
- title?: string;
- description?: string;
- };
-
- <span class="cstat-no" title="statement not covered" > if (!title) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '请提供书籍标题' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const detectableTypes = DETECTABLE_TYPES;</span>
-
- // 构建类型特征描述,帮助 AI 分类
- <span class="cstat-no" title="statement not covered" > const typeDescriptions = detectableTypes.map(key => {</span>
- <span class="cstat-no" title="statement not covered" > const t = BOOK_TYPE_CONFIG[key];</span>
- <span class="cstat-no" title="statement not covered" > return `- ${t.key}: ${t.description},${t.chapters}章,总字数约${t.totalWords}字,每章约${t.chapterWords}字,结构形式:${t.structureFormat},阅读难度:${t.readingDifficulty}`;</span>
- <span class="cstat-no" title="statement not covered" > }).join('\n');</span>
-
- <span class="cstat-no" title="statement not covered" > const messages: ChatMessage[] = [</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'system',</span>
- <span class="cstat-no" title="statement not covered" > content: `你是一位专业的图书分类编辑。根据用户提供的标题和描述,判断这本书最可能属于以下哪种类型:</span>
-
- 可选类型:
- <span class="cstat-no" title="statement not covered" >${typeDescriptions}</span>
-
- ## 分类规则
- 1. 分析标题中的关键词(如"科普""青少年""专业""小说"等)
- 2. 分析描述中的目标读者、写作风格、内容深度
- 3. 匹配最符合的类型
-
- ## 输出格式
- 必须返回 JSON,不要包含 markdown 代码块标记:
- {
- "detectedType": "类型 key",
- "confidence": 0.85,
- "reasoning": "分类理由,1-2句话"
- }
-
- confidence 是 0-1 的数值,表示置信程度。`,
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'user',</span>
- <span class="cstat-no" title="statement not covered" > content: `标题:《${title}》\n描述:${description || '无'}`,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > ];</span>
-
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const response = await callLLMWithMessages(messages);</span>
- <span class="cstat-no" title="statement not covered" > const parsed = parseDetectResult(response);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!parsed) {</span>
- // 降级到关键词匹配
- <span class="cstat-no" title="statement not covered" > const fallback = keywordFallback(title, description || '');</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > detectedType: fallback.detectedType,</span>
- <span class="cstat-no" title="statement not covered" > confidence: 0.5,</span>
- <span class="cstat-no" title="statement not covered" > reasoning: '基于关键词匹配(AI 解析失败,使用降级策略)',</span>
- <span class="cstat-no" title="statement not covered" > config: getBookTypeConfig(fallback.detectedType),</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > detectedType: parsed.detectedType,</span>
- <span class="cstat-no" title="statement not covered" > confidence: parsed.confidence,</span>
- <span class="cstat-no" title="statement not covered" > reasoning: parsed.reasoning,</span>
- <span class="cstat-no" title="statement not covered" > config: getBookTypeConfig(parsed.detectedType),</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error: any) {</span>
- // 最终降级:关键词匹配
- <span class="cstat-no" title="statement not covered" > const fallback = keywordFallback(title, description || '');</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > detectedType: fallback.detectedType,</span>
- <span class="cstat-no" title="statement not covered" > confidence: 0.3,</span>
- <span class="cstat-no" title="statement not covered" > reasoning: 'LLM 调用失败,使用关键词匹配降级',</span>
- <span class="cstat-no" title="statement not covered" > config: getBookTypeConfig(fallback.detectedType),</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- <span class="cstat-no" title="statement not covered" >function parseDetectResult(text: string): { detectedType: string; confidence: number; reasoning: string } | null {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const match = text.match(/\{[\s\S]*\}/);</span>
- <span class="cstat-no" title="statement not covered" > if (!match) return null;</span>
- <span class="cstat-no" title="statement not covered" > const data = JSON.parse(match[0]);</span>
- <span class="cstat-no" title="statement not covered" > if (!data.detectedType) return null;</span>
- // 验证类型是否有效
- <span class="cstat-no" title="statement not covered" > if (!DETECTABLE_TYPES.includes(data.detectedType)) {</span>
- // 尝试模糊匹配
- <span class="cstat-no" title="statement not covered" > const found = DETECTABLE_TYPES.find(t => data.detectedType.includes(t) || t.includes(data.detectedType));</span>
- <span class="cstat-no" title="statement not covered" > if (!found) return null;</span>
- <span class="cstat-no" title="statement not covered" > data.detectedType = found;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > return {</span>
- <span class="cstat-no" title="statement not covered" > detectedType: data.detectedType,</span>
- <span class="cstat-no" title="statement not covered" > confidence: Math.min(1, Math.max(0, data.confidence || 0.5)),</span>
- <span class="cstat-no" title="statement not covered" > reasoning: data.reasoning || '',</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch {</span>
- <span class="cstat-no" title="statement not covered" > return null;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >}</span>
-
- <span class="cstat-no" title="statement not covered" >function keywordFallback(_title: string, _description: string): { detectedType: string } {</span>
- // 完全由 AI 判断,fallback 只在 LLM 完全失败时作为最后保险
- <span class="cstat-no" title="statement not covered" > return { detectedType: '1000' }; // 最小规模</span>
- <span class="cstat-no" title="statement not covered" >}</span>
-
- /**
- * AI 根据描述自动生成书名
- */
- <span class="cstat-no" title="statement not covered" >async function autoGenerateTitle(description: string): Promise<string> {</span>
- <span class="cstat-no" title="statement not covered" > const prompt = `根据以下描述起一个书名。要求:中文不超过20字,英文不超过20个单词。只返回书名,不要任何解释、思考或前缀。</span>
-
- <span class="cstat-no" title="statement not covered" >描述:${description.substring(0, 200)}</span>
-
- 书名:`;
-
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const response = await callLLM(prompt);</span>
- <span class="cstat-no" title="statement not covered" > const title = cleanLlmShortText(response, {</span>
- <span class="cstat-no" title="statement not covered" > maxLength: 50,</span>
- <span class="cstat-no" title="statement not covered" > maxChineseChars: 20,</span>
- <span class="cstat-no" title="statement not covered" > maxEnglishWords: 20,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] AI 生成书名: "${title}"`);</span>
- <span class="cstat-no" title="statement not covered" > return title || '未命名书籍';</span>
- <span class="cstat-no" title="statement not covered" > } catch (e) {</span>
- <span class="cstat-no" title="statement not covered" > console.warn('[LangGraph] AI 自动生成书名失败,使用默认:', e);</span>
- <span class="cstat-no" title="statement not covered" > return '未命名书籍';</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >}</span>
-
- /**
- * AI 自动检测书籍规模(字数等级),后端静默调用
- * AI 分析描述中的字数要求,以 JSON 格式返回,供程序提取
- */
- <span class="cstat-no" title="statement not covered" >async function autoDetectBookType(title: string, description: string): Promise<string> {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[autoDetectBookType] 被调用: title="${title}", desc前50="${description?.substring(0, 50)}"`);</span>
- <span class="cstat-no" title="statement not covered" > const messages: ChatMessage[] = [</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'system',</span>
- <span class="cstat-no" title="statement not covered" > content: `你是一位专业的图书分类编辑。根据标题和描述,判断书籍适合的字数规模。</span>
-
- ## 判断规则
-
- **规则1 - 字数直接返回**:如果描述里有"X字"(如"200字""500字""几千字"),直接返回X作为bookScale值,不要映射到预定义规模。
- - 描述含"200字"→返回200
- - 描述含"500字"→返回500
- - 描述含"几千字"→估计约3000,返回3000
- - 描述含"上万字"→估计约10000,返回10000
-
- **规则2 - 无法判断**:描述中没有字数信息 → 返回1000
-
- ## 输出格式(必须严格JSON)
- {"bookScale": 数字}
- 只返回JSON,不要任何其他文字。`,
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'user',</span>
- <span class="cstat-no" title="statement not covered" > content: `标题:《${title}》\n描述:${description}`,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > ];</span>
-
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const response = await callLLMWithMessages(messages);</span>
- <span class="cstat-no" title="statement not covered" > const trimmed = response.trim();</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[autoDetectBookType] AI原始响应: ${trimmed.substring(0, 200)}`);</span>
-
- // 尝试解析 JSON,提取 bookScale(实际字数)
- <span class="cstat-no" title="statement not covered" > const jsonMatch = trimmed.match(/\{[\s\S]*\}/);</span>
- <span class="cstat-no" title="statement not covered" > if (jsonMatch) {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const data = JSON.parse(jsonMatch[0]);</span>
- <span class="cstat-no" title="statement not covered" > if (typeof data.bookScale === 'number') {</span>
- <span class="cstat-no" title="statement not covered" > const wordCount = data.bookScale;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[autoDetectBookType] AI返回: bookScale=${wordCount}`);</span>
- // 直接返回实际字数,getBookTypeConfig 支持任意数字 key
- <span class="cstat-no" title="statement not covered" > return String(wordCount);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > } catch {</span>
- // JSON解析失败,忽略
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // JSON解析失败 → 默认返回最小规模
- <span class="cstat-no" title="statement not covered" > console.log(`[autoDetectBookType] AI响应无法解析,使用默认值1000`);</span>
- <span class="cstat-no" title="statement not covered" > return '1000';</span>
- <span class="cstat-no" title="statement not covered" > } catch (error: any) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[autoDetectBookType] AI调用异常:`, error?.message || error);</span>
- <span class="cstat-no" title="statement not covered" > return '1000';</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >}</span>
-
- /**
- * POST /api/book-generator/langgraph/smart-recommend
- * 根据书籍描述智能推荐难度、人群、风格、领域
- */
- <span class="cstat-no" title="statement not covered" >router.post('/smart-recommend', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { description, title } = ctx.request.body as { description: string; title?: string };</span>
-
- <span class="cstat-no" title="statement not covered" > if (!description || !description.trim()) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '描述不能为空' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 默认推荐值
- <span class="cstat-no" title="statement not covered" > const defaultResult = {</span>
- <span class="cstat-no" title="statement not covered" > knowledgeLevel: '入门',</span>
- <span class="cstat-no" title="statement not covered" > targetAudience: '通用',</span>
- <span class="cstat-no" title="statement not covered" > style: '轻松幽默',</span>
- <span class="cstat-no" title="statement not covered" > industry: '教育',</span>
- <span class="cstat-no" title="statement not covered" > reason: '默认推荐',</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- <span class="cstat-no" title="statement not covered" > const prompt = `根据以下书籍描述,推荐合适的知识难度、目标人群、写作风格和行业领域。</span>
-
- <span class="cstat-no" title="statement not covered" >书名:${title || '未命名'}</span>
- <span class="cstat-no" title="statement not covered" >描述:${description}</span>
-
- 请以 JSON 格式返回推荐结果,不要包含任何其他文字:
- {
- "knowledgeLevel": "入门|进阶|专业",
- "targetAudience": "推荐的目标人群",
- "style": "推荐风格",
- "industry": "推荐行业领域",
- "reason": "简要说明推荐理由"
- }`;
-
- <span class="cstat-no" title="statement not covered" > const messages: ChatMessage[] = [</span>
- <span class="cstat-no" title="statement not covered" > { role: 'system', content: '你是一位专业的图书策划编辑,擅长根据书籍内容推荐合适的定位。' },</span>
- <span class="cstat-no" title="statement not covered" > { role: 'user', content: prompt },</span>
- <span class="cstat-no" title="statement not covered" > ];</span>
-
- <span class="cstat-no" title="statement not covered" > const response = await callLLMWithMessages(messages);</span>
- <span class="cstat-no" title="statement not covered" > const result = extractJsonFromResponse(response) || defaultResult;</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: 'success', data: result };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('智能推荐失败:', error);</span>
- // 返回默认值而不是错误
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > knowledgeLevel: '入门',</span>
- <span class="cstat-no" title="statement not covered" > targetAudience: '通用',</span>
- <span class="cstat-no" title="statement not covered" > style: '轻松幽默',</span>
- <span class="cstat-no" title="statement not covered" > industry: '教育',</span>
- <span class="cstat-no" title="statement not covered" > reason: 'AI服务暂时不可用,使用默认推荐',</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books
- * 使用 LangGraph 创建并生成书籍(异步,自动生成大纲和内容)
- * AI 根据标题+描述自动判断书籍类型
- *
- * 优化策略:
- * 1. 并行执行 autoGenerateTitle + autoDetectBookType(串行→并行,耗时减半)
- * 2. 先创建书籍返回响应,AI 结果异步回填(用户无需等待 AI 完成即可看到书籍)
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const body = ctx.request.body as {</span>
- title: string;
- description: string;
- bookScale?: string;
- bookType?: string;
- genLevel?: number;
- generateForeword?: boolean;
- generateAfterword?: boolean;
- immediateGenerate?: boolean;
- };
-
- <span class="cstat-no" title="statement not covered" > if (!body.description) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '描述不能为空' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取用户 ID(未登录时使用测试用户)
- <span class="cstat-no" title="statement not covered" > const userId = ctx.state.user?.userId ? parseInt(ctx.state.user.userId as string) : parseInt(TEST_USER_ID);</span>
-
- <span class="cstat-no" title="statement not covered" > const providedTitle = body.title?.trim();</span>
- // 只接受数字格式的 bookScale(如 '200', '1000', '130000'),非数字当作未提供
- <span class="cstat-no" title="statement not covered" > const providedBookScale = body.bookScale && /^\d+$/.test(body.bookScale) ? body.bookScale : undefined;</span>
-
- // ========== 快速路径:用户已提供 title 和 bookScale,无需 AI ==========
- <span class="cstat-no" title="statement not covered" > if (providedTitle && providedBookScale) {</span>
- <span class="cstat-no" title="statement not covered" > const bookScale = providedBookScale;</span>
- <span class="cstat-no" title="statement not covered" > const genLevel = body.genLevel !== undefined</span>
- <span class="cstat-no" title="statement not covered" > ? resolveGenLevel(bookScale, body.genLevel)</span>
- <span class="cstat-no" title="statement not covered" > : body.bookType && body.bookType !== 'auto'</span>
- <span class="cstat-no" title="statement not covered" > ? mapBookTypeToGenLevel(body.bookType)</span>
- <span class="cstat-no" title="statement not covered" > : resolveGenLevel(bookScale);</span>
-
- <span class="cstat-no" title="statement not covered" > const scaleConfig = getScaleConfig(bookScale);</span>
- <span class="cstat-no" title="statement not covered" > const totalWords = scaleConfig.totalWords;</span>
- <span class="cstat-no" title="statement not covered" > const audioQuota = await checkAudioQuota(userId, totalWords);</span>
- <span class="cstat-no" title="statement not covered" > if (!audioQuota.allowed) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 403;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: audioQuota.reason, data: { estimatedWords: totalWords, estimatedAudioMinutes: estimateAudioMinutesFromWords(totalWords), remainingMinutes: audioQuota.remainingMinutes, totalMinutes: audioQuota.totalMinutes } };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.create({</span>
- <span class="cstat-no" title="statement not covered" > userId,</span>
- <span class="cstat-no" title="statement not covered" > title: providedTitle,</span>
- <span class="cstat-no" title="statement not covered" > description: body.description,</span>
- <span class="cstat-no" title="statement not covered" > bookScale,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters: scaleConfig.isShortArticle ? 1 : scaleConfig.chapters,</span>
- <span class="cstat-no" title="statement not covered" > estimatedWords: totalWords,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > if (body.immediateGenerate === false) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: '书籍创建成功(交互模式)', data: { book, genStage: 'draft', mode: 'interactive' } };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > await bookStore.update(book.id, { genStage: 'outlining' });</span>
- <span class="cstat-no" title="statement not covered" > langGraphGenerator.generate(book.id.toString(), body.description, bookScale, genLevel)</span>
- <span class="cstat-no" title="statement not covered" > .then(() => console.log(`[LangGraph] 生成完成: bookId=${book.id}`))</span>
- <span class="cstat-no" title="statement not covered" > .catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[LangGraph] 生成失败: bookId=${book.id}`, err);</span>
- <span class="cstat-no" title="statement not covered" > bookStore.update(book.id.toString(), { genStage: 'failed', errorMsg: err instanceof Error ? err.message : '生成失败', failedStage: 'outlining' });</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: '书籍创建成功,生成已开始', data: { book, genStage: 'outlining', mode: 'async' } };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // ========== 需要 AI 辅助的路径:先创建书籍,再异步回填 ==========
- // 使用临时标题/默认规模先创建书籍,立即返回给前端
- // 规模会由 AI 异步回填
- <span class="cstat-no" title="statement not covered" > const fallbackScale = providedBookScale || '1000';</span>
- <span class="cstat-no" title="statement not covered" > const fallbackTitle = providedTitle || '正在生成标题...';</span>
- <span class="cstat-no" title="statement not covered" > const fallbackConfig = getScaleConfig(fallbackScale);</span>
- <span class="cstat-no" title="statement not covered" > const fallbackWords = fallbackConfig.totalWords;</span>
-
- // 配额预检查(使用默认规模估算,后续可能因 AI 检测结果调整)
- <span class="cstat-no" title="statement not covered" > const audioQuota = await checkAudioQuota(userId, fallbackWords);</span>
- <span class="cstat-no" title="statement not covered" > if (!audioQuota.allowed) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 403;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: audioQuota.reason, data: { estimatedWords: fallbackWords, estimatedAudioMinutes: estimateAudioMinutesFromWords(fallbackWords), remainingMinutes: audioQuota.remainingMinutes, totalMinutes: audioQuota.totalMinutes } };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 先创建书籍,立即返回
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.create({</span>
- <span class="cstat-no" title="statement not covered" > userId,</span>
- <span class="cstat-no" title="statement not covered" > title: fallbackTitle,</span>
- <span class="cstat-no" title="statement not covered" > description: body.description,</span>
- <span class="cstat-no" title="statement not covered" > bookScale: fallbackScale,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters: fallbackConfig.isShortArticle ? 1 : fallbackConfig.chapters,</span>
- <span class="cstat-no" title="statement not covered" > estimatedWords: fallbackWords,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 标记为 AI 正在准备中
- <span class="cstat-no" title="statement not covered" > const needTitle = !providedTitle;</span>
- <span class="cstat-no" title="statement not covered" > const needScale = !providedBookScale;</span>
- <span class="cstat-no" title="statement not covered" > const aiPreparing = needTitle || needScale;</span>
-
- <span class="cstat-no" title="statement not covered" > if (body.immediateGenerate === false) {</span>
- // 交互模式:异步填充 AI 结果,但不需要启动生成
- <span class="cstat-no" title="statement not covered" > if (aiPreparing) {</span>
- <span class="cstat-no" title="statement not covered" > fillAiResultsAsync(book.id.toString(), body.description, providedTitle, providedBookScale);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: '书籍创建成功(交互模式)', data: { book, genStage: 'draft', mode: 'interactive', aiPreparing } };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 非交互模式:需要等 AI 完成后才能确定 bookScale/genLevel 启动生成
- <span class="cstat-no" title="statement not covered" > await bookStore.update(book.id, { genStage: 'outlining' });</span>
-
- // 立即返回响应
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '书籍创建成功,AI 正在准备标题和规模...',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > book,</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'outlining',</span>
- <span class="cstat-no" title="statement not covered" > mode: 'async',</span>
- <span class="cstat-no" title="statement not covered" > aiPreparing,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- // 异步:并行执行 AI 生成标题 + 检测规模,然后启动内容生成
- <span class="cstat-no" title="statement not covered" > (async () => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > let title = providedTitle;</span>
- <span class="cstat-no" title="statement not covered" > let bookScale = providedBookScale;</span>
-
- // 并行执行 AI 调用
- <span class="cstat-no" title="statement not covered" > const aiPromises: Promise<any>[] = [];</span>
- <span class="cstat-no" title="statement not covered" > const titleIdx = needTitle ? aiPromises.push(autoGenerateTitle(body.description)) - 1 : -1;</span>
- <span class="cstat-no" title="statement not covered" > const scaleIdx = needScale ? aiPromises.push(autoDetectBookType(providedTitle || '', body.description)) - 1 : -1;</span>
-
- <span class="cstat-no" title="statement not covered" > if (aiPromises.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > const results = await Promise.all(aiPromises);</span>
- <span class="cstat-no" title="statement not covered" > if (titleIdx >= 0) {</span>
- <span class="cstat-no" title="statement not covered" > title = results[titleIdx] as string;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] AI 自动生成书名: "${title}"`);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > if (scaleIdx >= 0) {</span>
- <span class="cstat-no" title="statement not covered" > bookScale = results[scaleIdx] as string;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] AI 自动检测规模: ${title} -> ${bookScale}`);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 回填 AI 结果到数据库
- <span class="cstat-no" title="statement not covered" > const scaleConfig = getScaleConfig(bookScale!);</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.update(book.id.toString(), {</span>
- <span class="cstat-no" title="statement not covered" > title: title!,</span>
- <span class="cstat-no" title="statement not covered" > bookScale: bookScale!,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters: scaleConfig.isShortArticle ? 1 : scaleConfig.chapters,</span>
- <span class="cstat-no" title="statement not covered" > estimatedWords: scaleConfig.totalWords,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 确定生成层级并启动内容生成
- <span class="cstat-no" title="statement not covered" > const genLevel = body.genLevel !== undefined</span>
- <span class="cstat-no" title="statement not covered" > ? resolveGenLevel(bookScale!, body.genLevel)</span>
- <span class="cstat-no" title="statement not covered" > : body.bookType && body.bookType !== 'auto'</span>
- <span class="cstat-no" title="statement not covered" > ? mapBookTypeToGenLevel(body.bookType)</span>
- <span class="cstat-no" title="statement not covered" > : resolveGenLevel(bookScale!);</span>
-
- <span class="cstat-no" title="statement not covered" > await langGraphGenerator.generate(book.id.toString(), body.description, bookScale!, genLevel);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] 生成完成: bookId=${book.id}`);</span>
- <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[LangGraph] AI 准备或生成失败: bookId=${book.id}`, err);</span>
- <span class="cstat-no" title="statement not covered" > bookStore.update(book.id.toString(), {</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'failed',</span>
- <span class="cstat-no" title="statement not covered" > errorMsg: err instanceof Error ? err.message : '生成失败',</span>
- <span class="cstat-no" title="statement not covered" > failedStage: 'outlining',</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > })();</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('启动失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: error instanceof Error ? error.message : '启动失败',</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * 异步填充 AI 结果(交互模式使用,不启动生成)
- */
- <span class="cstat-no" title="statement not covered" >async function fillAiResultsAsync(</span>
- <span class="cstat-no" title="statement not covered" > bookId: string,</span>
- <span class="cstat-no" title="statement not covered" > description: string,</span>
- <span class="cstat-no" title="statement not covered" > providedTitle?: string,</span>
- <span class="cstat-no" title="statement not covered" > providedBookScale?: string,</span>
- <span class="cstat-no" title="statement not covered" >): Promise<void> {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[fillAiResultsAsync] 开始: bookId=${bookId}, providedTitle="${providedTitle}", providedBookScale="${providedBookScale}", desc前50字="${description?.substring(0, 50)}"`);</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > let title = providedTitle;</span>
- <span class="cstat-no" title="statement not covered" > let bookScale = providedBookScale;</span>
-
- <span class="cstat-no" title="statement not covered" > const needTitle = !title;</span>
- <span class="cstat-no" title="statement not covered" > const needScale = !bookScale;</span>
-
- <span class="cstat-no" title="statement not covered" > const aiPromises: Promise<any>[] = [];</span>
- <span class="cstat-no" title="statement not covered" > const titleIdx = needTitle ? aiPromises.push(autoGenerateTitle(description)) - 1 : -1;</span>
- <span class="cstat-no" title="statement not covered" > const scaleIdx = needScale ? aiPromises.push(autoDetectBookType(title || '', description)) - 1 : -1;</span>
-
- <span class="cstat-no" title="statement not covered" > if (aiPromises.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > const results = await Promise.all(aiPromises);</span>
- <span class="cstat-no" title="statement not covered" > if (titleIdx >= 0) {</span>
- <span class="cstat-no" title="statement not covered" > title = results[titleIdx] as string;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] AI 自动生成书名 (交互): "${title}"`);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > if (scaleIdx >= 0) {</span>
- <span class="cstat-no" title="statement not covered" > bookScale = results[scaleIdx] as string;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] AI 自动检测规模 (交互): ${title} -> ${bookScale}`);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const scaleConfig = getScaleConfig(bookScale!);</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.update(bookId.toString(), {</span>
- <span class="cstat-no" title="statement not covered" > title: title!,</span>
- <span class="cstat-no" title="statement not covered" > bookScale: bookScale!,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters: scaleConfig.isShortArticle ? 1 : scaleConfig.chapters,</span>
- <span class="cstat-no" title="statement not covered" > estimatedWords: scaleConfig.totalWords,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
- <span class="cstat-no" title="statement not covered" > console.warn(`[LangGraph] AI 异步填充失败: bookId=${bookId}`, err);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >}</span>
-
- /**
- * GET /api/book-generator/langgraph/books
- * 获取书籍列表
- * 返回:公开的书籍(有公开音频)+ 当前用户自己的书籍
- * 注意:此接口已废弃,请使用 /public-books 或 /my-books
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const userId = ctx.state.user?.userId;</span>
- <span class="cstat-no" title="statement not covered" > const userIdNum = userId ? parseInt(userId as string) : undefined;</span>
-
- // 获取公开书籍(有公开音频的书籍)
- <span class="cstat-no" title="statement not covered" > const publicBooks = await bookStore.getPublicBooks();</span>
-
- // 如果用户已登录,获取用户自己的书籍
- <span class="cstat-no" title="statement not covered" > let userBooks: any[] = [];</span>
- <span class="cstat-no" title="statement not covered" > if (userIdNum) {</span>
- <span class="cstat-no" title="statement not covered" > userBooks = await bookStore.getAllByUser(userIdNum, false);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 合并并去重(按 id)
- <span class="cstat-no" title="statement not covered" > const bookMap = new Map<string, any>();</span>
- <span class="cstat-no" title="statement not covered" > publicBooks.forEach(b => bookMap.set(b.id, b));</span>
- <span class="cstat-no" title="statement not covered" > userBooks.forEach(b => {</span>
- <span class="cstat-no" title="statement not covered" > if (!bookMap.has(b.id)) {</span>
- <span class="cstat-no" title="statement not covered" > bookMap.set(b.id, b);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > const books = Array.from(bookMap.values());</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: 'success', data: { books } };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('查询失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '查询失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/public-books
- * 获取公开书籍列表(首页专用)
- * 只返回有公开音频的书籍
- */
- <span class="cstat-no" title="statement not covered" >router.get('/public-books', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const publicBooks = await bookStore.getPublicBooks();</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: 'success', data: { books: publicBooks } };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('查询公开书籍失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '查询失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/my-books
- * 获取当前用户自己的书籍列表(管理页专用)
- * 只返回当前用户创建的书籍
- */
- <span class="cstat-no" title="statement not covered" >router.get('/my-books', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const userId = ctx.state.user?.userId;</span>
- <span class="cstat-no" title="statement not covered" > if (!userId) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 401;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '请先登录' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const userBooks = await bookStore.getAllByUser(parseInt(userId as string), false);</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: 'success', data: { books: userBooks } };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('查询用户书籍失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '查询失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * PUT /api/book-generator/langgraph/books/:id/publish
- * 切换书籍公开状态
- */
- <span class="cstat-no" title="statement not covered" >router.put('/books/:id/publish', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const newStatus = await bookStore.togglePublish(bookId);</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { </span>
- <span class="cstat-no" title="statement not covered" > code: 0, </span>
- <span class="cstat-no" title="statement not covered" > message: 'success', </span>
- <span class="cstat-no" title="statement not covered" > data: { isPublished: newStatus } </span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('切换发布状态失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '操作失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id
- * 获取书籍详情
- * 支持公开过滤:?filterPublic=true&userId=1
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const userId = ctx.state.user?.userId || TEST_USER_ID;</span>
- <span class="cstat-no" title="statement not covered" > const filterPublic = ctx.query.filterPublic === 'true';</span>
-
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId, filterPublic, parseInt(userId as string));</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: 'success', data: { book } };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('查询失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '查询失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/progress
- * 获取书籍生成进度
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/progress', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 计算实际进度(基于章节完成情况)
- <span class="cstat-no" title="statement not covered" > const completedChapters = book.chapters.filter((c) => c.genStage === 'video_completed').length;</span>
- <span class="cstat-no" title="statement not covered" > const totalChapters = book.outline?.chapters?.length || book.totalChapters || 0;</span>
-
- // 查找当前正在生成的章节
- <span class="cstat-no" title="statement not covered" > const currentGenerating = book.chapters.find(</span>
- <span class="cstat-no" title="statement not covered" > (c) => c.genStage === 'content_generating' || c.genStage === 'audio_generating' || c.genStage === 'video_generating'</span>
- <span class="cstat-no" title="statement not covered" > );</span>
- <span class="cstat-no" title="statement not covered" > const currentChapter = currentGenerating</span>
- <span class="cstat-no" title="statement not covered" > ? { number: currentGenerating.number, title: currentGenerating.title, level: currentGenerating.level }</span>
- <span class="cstat-no" title="statement not covered" > : null;</span>
-
- // 如果有大纲,使用大纲章节数计算进度
- <span class="cstat-no" title="statement not covered" > let progress = book.progress;</span>
- <span class="cstat-no" title="statement not covered" > if (totalChapters > 0 && book.genStage !== 'video_completed') {</span>
- <span class="cstat-no" title="statement not covered" > progress = Math.round((completedChapters / totalChapters) * 100);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > genStage: book.genStage,</span>
- <span class="cstat-no" title="statement not covered" > progress,</span>
- <span class="cstat-no" title="statement not covered" > completedChapters,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters,</span>
- <span class="cstat-no" title="statement not covered" > currentChapter,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('查询进度失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '查询失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * DELETE /api/book-generator/langgraph/books/:id
- * 删除书籍
- */
- <span class="cstat-no" title="statement not covered" >router.delete('/books/:id', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.delete(bookId);</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: '删除成功' };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('删除失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '删除失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/generate
- * 对已有书籍使用 LangGraph 生成
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/generate', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph Generate] 收到请求 bookId=${bookId}`);</span>
-
- <span class="cstat-no" title="statement not covered" > const body = (ctx.request.body || {}) as { bookScale?: string; genLevel?: number };</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph Generate] book对象:`, book ? '存在' : 'null');</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // ========== 确定 bookScale ==========
- // 优先级:
- // 1) 请求显式指定(body.bookScale)→ 用户选的,直接用
- // 2) AI 根据描述自动检测 → LLM 判断
- // 3) 书籍已有规模 → 沿用
- // 4) 兜底 → 1000(最小规模)
- <span class="cstat-no" title="statement not covered" > let bookScale: string | undefined;</span>
-
- <span class="cstat-no" title="statement not covered" > if (body.bookScale && BOOK_TYPE_CONFIG[body.bookScale]) {</span>
- // 用户在当前请求中显式选了规模
- <span class="cstat-no" title="statement not covered" > bookScale = body.bookScale;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph Generate] 使用请求指定的 bookScale=${bookScale}`);</span>
- <span class="cstat-no" title="statement not covered" > } else {</span>
- // 未显式选择 → 让 AI 根据描述判断
- <span class="cstat-no" title="statement not covered" > const desc = book.description || '';</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph Generate] AI 自动检测规模...`);</span>
- <span class="cstat-no" title="statement not covered" > bookScale = await autoDetectBookType(book.title || '', desc);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph Generate] AI 检测结果 → bookScale=${bookScale}`);</span>
- <span class="cstat-no" title="statement not covered" > } catch (e) {</span>
- <span class="cstat-no" title="statement not covered" > console.warn(`[LangGraph Generate] AI 检测失败,回退:`, e);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // AI 失败或返回无效值 → 用书籍已保存的
- <span class="cstat-no" title="statement not covered" > if (!bookScale || !BOOK_TYPE_CONFIG[bookScale]) {</span>
- <span class="cstat-no" title="statement not covered" > bookScale = book.bookScale && BOOK_TYPE_CONFIG[book.bookScale] ? book.bookScale : undefined;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 最终兜底:用最小规模(1000字),避免误判生成大量无用内容
- <span class="cstat-no" title="statement not covered" > bookScale = bookScale && BOOK_TYPE_CONFIG[bookScale] ? bookScale : '1000';</span>
-
- // 持久化检测结果
- <span class="cstat-no" title="statement not covered" > if (bookScale !== book.bookScale) {</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.update(bookId, { bookScale });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const genLevel = resolveGenLevel(bookScale, body.genLevel, book.description);</span>
-
- // ========== 生成前配额检查 ==========
- <span class="cstat-no" title="statement not covered" > const userId = ctx.state.user?.userId ? parseInt(ctx.state.user.userId as string) : (book.userId || parseInt(TEST_USER_ID));</span>
- <span class="cstat-no" title="statement not covered" > const scaleConfig = getScaleConfig(bookScale);</span>
- <span class="cstat-no" title="statement not covered" > const totalWords = scaleConfig.totalWords;</span>
- <span class="cstat-no" title="statement not covered" > const audioQuota = await checkAudioQuota(userId, totalWords);</span>
- <span class="cstat-no" title="statement not covered" > if (!audioQuota.allowed) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 403;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: audioQuota.reason,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > estimatedWords: totalWords,</span>
- <span class="cstat-no" title="statement not covered" > estimatedAudioMinutes: estimateAudioMinutesFromWords(totalWords),</span>
- <span class="cstat-no" title="statement not covered" > remainingMinutes: audioQuota.remainingMinutes,</span>
- <span class="cstat-no" title="statement not covered" > totalMinutes: audioQuota.totalMinutes,</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 防止重复生成:如果书籍正在生成中,拒绝请求
- <span class="cstat-no" title="statement not covered" > if (book.genStage === 'content_generating' || book.genStage === 'audio_generating' || book.genStage === 'video_generating') {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph Generate] 书籍正在生成中,拒绝重复请求 bookId=${bookId}`);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: '书籍正在生成中,请勿重复提交',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > genStage: book.genStage,</span>
- <span class="cstat-no" title="statement not covered" > progress: book.progress,</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 异步生成(跳过队列,开发环境下队列不可靠)
- <span class="cstat-no" title="statement not covered" > await bookStore.update(bookId, { genStage: 'outlining' });</span>
-
- <span class="cstat-no" title="statement not covered" > langGraphGenerator.generate(bookId, book.description, bookScale, genLevel)</span>
- <span class="cstat-no" title="statement not covered" > .then(() => {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] 生成完成: bookId=${bookId}`);</span>
- <span class="cstat-no" title="statement not covered" > })</span>
- <span class="cstat-no" title="statement not covered" > .catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[LangGraph] 生成失败: bookId=${bookId}`, err);</span>
- <span class="cstat-no" title="statement not covered" > bookStore.update(bookId, {</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'failed', failedStage: 'outlining',</span>
- <span class="cstat-no" title="statement not covered" > errorMsg: err instanceof Error ? err.message : '生成失败',</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'LangGraph 生成任务已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: { bookId, genStage: 'outlining', mode: 'async' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('启动失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: error instanceof Error ? error.message : '启动失败',</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/audio
- * 批量生成书籍所有小节的音频
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/audio', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const { voiceId = 'longyingling_v3' } = ctx.request.body as { voiceId?: string };</span>
-
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 动态获取叶节点层级(最大level值)
- <span class="cstat-no" title="statement not covered" > const maxLevel = chapters.length > 0</span>
- <span class="cstat-no" title="statement not covered" > ? Math.max(...chapters.map((c: any) => c.level || 0))</span>
- <span class="cstat-no" title="statement not covered" > : 0;</span>
-
- <span class="cstat-no" title="statement not covered" > if (maxLevel === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '没有章节' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取叶节点(最大level的所有节点)
- <span class="cstat-no" title="statement not covered" > const leafNodes = chapters.filter((c: any) => c.level === maxLevel);</span>
-
- // 检查内容状态 - 叶节点必须有content且genStage为content_completed
- <span class="cstat-no" title="statement not covered" > const leafNodesWithContent = leafNodes.filter((c: any) => c.content && c.genStage === 'content_completed');</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodes.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: `没有${maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节'}` };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodesWithContent.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: `没有内容生成完成的${maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节'},请先生成内容`,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > totalSubsections: leafNodes.length,</span>
- <span class="cstat-no" title="statement not covered" > completedSubsections: 0,</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Audio] 书籍 ${bookId} 共有 ${leafNodes.length} 个${maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节'},其中 ${leafNodesWithContent.length} 个内容已生成完成`);</span>
-
- // 异步生成所有叶节点音频
- <span class="cstat-no" title="statement not covered" > for (const sub of leafNodesWithContent) {</span>
- <span class="cstat-no" title="statement not covered" > bookStore.generateChapterAudioById(sub.id, book.userId || 1).catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Audio] ${maxLevel === 3 ? '小节' : '节'}${sub.number}音频生成失败:`, err);</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '音频生成任务已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > totalSubsections: leafNodesWithContent.length,</span>
- <span class="cstat-no" title="statement not covered" > taskId: `audio_${bookId}_${Date.now()}`,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('音频生成失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '音频生成失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/audio/cancel
- * 取消书籍所有章节的音频生成
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/audio/cancel', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
-
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const result = await cancelAudioGeneration(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (result.cancelledCount === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '没有正在运行的音频生成任务',</span>
- <span class="cstat-no" title="statement not covered" > data: result,</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Audio] 书籍 ${bookId} 取消音频生成,已取消 ${result.cancelledCount} 个任务,回退 ${result.rolledBackChapters.length} 个章节`);</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: `已取消 ${result.cancelledCount} 个音频生成任务`,</span>
- <span class="cstat-no" title="statement not covered" > data: result,</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('取消音频生成失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '取消失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/video-status
- * 获取书籍视频生成状态(用于前端轮询)
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/video-status', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 动态获取叶节点层级
- <span class="cstat-no" title="statement not covered" > const maxLevel = chapters.length > 0</span>
- <span class="cstat-no" title="statement not covered" > ? Math.max(...chapters.map((c: any) => c.level || 0))</span>
- <span class="cstat-no" title="statement not covered" > : 0;</span>
-
- // 获取叶节点
- <span class="cstat-no" title="statement not covered" > const leafNodes = chapters.filter((c: any) => c.level === maxLevel);</span>
-
- // 统计视频状态
- <span class="cstat-no" title="statement not covered" > const total = leafNodes.length;</span>
- <span class="cstat-no" title="statement not covered" > const completed = leafNodes.filter((c: any) => c.videoUrl && c.videoUrl !== '').length;</span>
- <span class="cstat-no" title="statement not covered" > const pending = leafNodes.filter((c: any) => !c.videoUrl || c.videoUrl === '').length;</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > total,</span>
- <span class="cstat-no" title="statement not covered" > completed,</span>
- <span class="cstat-no" title="statement not covered" > pending,</span>
- <span class="cstat-no" title="statement not covered" > allCompleted: completed >= total && total > 0,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('获取视频状态失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '获取失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/audio-status
- * 获取书籍音频生成状态(用于前端轮询)
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/audio-status', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 动态获取叶节点层级
- <span class="cstat-no" title="statement not covered" > const maxLevel = chapters.length > 0</span>
- <span class="cstat-no" title="statement not covered" > ? Math.max(...chapters.map((c: any) => c.level || 0))</span>
- <span class="cstat-no" title="statement not covered" > : 0;</span>
-
- // 获取叶节点
- <span class="cstat-no" title="statement not covered" > const leafNodes = chapters.filter((c: any) => c.level === maxLevel);</span>
-
- // 统计音频状态
- <span class="cstat-no" title="statement not covered" > const total = leafNodes.length;</span>
- <span class="cstat-no" title="statement not covered" > const completed = leafNodes.filter((c: any) => c.audioUrl && c.audioUrl !== '').length;</span>
- <span class="cstat-no" title="statement not covered" > const pending = leafNodes.filter((c: any) => !c.audioUrl || c.audioUrl === '').length;</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > total,</span>
- <span class="cstat-no" title="statement not covered" > completed,</span>
- <span class="cstat-no" title="statement not covered" > pending,</span>
- <span class="cstat-no" title="statement not covered" > allCompleted: completed >= total && total > 0,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('获取音频状态失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '获取失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/failed-chapters
- * 获取生成失败的小节列表
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/failed-chapters', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取所有失败的小节
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
- <span class="cstat-no" title="statement not covered" > const failedSubsections = chapters.filter(c => c.genStage === 'failed');</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > failedCount: failedSubsections.length,</span>
- <span class="cstat-no" title="statement not covered" > failedChapters: failedSubsections.map(c => ({</span>
- <span class="cstat-no" title="statement not covered" > id: c.id,</span>
- <span class="cstat-no" title="statement not covered" > number: c.number,</span>
- <span class="cstat-no" title="statement not covered" > title: c.title,</span>
- <span class="cstat-no" title="statement not covered" > level: c.level,</span>
- <span class="cstat-no" title="statement not covered" > errorMsg: c.errorMsg,</span>
- <span class="cstat-no" title="statement not covered" > parentId: c.parentId,</span>
- <span class="cstat-no" title="statement not covered" > })),</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('获取失败小节失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '获取失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/resume
- * 从断点处继续生成(重试失败的小节)
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/resume', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (book.genStage === 'video_completed') {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍已生成完成,无需继续' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取失败的小节
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
- <span class="cstat-no" title="statement not covered" > const failedSubsections = chapters.filter(c => c.genStage === 'failed');</span>
-
- <span class="cstat-no" title="statement not covered" > if (failedSubsections.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '没有失败的小节需要重试' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 重置失败小节的状态为 pending
- <span class="cstat-no" title="statement not covered" > for (const sub of failedSubsections) {</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(sub.id, {</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'idle',</span>
- <span class="cstat-no" title="statement not covered" > errorMsg: null,</span>
- <span class="cstat-no" title="statement not covered" > content: null,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 直接重新生成(跳过队列)
- <span class="cstat-no" title="statement not covered" > const { langGraphGenerator } = await import('./index.js');</span>
- <span class="cstat-no" title="statement not covered" > langGraphGenerator.generate(</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > book.description || book.title,</span>
- <span class="cstat-no" title="statement not covered" > book.bookScale || '1000'</span>
- <span class="cstat-no" title="statement not covered" > ).then(() => {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[LangGraph] 续生成完成: bookId=${bookId}`);</span>
- <span class="cstat-no" title="statement not covered" > }).catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[LangGraph] 续生成失败: bookId=${bookId}`, err);</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: `已重启生成,将重试 ${failedSubsections.length} 个失败的小节`,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > retryCount: failedSubsections.length,</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'resuming',</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('继续生成失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '继续生成失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/retry-chapter
- * 单独重试某个失败的小节
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/retry-chapter', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const { chapterId } = ctx.request.body as { chapterId: number };</span>
-
- <span class="cstat-no" title="statement not covered" > if (!chapterId) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '请提供章节 ID' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取所有章节查找指定的章节
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
- <span class="cstat-no" title="statement not covered" > const chapter = chapters.find(c => c.id === chapterId);</span>
- <span class="cstat-no" title="statement not covered" > if (!chapter) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 重置章节状态
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(chapterId, {</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'idle',</span>
- <span class="cstat-no" title="statement not covered" > errorMsg: null,</span>
- <span class="cstat-no" title="statement not covered" > content: null,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '章节已重置为待生成状态',</span>
- <span class="cstat-no" title="statement not covered" > data: { chapterId },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('重试章节失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '重试失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/full-content
- * 获取完整书籍内容(所有章节内容合并)
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/full-content', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 按层级和顺序构建内容
- <span class="cstat-no" title="statement not covered" > let fullContent = `# ${book.title}\n\n`;</span>
- <span class="cstat-no" title="statement not covered" > if (book.description) {</span>
- <span class="cstat-no" title="statement not covered" > fullContent += `## 简介\n${book.description}\n\n`;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 递归添加章节内容
- <span class="cstat-no" title="statement not covered" > const addChapterContent = (chapter: any, indent: string = '') => {</span>
- <span class="cstat-no" title="statement not covered" > if (chapter.content && chapter.genStage === 'content_completed') {</span>
- <span class="cstat-no" title="statement not covered" > fullContent += `${indent}${chapter.number}. ${chapter.title}\n\n`;</span>
- <span class="cstat-no" title="statement not covered" > fullContent += chapter.content + '\n\n';</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- // 处理子章节
- <span class="cstat-no" title="statement not covered" > const children = chapters.filter((c: any) => c.parentId === chapter.id);</span>
- <span class="cstat-no" title="statement not covered" > children.forEach(child => {</span>
- <span class="cstat-no" title="statement not covered" > addChapterContent(child, indent + ' ');</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- // 添加一级章节
- <span class="cstat-no" title="statement not covered" > const level1Chapters = chapters.filter((c: any) => c.level === 1);</span>
- <span class="cstat-no" title="statement not covered" > level1Chapters.forEach(chapter => addChapterContent(chapter));</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > title: book.title,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters: level1Chapters.length,</span>
- <span class="cstat-no" title="statement not covered" > content: fullContent,</span>
- <span class="cstat-no" title="statement not covered" > wordCount: book.estimatedWords,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('获取完整内容失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '获取失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/outline
- * 生成书籍大纲
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/outline', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 检查是否已经有大纲
- <span class="cstat-no" title="statement not covered" > if (book.outline && book.outline.chapters && book.outline.chapters.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '大纲已存在,无需重复生成',</span>
- <span class="cstat-no" title="statement not covered" > data: { outline: book.outline },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取书籍类型配置
- <span class="cstat-no" title="statement not covered" > const scaleConfig = getScaleConfig(book.bookScale || '1000');</span>
-
- // 调用AI生成大纲
- <span class="cstat-no" title="statement not covered" > const { generateOutline } = await import('./index.js');</span>
- <span class="cstat-no" title="statement not covered" > const outline = await generateOutline(bookId, book.description, book.bookScale || '1000');</span>
-
- // 更新书籍的大纲
- <span class="cstat-no" title="statement not covered" > await bookStore.update(bookId, { outline });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '大纲生成成功',</span>
- <span class="cstat-no" title="statement not covered" > data: { outline },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('生成大纲失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '生成大纲失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/chapters
- * 生成单个章节(或全部章节,取决于参数)
- * body: { chapterNumber?: number } - 如果不传chapterNumber,则生成全部
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/chapters', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const body = ctx.request.body as { chapterNumber?: number };</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 如果指定了章节号,只生成单个章节
- <span class="cstat-no" title="statement not covered" > if (body.chapterNumber) {</span>
- // 检查章节是否存在
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
- <span class="cstat-no" title="statement not covered" > const targetChapter = chapters.find((c: any) => c.number === body.chapterNumber);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!targetChapter) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: `章节 ${body.chapterNumber} 不存在` };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 异步生成章节内容
- <span class="cstat-no" title="statement not covered" > bookStore.generateSingleChapterContent(bookId, targetChapter.id).catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Generate Chapter] 章节${body.chapterNumber}生成失败:`, err);</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: `章节 ${body.chapterNumber} 生成任务已启动`,</span>
- <span class="cstat-no" title="statement not covered" > data: { chapterId: targetChapter.id, chapterNumber: body.chapterNumber },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } else {</span>
- // 没有指定章节号,触发整本书生成
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '请使用 /generate 接口生成整本书',</span>
- <span class="cstat-no" title="statement not covered" > data: { hint: '使用 POST /books/:id/generate' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('生成章节失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '生成章节失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/foreword
- * 生成前言
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/foreword', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 调用LLM生成前言
- <span class="cstat-no" title="statement not covered" > const messages: ChatMessage[] = [</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'system',</span>
- <span class="cstat-no" title="statement not covered" > content: `你是一位专业的图书作者。请根据以下信息为书籍生成前言(前言通常介绍写作背景、目标读者、内容概要)。</span>
- 要求:
- 1. 字数控制在300-500字
- 2. 语言正式但亲切
- 3. 不要使用 markdown 格式,直接输出纯文本
-
- 输出格式:
- 直接输出前言内容,不要包含任何标记。`,
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'user',</span>
- <span class="cstat-no" title="statement not covered" > content: `书籍信息:</span>
- <span class="cstat-no" title="statement not covered" >- 书名:${book.title}</span>
- <span class="cstat-no" title="statement not covered" >- 描述:${book.description}</span>
- <span class="cstat-no" title="statement not covered" >- 目标读者:${book.targetAudience || '普通读者'}</span>
- <span class="cstat-no" title="statement not covered" >- 风格:${book.style || '专业'}</span>
-
- 请生成这本书的前言。`,
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > ];</span>
-
- <span class="cstat-no" title="statement not covered" > const foreword = await callLLMWithMessages(messages);</span>
-
- // 更新书籍前言字段
- <span class="cstat-no" title="statement not covered" > await bookStore.update(bookId, { foreword });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '前言生成成功',</span>
- <span class="cstat-no" title="statement not covered" > data: { foreword },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('生成前言失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '生成前言失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/afterword
- * 生成后记
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/afterword', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 调用LLM生成后记
- <span class="cstat-no" title="statement not covered" > const messages: ChatMessage[] = [</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'system',</span>
- <span class="cstat-no" title="statement not covered" > content: `你是一位专业的图书作者。请为书籍生成后记(后记通常总结全书核心观点、分享写作心得、感谢读者)。</span>
- 要求:
- 1. 字数控制在300-500字
- 2. 语言真挚、诚恳
- 3. 不要使用 markdown 格式,直接输出纯文本
-
- 输出格式:
- 直接输出后记内容,不要包含任何标记。`,
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > {</span>
- <span class="cstat-no" title="statement not covered" > role: 'user',</span>
- <span class="cstat-no" title="statement not covered" > content: `书籍信息:</span>
- <span class="cstat-no" title="statement not covered" >- 书名:${book.title}</span>
- <span class="cstat-no" title="statement not covered" >- 描述:${book.description}</span>
- <span class="cstat-no" title="statement not covered" >- 章节数:${book.totalChapters}</span>
- <span class="cstat-no" title="statement not covered" >- 总字数:约${book.estimatedWords}字</span>
-
- 请生成这本书的后记。`,
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > ];</span>
-
- <span class="cstat-no" title="statement not covered" > const afterword = await callLLMWithMessages(messages);</span>
-
- // 更新书籍后记字段
- <span class="cstat-no" title="statement not covered" > await bookStore.update(bookId, { afterword });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '后记生成成功',</span>
- <span class="cstat-no" title="statement not covered" > data: { afterword },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('生成后记失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '生成后记失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/workflow/:bookId
- * 获取书籍生成工作流状态
- */
- <span class="cstat-no" title="statement not covered" >router.get('/workflow/:bookId', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.bookId as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 分析工作流状态
- <span class="cstat-no" title="statement not covered" > const completedChapters = chapters.filter((c: any) => ['content_completed', 'audio_completed', 'video_completed'].includes(c.genStage)).length;</span>
- <span class="cstat-no" title="statement not covered" > const failedChapters = chapters.filter((c: any) => c.genStage === 'failed').length;</span>
- <span class="cstat-no" title="statement not covered" > const pendingChapters = chapters.filter((c: any) => c.genStage === 'idle' || !c.genStage).length;</span>
- <span class="cstat-no" title="statement not covered" > const generatingChapters = chapters.filter((c: any) => ['content_generating', 'audio_generating', 'video_generating'].includes(c.genStage)).length;</span>
-
- // 确定当前阶段
- <span class="cstat-no" title="statement not covered" > let phase: 'planning' | 'writing' | 'supplement' | 'done' = 'planning';</span>
- <span class="cstat-no" title="statement not covered" > if (['content_generating', 'audio_generating', 'video_generating'].includes(book.genStage)) {</span>
- <span class="cstat-no" title="statement not covered" > phase = 'writing';</span>
- <span class="cstat-no" title="statement not covered" > } else if (completedChapters > 0 && failedChapters === 0) {</span>
- <span class="cstat-no" title="statement not covered" > phase = 'done';</span>
- <span class="cstat-no" title="statement not covered" > } else if (failedChapters > 0) {</span>
- <span class="cstat-no" title="statement not covered" > phase = 'supplement';</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > genStage: book.genStage,</span>
- <span class="cstat-no" title="statement not covered" > phase,</span>
- <span class="cstat-no" title="statement not covered" > progress: book.progress || 0,</span>
- <span class="cstat-no" title="statement not covered" > completedChapters,</span>
- <span class="cstat-no" title="statement not covered" > failedChapters,</span>
- <span class="cstat-no" title="statement not covered" > pendingChapters,</span>
- <span class="cstat-no" title="statement not covered" > generatingChapters,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters: chapters.length,</span>
- <span class="cstat-no" title="statement not covered" > failedChapterIds: chapters.filter((c: any) => c.genStage === 'failed').map((c: any) => c.id),</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('获取工作流状态失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '获取失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/chapters/:chapterId/content
- * 获取指定章节的内容
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/chapters/:chapterId/content', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { id: bookId, chapterId } = ctx.params as { id: string; chapterId: string };</span>
- <span class="cstat-no" title="statement not covered" > const chapterIdNum = parseInt(chapterId);</span>
-
- // 获取书籍
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节
- <span class="cstat-no" title="statement not covered" > const chapter = await prisma.bookChapter.findUnique({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (!chapter) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 检查是否属于该书籍
- <span class="cstat-no" title="statement not covered" > if (chapter.bookId !== parseInt(bookId)) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不属于该书籍' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: 'success',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > id: chapter.id,</span>
- <span class="cstat-no" title="statement not covered" > bookId: chapter.bookId,</span>
- <span class="cstat-no" title="statement not covered" > number: chapter.number,</span>
- <span class="cstat-no" title="statement not covered" > title: chapter.title,</span>
- <span class="cstat-no" title="statement not covered" > content: chapter.content || '',</span>
- <span class="cstat-no" title="statement not covered" > wordCount: chapter.wordCount || 0,</span>
- <span class="cstat-no" title="statement not covered" > genStage: chapter.genStage || null,</span>
- <span class="cstat-no" title="statement not covered" > level: chapter.level,</span>
- <span class="cstat-no" title="statement not covered" > parentId: chapter.parentId,</span>
- <span class="cstat-no" title="statement not covered" > summary: chapter.summary || '',</span>
- <span class="cstat-no" title="statement not covered" > keyPoints: chapter.keyPoints ? JSON.parse(chapter.keyPoints) : [],</span>
- <span class="cstat-no" title="statement not covered" > audioUrl: chapter.audioUrl || '',</span>
- <span class="cstat-no" title="statement not covered" > videoUrl: chapter.videoUrl || '',</span>
- <span class="cstat-no" title="statement not covered" > isPublic: chapter.isPublic || false,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('获取章节内容失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '获取章节内容失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/chapters/:chapterId/content
- * 保存章节内容(手工编辑后保存)
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/chapters/:chapterId/content', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { id: bookId, chapterId } = ctx.params as { id: string; chapterId: string };</span>
- <span class="cstat-no" title="statement not covered" > const chapterIdNum = parseInt(chapterId);</span>
- <span class="cstat-no" title="statement not covered" > const { content } = ctx.request.body as { content: string };</span>
-
- <span class="cstat-no" title="statement not covered" > if (content === undefined) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '内容不能为空' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节
- <span class="cstat-no" title="statement not covered" > const chapter = await prisma.bookChapter.findUnique({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (!chapter) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 检查是否属于该书籍
- <span class="cstat-no" title="statement not covered" > if (chapter.bookId !== parseInt(bookId)) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不属于该书籍' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 计算字数
- <span class="cstat-no" title="statement not covered" > const wordCount = content.replace(/<[^>]*>/g, '').length;</span>
-
- // 更新章节内容
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(chapterIdNum, {</span>
- <span class="cstat-no" title="statement not covered" > content,</span>
- <span class="cstat-no" title="statement not covered" > wordCount,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '保存成功',</span>
- <span class="cstat-no" title="statement not covered" > data: { chapterId: chapterIdNum, wordCount },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('保存章节内容失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '保存章节内容失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/chapters/batch-regenerate
- * 批量重新生成章节内容
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/chapters/batch-regenerate', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { id: bookId } = ctx.params as { id: string };</span>
- <span class="cstat-no" title="statement not covered" > const { chapterIds } = ctx.request.body as { chapterIds: number[] };</span>
-
- <span class="cstat-no" title="statement not covered" > if (!chapterIds || !Array.isArray(chapterIds) || chapterIds.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '请选择要重新生成的章节' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取书籍
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 更新书籍状态为 content_generating,让前端能正确追踪轮询
- <span class="cstat-no" title="statement not covered" > await bookStore.update(bookId, { genStage: 'content_generating' });</span>
-
- // 重置并触发每个选中章节的重新生成
- <span class="cstat-no" title="statement not covered" > for (const chapterId of chapterIds) {</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(chapterId, {</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'idle',</span>
- <span class="cstat-no" title="statement not covered" > content: null,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- // 后台异步执行
- <span class="cstat-no" title="statement not covered" > bookStore.generateSingleChapterContent(bookId, chapterId).catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[BatchRegenerate] 章节${chapterId}内容生成失败:`, err);</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: `已提交 ${chapterIds.length} 个章节的重新生成任务`,</span>
- <span class="cstat-no" title="statement not covered" > data: { count: chapterIds.length },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('批量重新生成章节失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '批量重新生成失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/chapters/batch-delete
- * 批量删除章节
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/chapters/batch-delete', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { id: bookId } = ctx.params as { id: string };</span>
- <span class="cstat-no" title="statement not covered" > const { chapterIds } = ctx.request.body as { chapterIds: number[] };</span>
-
- <span class="cstat-no" title="statement not covered" > if (!chapterIds || !Array.isArray(chapterIds) || chapterIds.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '请选择要删除的章节' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取书籍
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 删除章节(同时会删除子章节,因为没有设置级联删除,需要手动处理)
- // 对于每个要删除的章节,先删除其所有子节点,再删除自身
- <span class="cstat-no" title="statement not covered" > for (const chapterId of chapterIds) {</span>
- // 删除子章节(level > 当前章节)
- <span class="cstat-no" title="statement not covered" > await prisma.bookChapter.deleteMany({</span>
- <span class="cstat-no" title="statement not covered" > where: {</span>
- <span class="cstat-no" title="statement not covered" > bookId: parseInt(bookId),</span>
- <span class="cstat-no" title="statement not covered" > parentId: chapterId,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- // 删除自身
- <span class="cstat-no" title="statement not covered" > await prisma.bookChapter.deleteMany({</span>
- <span class="cstat-no" title="statement not covered" > where: {</span>
- <span class="cstat-no" title="statement not covered" > id: chapterId,</span>
- <span class="cstat-no" title="statement not covered" > bookId: parseInt(bookId),</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: `已删除 ${chapterIds.length} 个章节`,</span>
- <span class="cstat-no" title="statement not covered" > data: { count: chapterIds.length },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('批量删除章节失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '批量删除失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/chapters/:chapterId/regenerate
- * 重新生成指定章节的内容(仅叶节点允许)
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/chapters/:chapterId/regenerate', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { id: bookId, chapterId } = ctx.params as { id: string; chapterId: string };</span>
- <span class="cstat-no" title="statement not covered" > const chapterIdNum = parseInt(chapterId);</span>
-
- // 获取书籍
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节
- <span class="cstat-no" title="statement not covered" > const chapter = await prisma.bookChapter.findUnique({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (!chapter) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 检查是否为叶节点(没有子节点的节点)
- <span class="cstat-no" title="statement not covered" > const childChapters = await prisma.bookChapter.findMany({</span>
- <span class="cstat-no" title="statement not covered" > where: { parentId: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (childChapters.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '只有叶节点(小节)才允许重新生成内容' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 重置章节状态和内容
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(chapterIdNum, {</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'idle',</span>
- <span class="cstat-no" title="statement not covered" > errorMsg: null,</span>
- <span class="cstat-no" title="statement not covered" > content: null,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 直接调用单个章节内容生成(不触发整个书籍生成流程)
- // 在后台异步执行
- <span class="cstat-no" title="statement not covered" > bookStore.generateSingleChapterContent(bookId, chapterIdNum).catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Regenerate] 章节${chapterIdNum}内容生成失败:`, err);</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '章节内容重新生成任务已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: { chapterId: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('重新生成章节失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '重新生成失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/chapters/:chapterId/regenerate-audio
- * 重新生成章节音频(仅叶节点)
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/chapters/:chapterId/regenerate-audio', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { id: bookId, chapterId } = ctx.params as { id: string; chapterId: string };</span>
- <span class="cstat-no" title="statement not covered" > const chapterIdNum = parseInt(chapterId);</span>
-
- // 获取书籍
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节
- <span class="cstat-no" title="statement not covered" > const chapter = await prisma.bookChapter.findUnique({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (!chapter) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 检查是否为叶节点
- <span class="cstat-no" title="statement not covered" > const childChapters = await prisma.bookChapter.findMany({</span>
- <span class="cstat-no" title="statement not covered" > where: { parentId: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (childChapters.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '只有叶节点(小节)才允许重新生成音频' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 检查内容是否已完成(有内容即可重生成音频,content_generating 但 content 已存在也允许)
- <span class="cstat-no" title="statement not covered" > if (!chapter.content || chapter.genStage === 'idle') {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节内容未生成完成,无法生成音频' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 清空现有音频并回退状态
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(chapterIdNum, {</span>
- <span class="cstat-no" title="statement not covered" > audioUrl: '',</span>
- <span class="cstat-no" title="statement not covered" > audioDuration: 0,</span>
- <span class="cstat-no" title="statement not covered" > lrcLyrics: null,</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'content_completed',</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 同时清空父章节的合并音频(因为子节音频变了,合并音频也需要重新生成)
- <span class="cstat-no" title="statement not covered" > if (chapter.parentId) {</span>
- <span class="cstat-no" title="statement not covered" > const parentChapter = await prisma.bookChapter.findUnique({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: chapter.parentId },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (parentChapter?.audioUrl?.includes('_merged')) {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[RegenerateAudio] 清除父章节 ${parentChapter.id} 的合并音频(子节${chapterIdNum}已重新生成)`);</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(parentChapter.id, {</span>
- <span class="cstat-no" title="statement not covered" > audioUrl: '',</span>
- <span class="cstat-no" title="statement not covered" > audioDuration: 0,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- // 如果父章节之上还有更高级的合并音频,也一并清除
- <span class="cstat-no" title="statement not covered" > if (parentChapter.parentId) {</span>
- <span class="cstat-no" title="statement not covered" > const grandParent = await prisma.bookChapter.findUnique({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: parentChapter.parentId },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (grandParent?.audioUrl?.includes('_merged')) {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[RegenerateAudio] 清除祖父章节 ${grandParent.id} 的合并音频`);</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(grandParent.id, {</span>
- <span class="cstat-no" title="statement not covered" > audioUrl: '',</span>
- <span class="cstat-no" title="statement not covered" > audioDuration: 0,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 异步生成新音频
- <span class="cstat-no" title="statement not covered" > bookStore.generateChapterAudioById(chapterIdNum, book.userId || 1);</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '音频重新生成任务已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: { chapterId: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('重新生成音频失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '重新生成音频失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/chapters/:chapterId/video
- * 生成单个章节视频
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/chapters/:chapterId/video', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { id: bookId, chapterId } = ctx.params as { id: string; chapterId: string };</span>
- <span class="cstat-no" title="statement not covered" > const chapterIdNum = parseInt(chapterId);</span>
-
- <span class="cstat-no" title="statement not covered" > const chapter = await prisma.bookChapter.findUnique({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: chapterIdNum },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > if (!chapter) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '章节不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 检查章节是否有音频
- <span class="cstat-no" title="statement not covered" > if (!chapter.audioUrl) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '该章节没有音频,请先生成音频' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 设置视频状态为生成中
- <span class="cstat-no" title="statement not covered" > await advanceChapter(chapterIdNum, 'video_generating');</span>
-
- // 调用视频服务创建视频项目
- <span class="cstat-no" title="statement not covered" > const project = await createVideoProjectFromBook(parseInt(bookId), chapterIdNum);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!project) {</span>
- <span class="cstat-no" title="statement not covered" > await regenerateChapter(chapterIdNum, 'failed');</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '创建视频项目失败' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 异步生成视频
- <span class="cstat-no" title="statement not covered" > generateVideoForProject(project.id)</span>
- <span class="cstat-no" title="statement not covered" > .then(async (result) => {</span>
- <span class="cstat-no" title="statement not covered" > if (result.success) {</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(chapterIdNum, {</span>
- <span class="cstat-no" title="statement not covered" > videoUrl: result.outputUrl,</span>
- <span class="cstat-no" title="statement not covered" > videoDuration: result.duration,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > await advanceChapter(chapterIdNum, 'video_completed');</span>
- <span class="cstat-no" title="statement not covered" > } else {</span>
- <span class="cstat-no" title="statement not covered" > await regenerateChapter(chapterIdNum, 'failed');</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > })</span>
- <span class="cstat-no" title="statement not covered" > .catch(async (err) => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Video] 章节${chapter.number}视频生成失败:`, err);</span>
- <span class="cstat-no" title="statement not covered" > await regenerateChapter(chapterIdNum, 'failed');</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '视频生成任务已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > projectId: project.id,</span>
- <span class="cstat-no" title="statement not covered" > chapterId: String(chapterId),</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('视频生成失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '视频生成失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/videos
- * 批量生成书籍所有章节视频
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/videos', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 动态获取叶节点层级(最大level值)
- <span class="cstat-no" title="statement not covered" > const maxLevel = chapters.length > 0</span>
- <span class="cstat-no" title="statement not covered" > ? Math.max(...chapters.map((c: any) => c.level || 0))</span>
- <span class="cstat-no" title="statement not covered" > : 0;</span>
-
- <span class="cstat-no" title="statement not covered" > if (maxLevel === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '没有章节' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取叶节点(最大level的所有节点)
- <span class="cstat-no" title="statement not covered" > const leafNodes = chapters.filter((c: any) => c.level === maxLevel);</span>
-
- // 过滤出有音频的叶节点
- <span class="cstat-no" title="statement not covered" > const leafNodesWithAudio = leafNodes.filter((c: any) => c.audioUrl && c.audioUrl !== '');</span>
-
- <span class="cstat-no" title="statement not covered" > const leafTypeName = maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节';</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodes.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: `没有${leafTypeName}` };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodesWithAudio.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: `没有音频生成完成的${leafTypeName},请先生成音频`,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > totalSubsections: leafNodes.length,</span>
- <span class="cstat-no" title="statement not covered" > audioCompletedSubsections: 0,</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Video] 书籍 ${bookId} 共有 ${leafNodes.length} 个${leafTypeName},其中 ${leafNodesWithAudio.length} 个音频已生成完成`);</span>
-
- // 异步生成所有叶节点视频
- <span class="cstat-no" title="statement not covered" > const taskId = `video_${bookId}_${Date.now()}`;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Video] 开始批量生成视频: bookId=${bookId}, taskId=${taskId}, 总数=${leafNodesWithAudio.length}`);</span>
-
- <span class="cstat-no" title="statement not covered" > for (const sub of leafNodesWithAudio) {</span>
- // 设置视频状态为生成中
- <span class="cstat-no" title="statement not covered" > await advanceChapter(sub.id, 'video_generating').catch(() => {});</span>
-
- // 异步处理每个章节的视频生成
- <span class="cstat-no" title="statement not covered" > (async () => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Video] 开始生成章节 ${sub.number} 的视频: ${sub.title}`);</span>
-
- // 从书籍章节创建视频项目
- <span class="cstat-no" title="statement not covered" > const project = await createVideoProjectFromBook(</span>
- <span class="cstat-no" title="statement not covered" > parseInt(bookId),</span>
- <span class="cstat-no" title="statement not covered" > sub.id,</span>
- <span class="cstat-no" title="statement not covered" > book.userId || 1</span>
- <span class="cstat-no" title="statement not covered" > );</span>
-
- <span class="cstat-no" title="statement not covered" > if (!project) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Video] 章节 ${sub.number} 视频项目创建失败`);</span>
- <span class="cstat-no" title="statement not covered" > await regenerateChapter(sub.id, 'failed').catch(() => {});</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Video] 章节 ${sub.number} 视频项目创建成功: projectId=${project.id}`);</span>
-
- // 生成视频
- <span class="cstat-no" title="statement not covered" > const result = await generateVideoForProject(project.id);</span>
-
- <span class="cstat-no" title="statement not covered" > if (result.success && result.outputUrl) {</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(sub.id, {</span>
- <span class="cstat-no" title="statement not covered" > videoUrl: result.outputUrl,</span>
- <span class="cstat-no" title="statement not covered" > videoDuration: result.duration,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > await advanceChapter(sub.id, 'video_completed');</span>
- <span class="cstat-no" title="statement not covered" > } else {</span>
- <span class="cstat-no" title="statement not covered" > await regenerateChapter(sub.id, 'failed');</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Video] 章节 ${sub.number} 视频生成异常:`, error);</span>
- <span class="cstat-no" title="statement not covered" > await regenerateChapter(sub.id, 'failed');</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > })();</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '视频生成任务已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > taskId,</span>
- <span class="cstat-no" title="statement not covered" > totalChapters: leafNodesWithAudio.length,</span>
- <span class="cstat-no" title="statement not covered" > totalSubsections: leafNodes.length,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('批量生成视频失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '批量生成视频失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/merge-audio
- * 合并叶节点音频到上级章节
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/merge-audio', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 动态获取叶节点层级(最大level值)
- <span class="cstat-no" title="statement not covered" > const maxLevel = chapters.length > 0</span>
- <span class="cstat-no" title="statement not covered" > ? Math.max(...chapters.map((c: any) => c.level || 0))</span>
- <span class="cstat-no" title="statement not covered" > : 0;</span>
-
- <span class="cstat-no" title="statement not covered" > if (maxLevel <= 1) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍层级不足,无法合并音频' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取叶节点(最大level的所有节点)
- <span class="cstat-no" title="statement not covered" > const leafNodes = chapters.filter((c: any) => c.level === maxLevel);</span>
-
- // 检查所有叶节点是否都有音频
- <span class="cstat-no" title="statement not covered" > const leafNodesWithAudio = leafNodes.filter((c: any) => c.audioUrl && c.audioUrl !== '');</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodes.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: `没有${maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节'}` };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodesWithAudio.length !== leafNodes.length) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: `并非所有${maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节'}都已完成音频生成,无法合并`,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > totalLeafNodes: leafNodes.length,</span>
- <span class="cstat-no" title="statement not covered" > completedAudioNodes: leafNodesWithAudio.length,</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 构建 sectionId → chapterId 映射(3层树需要,2层树直接 parentId 就是 chapterId)
- <span class="cstat-no" title="statement not covered" > const sectionToChapter = new Map<number, number>();</span>
- <span class="cstat-no" title="statement not covered" > if (maxLevel >= 3) {</span>
- <span class="cstat-no" title="statement not covered" > const sections = chapters.filter((c: any) => c.level === 2);</span>
- <span class="cstat-no" title="statement not covered" > for (const sec of sections) {</span>
- <span class="cstat-no" title="statement not covered" > if (sec.parentId) {</span>
- <span class="cstat-no" title="statement not covered" > sectionToChapter.set(sec.id, sec.parentId);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 按章(level=1)分组叶节点
- <span class="cstat-no" title="statement not covered" > const groupedByChapter: { [key: number]: any[] } = {};</span>
- <span class="cstat-no" title="statement not covered" > const chapterMeta: { [key: number]: any } = {}; // 章的基本信息</span>
- <span class="cstat-no" title="statement not covered" > leafNodesWithAudio.forEach(node => {</span>
- // 找到该叶节点所属的1级章ID
- <span class="cstat-no" title="statement not covered" > let chapterId: number | null = null;</span>
- <span class="cstat-no" title="statement not covered" > if (maxLevel === 2) {</span>
- <span class="cstat-no" title="statement not covered" > chapterId = node.parentId; // level=2叶节点的parentId就是章</span>
- <span class="cstat-no" title="statement not covered" > } else if (maxLevel === 3 && node.parentId) {</span>
- <span class="cstat-no" title="statement not covered" > chapterId = sectionToChapter.get(node.parentId) || null; // 通过节→章映射</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (chapterId) {</span>
- <span class="cstat-no" title="statement not covered" > if (!groupedByChapter[chapterId]) {</span>
- <span class="cstat-no" title="statement not covered" > groupedByChapter[chapterId] = [];</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > groupedByChapter[chapterId].push(node);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 收集各章的元信息
- <span class="cstat-no" title="statement not covered" > for (const ch of chapters) {</span>
- <span class="cstat-no" title="statement not covered" > if (ch.level === 1) {</span>
- <span class="cstat-no" title="statement not covered" > chapterMeta[ch.id] = ch;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const chapterIds = Object.keys(groupedByChapter);</span>
-
- // 对每个章下的叶节点音频进行合并
- <span class="cstat-no" title="statement not covered" > for (const chapterId of chapterIds) {</span>
- <span class="cstat-no" title="statement not covered" > const chId = parseInt(chapterId);</span>
- <span class="cstat-no" title="statement not covered" > const childNodes = groupedByChapter[chId];</span>
- <span class="cstat-no" title="statement not covered" > const chInfo = chapterMeta[chId];</span>
-
- <span class="cstat-no" title="statement not covered" > if (childNodes.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const mergedAudioUrl = await mergeChapterAudios(chId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (mergedAudioUrl) {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Audio] 章 ${chInfo?.number || chId}(${chInfo?.title || ''}) 音频合并完成: ${mergedAudioUrl}`);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Merge Audio] 章 ${chInfo?.number || chId}(${chInfo?.title || ''}) 音频合并失败:`, error);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: `音频合并任务已启动,共处理 ${chapterIds.length} 个章`,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > processedParents: chapterIds.length,</span>
- <span class="cstat-no" title="statement not covered" > totalLeafNodes: leafNodes.length,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('合并音频失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '合并音频失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/merge-video
- * 合并叶节点视频到上级章节
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/merge-video', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id as string;</span>
- <span class="cstat-no" title="statement not covered" > const book = await bookStore.getById(bookId);</span>
-
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取章节树
- <span class="cstat-no" title="statement not covered" > const chapters = await bookStore.getChapterTree(bookId);</span>
-
- // 动态获取叶节点层级(最大level值)
- <span class="cstat-no" title="statement not covered" > const maxLevel = chapters.length > 0</span>
- <span class="cstat-no" title="statement not covered" > ? Math.max(...chapters.map((c: any) => c.level || 0))</span>
- <span class="cstat-no" title="statement not covered" > : 0;</span>
-
- <span class="cstat-no" title="statement not covered" > if (maxLevel <= 1) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍层级不足,无法合并视频' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 获取叶节点(最大level的所有节点)
- <span class="cstat-no" title="statement not covered" > const leafNodes = chapters.filter((c: any) => c.level === maxLevel);</span>
-
- // 检查所有叶节点是否都有视频
- <span class="cstat-no" title="statement not covered" > const leafNodesWithVideo = leafNodes.filter((c: any) => c.videoUrl && c.videoUrl !== '');</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodes.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: `没有${maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节'}` };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (leafNodesWithVideo.length !== leafNodes.length) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 1,</span>
- <span class="cstat-no" title="statement not covered" > message: `并非所有${maxLevel === 3 ? '小节' : maxLevel === 2 ? '节' : '章节'}都已完成视频生成,无法合并`,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > totalLeafNodes: leafNodes.length,</span>
- <span class="cstat-no" title="statement not covered" > completedVideoNodes: leafNodesWithVideo.length,</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 按父节点分组叶节点(通常是1级章节)
- <span class="cstat-no" title="statement not covered" > const groupedByParent: { [key: number]: any[] } = {};</span>
- <span class="cstat-no" title="statement not covered" > leafNodesWithVideo.forEach(node => {</span>
- <span class="cstat-no" title="statement not covered" > if (node.parentId) {</span>
- <span class="cstat-no" title="statement not covered" > if (!groupedByParent[node.parentId]) {</span>
- <span class="cstat-no" title="statement not covered" > groupedByParent[node.parentId] = [];</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > groupedByParent[node.parentId].push(node);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 对每个父节点下的叶节点视频进行合并
- <span class="cstat-no" title="statement not covered" > let totalProcessedParents = 0;</span>
- <span class="cstat-no" title="statement not covered" > for (const parentId in groupedByParent) {</span>
- <span class="cstat-no" title="statement not covered" > const childNodes = groupedByParent[parentId];</span>
- <span class="cstat-no" title="statement not covered" > if (childNodes.length > 0) {</span>
- // 获取父章节信息
- <span class="cstat-no" title="statement not covered" > const parentChapter = chapters.find((c: any) => c.id === parseInt(parentId));</span>
-
- <span class="cstat-no" title="statement not covered" > if (parentChapter) {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- // 调用合并函数
- <span class="cstat-no" title="statement not covered" > const mergedVideoUrl = await mergeChapterVideos(</span>
- <span class="cstat-no" title="statement not covered" > parentChapter,</span>
- <span class="cstat-no" title="statement not covered" > childNodes,</span>
- <span class="cstat-no" title="statement not covered" > book.userId || 1</span>
- <span class="cstat-no" title="statement not covered" > );</span>
-
- <span class="cstat-no" title="statement not covered" > if (mergedVideoUrl) {</span>
- // 更新父章节的视频URL
- <span class="cstat-no" title="statement not covered" > await bookStore.updateChapterById(parentChapter.id, {</span>
- <span class="cstat-no" title="statement not covered" > videoUrl: mergedVideoUrl,</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] 章节 ${parentChapter.number}(${parentChapter.title}) 视频合并完成: ${mergedVideoUrl}`);</span>
- <span class="cstat-no" title="statement not covered" > totalProcessedParents++;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Merge Video] 章节 ${parentChapter.number}(${parentChapter.title}) 视频合并失败:`, error);</span>
- // 不抛出异常,继续处理其他章节
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: `视频合并任务已完成,共处理 ${totalProcessedParents} 个上级章节`,</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > processedParents: totalProcessedParents,</span>
- <span class="cstat-no" title="statement not covered" > totalLeafNodes: leafNodes.length,</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('合并视频失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '合并视频失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * 合并章节视频的辅助函数
- */
- <span class="cstat-no" title="statement not covered" >async function mergeChapterVideos(parentChapter: any, childChapters: any[], userId: number) {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- // 获取项目根目录(假设视频文件存储在特定目录下)
- <span class="cstat-no" title="statement not covered" > const videoDir = path.join(__dirname, '../../../../../../uploads/video');</span>
- <span class="cstat-no" title="statement not covered" > const outputDir = path.join(videoDir, 'merged');</span>
-
- // 确保输出目录存在
- <span class="cstat-no" title="statement not covered" > await fs.mkdir(outputDir, { recursive: true });</span>
-
- // 创建合并文件列表
- <span class="cstat-no" title="statement not covered" > const fileListPath = path.join(videoDir, `merge_list_${parentChapter.id}.txt`);</span>
- <span class="cstat-no" title="statement not covered" > const outputPath = path.join(outputDir, `merged_chapter_${parentChapter.id}_${Date.now()}.mp4`);</span>
-
- // 准备要合并的视频文件路径
- <span class="cstat-no" title="statement not covered" > const videoPaths = [];</span>
- <span class="cstat-no" title="statement not covered" > for (const child of childChapters) {</span>
- <span class="cstat-no" title="statement not covered" > if (child.videoUrl) {</span>
- // 从URL提取文件名
- <span class="cstat-no" title="statement not covered" > const fileName = path.basename(child.videoUrl);</span>
- <span class="cstat-no" title="statement not covered" > const fullPath = path.join(videoDir, fileName);</span>
-
- // 检查文件是否存在
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > await fs.access(fullPath);</span>
- <span class="cstat-no" title="statement not covered" > videoPaths.push(fullPath);</span>
- <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Merge Video] 文件不存在: ${fullPath}`, err);</span>
- <span class="cstat-no" title="statement not covered" > continue; // 跳过不存在的文件</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (videoPaths.length === 0) {</span>
- <span class="cstat-no" title="statement not covered" > throw new Error('没有找到有效的视频文件');</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (videoPaths.length === 1) {</span>
- // 如果只有一个视频,检查格式是否一致
- <span class="cstat-no" title="statement not covered" > const srcExt = videoPaths[0].split('.').pop()?.toLowerCase();</span>
- <span class="cstat-no" title="statement not covered" > const dstExt = outputPath.split('.').pop()?.toLowerCase();</span>
- <span class="cstat-no" title="statement not covered" > if (srcExt !== dstExt) {</span>
- // 格式不同,用 FFmpeg 转码
- <span class="cstat-no" title="statement not covered" > const cmd = `ffmpeg -i "${videoPaths[0]}" -c copy -y "${outputPath}"`;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] 格式不同,转码: ${cmd}`);</span>
- <span class="cstat-no" title="statement not covered" > await execPromise(cmd);</span>
- <span class="cstat-no" title="statement not covered" > } else {</span>
- <span class="cstat-no" title="statement not covered" > await fs.copyFile(videoPaths[0], outputPath);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > const relativePath = outputPath.replace(videoDir, '/uploads/video').replace(/\\/g, '/');</span>
- <span class="cstat-no" title="statement not covered" > return relativePath;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 创建FFmpeg输入列表 - 使用concat协议来合并视频
- <span class="cstat-no" title="statement not covered" > const inputLines = videoPaths.map(videoPath => `file '${videoPath}'`).join('\n');</span>
- <span class="cstat-no" title="statement not covered" > await fs.writeFile(fileListPath, inputLines);</span>
-
- // 使用FFmpeg合并视频 - 更安全的方式,避免编码问题
- // 先尝试简单的copy方式
- <span class="cstat-no" title="statement not covered" > const cmd = `ffmpeg -f concat -safe 0 -i "${fileListPath}" -c copy -avoid_negative_ts make_zero "${outputPath}"`;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] 执行命令: ${cmd}`);</span>
-
- <span class="cstat-no" title="statement not covered" > let result;</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > result = await execPromise(cmd);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] FFmpeg stdout:`, result.stdout);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] FFmpeg stderr:`, result.stderr);</span>
- <span class="cstat-no" title="statement not covered" > } catch (execErr: any) {</span>
- <span class="cstat-no" title="statement not covered" > console.warn(`[Merge Video] copy模式失败,尝试重新编码:`, execErr.message);</span>
- // 如果简单copy失败,尝试重新编码
- <span class="cstat-no" title="statement not covered" > const reencodeCmd = `ffmpeg -f concat -safe 0 -i "${fileListPath}" -c:v libx264 -c:a aac -avoid_negative_ts make_zero "${outputPath}"`;</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] 执行重新编码命令: ${reencodeCmd}`);</span>
- <span class="cstat-no" title="statement not covered" > result = await execPromise(reencodeCmd);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] FFmpeg reencode stdout:`, result.stdout);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Merge Video] FFmpeg reencode stderr:`, result.stderr);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 清理临时文件
- <span class="cstat-no" title="statement not covered" > await fs.unlink(fileListPath).catch(() => {});</span>
-
- // 检查输出文件是否成功创建
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > await fs.access(outputPath);</span>
- <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
- <span class="cstat-no" title="statement not covered" > throw new Error('视频合并后文件未生成');</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 返回相对路径(相对于上传目录)
- <span class="cstat-no" title="statement not covered" > const relativePath = outputPath.replace(videoDir, '/uploads/video').replace(/\\/g, '/');</span>
- <span class="cstat-no" title="statement not covered" > return relativePath;</span>
-
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Merge Video] 合并过程中出错:', error);</span>
- <span class="cstat-no" title="statement not covered" > throw error;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >}</span>
-
- /**
- * DEBUG: 手动触发章节音频生成(强制从content_completed重新开始)
- * POST /api/book-generator/debug/trigger-audio
- */
- <span class="cstat-no" title="statement not covered" >router.post('/debug/trigger-audio', async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const { chapterId } = ctx.request.body as { chapterId?: number };</span>
- <span class="cstat-no" title="statement not covered" > if (!chapterId) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '缺少 chapterId' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 先检查chapter状态,如果是audio_generating但没有audioUrl,说明之前的生成卡住了
- <span class="cstat-no" title="statement not covered" > const chapter = await prisma.bookChapter.findUnique({ where: { id: chapterId } });</span>
- <span class="cstat-no" title="statement not covered" > if (chapter?.genStage === 'audio_generating' && !chapter?.audioUrl) {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[DEBUG] 章节${chapterId}卡在audio_generating无audioUrl,重置到content_completed重新生成`);</span>
- <span class="cstat-no" title="statement not covered" > await prisma.bookChapter.update({ where: { id: chapterId }, data: { genStage: 'content_completed' } });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[DEBUG] 手动触发章节${chapterId}音频生成`);</span>
- <span class="cstat-no" title="statement not covered" > await bookStore.generateChapterAudioById(chapterId);</span>
-
- <span class="cstat-no" title="statement not covered" > const updated = await prisma.bookChapter.findUnique({ where: { id: chapterId } });</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '音频生成已触发',</span>
- <span class="cstat-no" title="statement not covered" > data: { chapterId, genStage: updated?.genStage, audioUrl: updated?.audioUrl },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[DEBUG] 触发音频失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '触发失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
-
- // ============ 交互式生成 API ============
-
- /**
- * POST /api/book-generator/langgraph/books/:id/interactive/plan
- * 异步启动深度规划,前端通过 GET 同名接口轮询结果
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/interactive/plan', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const idNum = parseInt(bookId);</span>
- <span class="cstat-no" title="statement not covered" > const book = await prisma.book.findUnique({ where: { id: idNum } });</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 标记为生成中,立即返回
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: idNum },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'plan_generating' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 构造 minimal state
- <span class="cstat-no" title="statement not covered" > const body = (ctx.request as any).body || {};</span>
- <span class="cstat-no" title="statement not covered" > const userFeedback = body.feedback || '';</span>
- <span class="cstat-no" title="statement not covered" > const initState: any = {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > topic: book.description,</span>
- <span class="cstat-no" title="statement not covered" > bookScale: book.bookScale || '1000',</span>
- <span class="cstat-no" title="statement not covered" > genLevel: (book as any).genLevel || 2,</span>
- <span class="cstat-no" title="statement not covered" > description: book.description,</span>
- <span class="cstat-no" title="statement not covered" > title: book.title,</span>
- <span class="cstat-no" title="statement not covered" > userId: book.userId,</span>
- <span class="cstat-no" title="statement not covered" > completedChapters: [],</span>
- <span class="cstat-no" title="statement not covered" > failedChapters: [],</span>
- <span class="cstat-no" title="statement not covered" > userFeedback,</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 深度规划已启动(异步): bookId=${bookId}${userFeedback ? ', 含用户反馈' : ''}`);</span>
-
- // 异步执行 AI 调用,不阻塞响应
- <span class="cstat-no" title="statement not covered" > setImmediate(async () => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const result = await deepPlanBookNode(initState);</span>
- <span class="cstat-no" title="statement not covered" > const bookPlan = result.bookPlan || '';</span>
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: idNum },</span>
- <span class="cstat-no" title="statement not covered" > data: { bookAnalysis: bookPlan, genStage: 'plan_ready' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 深度规划完成: bookId=${bookId}`);</span>
- <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Interactive] 深度规划失败: bookId=${bookId}`, err);</span>
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: idNum },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'plan_failed', errorMsg: err instanceof Error ? err.message : '规划失败' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '规划已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'plan_generating' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Interactive] plan 启动失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '启动失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/interactive/plan
- * 轮询获取深度规划结果
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/interactive/plan', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const book = await prisma.book.findUnique({ where: { id: parseInt(bookId) } });</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const stage = (book as any).genStage || '';</span>
-
- <span class="cstat-no" title="statement not covered" > if (stage === 'plan_failed') {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, data: { genStage: 'plan_failed', error: (book as any).errorMsg || '规划失败' } };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (stage === 'plan_ready' || book.bookAnalysis) {</span>
- <span class="cstat-no" title="statement not covered" > const bookPlan = book.bookAnalysis || '';</span>
- <span class="cstat-no" title="statement not covered" > let planData: any = null;</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const fixed_json = bookPlan.replace(/\\u000a/g, '\\n').replace(/\\\\/g, '\\');</span>
- <span class="cstat-no" title="statement not covered" > const match = fixed_json.match(/\{[\s\S]*\}/);</span>
- <span class="cstat-no" title="statement not covered" > if (match) planData = JSON.parse(match[0]);</span>
- <span class="cstat-no" title="statement not covered" > } catch (e) { /* ignore */ }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '规划完成',</span>
- <span class="cstat-no" title="statement not covered" > data: { rawPlan: bookPlan, planData, genStage: 'plan_ready' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 还在生成中
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: stage || 'plan_generating' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Interactive] 查询 plan 失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '查询失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * PUT /api/book-generator/langgraph/books/:id/interactive/plan
- * 保存用户修改后的 plan
- */
- <span class="cstat-no" title="statement not covered" >router.put('/books/:id/interactive/plan', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const { plan } = ctx.request.body as { plan: string };</span>
-
- <span class="cstat-no" title="statement not covered" > if (!plan) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: 'plan 不能为空' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: parseInt(bookId) },</span>
- <span class="cstat-no" title="statement not covered" > data: { bookAnalysis: plan },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, message: 'Plan 已保存' };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Interactive] 保存 plan 失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '保存失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/interactive/outline
- * 异步启动大纲生成,前端通过 GET 同名接口轮询结果
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/interactive/outline', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const idNum = parseInt(bookId);</span>
- <span class="cstat-no" title="statement not covered" > const book = await prisma.book.findUnique({ where: { id: idNum } });</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 标记为生成中,立即返回
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: idNum },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'outline_generating' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 构造 state,使用已保存的 plan
- <span class="cstat-no" title="statement not covered" > const initState: any = {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > topic: book.description,</span>
- <span class="cstat-no" title="statement not covered" > bookScale: book.bookScale || '1000',</span>
- <span class="cstat-no" title="statement not covered" > genLevel: (book as any).genLevel || 2,</span>
- <span class="cstat-no" title="statement not covered" > description: book.description,</span>
- <span class="cstat-no" title="statement not covered" > title: book.title,</span>
- <span class="cstat-no" title="statement not covered" > userId: book.userId,</span>
- <span class="cstat-no" title="statement not covered" > bookPlan: book.bookAnalysis || '',</span>
- <span class="cstat-no" title="statement not covered" > completedChapters: [],</span>
- <span class="cstat-no" title="statement not covered" > failedChapters: [],</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 大纲生成已启动(异步): bookId=${bookId}`);</span>
-
- // 异步执行 AI 调用
- <span class="cstat-no" title="statement not covered" > setImmediate(async () => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > await richOutlineNode(initState);</span>
- // richOutlineNode 内部已通过 bookStore.update 写入 outlineJson
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: idNum },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'outline_ready' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 大纲生成完成: bookId=${bookId}`);</span>
- <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Interactive] 大纲生成失败: bookId=${bookId}`, err);</span>
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: idNum },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'outline_failed', errorMsg: err instanceof Error ? err.message : '大纲生成失败' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '大纲生成已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'outline_generating' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Interactive] outline 启动失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '启动失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * GET /api/book-generator/langgraph/books/:id/interactive/outline
- * 轮询获取大纲生成结果
- */
- <span class="cstat-no" title="statement not covered" >router.get('/books/:id/interactive/outline', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const book = await prisma.book.findUnique({ where: { id: parseInt(bookId) } });</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const stage = (book as any).genStage || '';</span>
-
- <span class="cstat-no" title="statement not covered" > if (stage === 'outline_failed') {</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 0, data: { genStage: 'outline_failed', error: (book as any).errorMsg || '大纲生成失败' } };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > if (stage === 'outline_ready' || book.outlineJson) {</span>
- <span class="cstat-no" title="statement not covered" > const outlineJson = book.outlineJson || '';</span>
- <span class="cstat-no" title="statement not covered" > let outlineData: any = null;</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > outlineData = typeof outlineJson === 'string' ? JSON.parse(outlineJson) : outlineJson;</span>
- <span class="cstat-no" title="statement not covered" > } catch (e) { /* ignore */ }</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '大纲生成完成',</span>
- <span class="cstat-no" title="statement not covered" > data: { rawOutline: outlineJson, outlineData, genStage: 'outline_ready' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 还在生成中
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: stage || 'outline_generating' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Interactive] 查询 outline 失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '查询失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * PUT /api/book-generator/langgraph/books/:id/interactive/outline
- * 保存用户修改后的大纲,并重建章节树
- */
- <span class="cstat-no" title="statement not covered" >router.put('/books/:id/interactive/outline', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const { outline } = ctx.request.body as { outline: any };</span>
-
- <span class="cstat-no" title="statement not covered" > if (!outline) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 400;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: 'outline 不能为空' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const outlineStr = typeof outline === 'string' ? outline : JSON.stringify(outline);</span>
-
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: parseInt(bookId) },</span>
- <span class="cstat-no" title="statement not covered" > data: { outlineJson: outlineStr },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // 根据大纲重建章节树(删除旧章节,创建新章节)
- <span class="cstat-no" title="statement not covered" > const chapterData = typeof outline === 'string' ? JSON.parse(outline) : outline;</span>
- <span class="cstat-no" title="statement not covered" > const chapters = chapterData.chapters || [];</span>
-
- // 删除旧章节
- <span class="cstat-no" title="statement not covered" > await prisma.bookChapter.deleteMany({ where: { bookId: parseInt(bookId) } });</span>
-
- // 插入新章节(递归处理章→节→小节)
- <span class="cstat-no" title="statement not covered" > let chapterNumber = 0;</span>
- <span class="cstat-no" title="statement not covered" > async function insertChapters(parentId: number | null, items: any[], level: number) {</span>
- <span class="cstat-no" title="statement not covered" > for (const item of items) {</span>
- <span class="cstat-no" title="statement not covered" > chapterNumber++;</span>
- <span class="cstat-no" title="statement not covered" > const section = await prisma.bookChapter.create({</span>
- <span class="cstat-no" title="statement not covered" > data: {</span>
- <span class="cstat-no" title="statement not covered" > bookId: parseInt(bookId),</span>
- <span class="cstat-no" title="statement not covered" > title: item.title || '未命名章节',</span>
- <span class="cstat-no" title="statement not covered" > summary: item.summary || '',</span>
- <span class="cstat-no" title="statement not covered" > content: '',</span>
- <span class="cstat-no" title="statement not covered" > wordCount: item.estimatedWords || 0,</span>
- <span class="cstat-no" title="statement not covered" > number: chapterNumber,</span>
- <span class="cstat-no" title="statement not covered" > level,</span>
- <span class="cstat-no" title="statement not covered" > parentId,</span>
- <span class="cstat-no" title="statement not covered" > genStage: 'draft',</span>
- <span class="cstat-no" title="statement not covered" > },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- // 递归处理子节点(节、小节)
- <span class="cstat-no" title="statement not covered" > if (item.sections && item.sections.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > await insertChapters(section.id, item.sections, level + 1);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > if (item.subsections && item.subsections.length > 0) {</span>
- <span class="cstat-no" title="statement not covered" > await insertChapters(section.id, item.subsections, level + 1);</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > await insertChapters(null, chapters, 1);</span>
-
- // 更新书籍的章节计数
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: parseInt(bookId) },</span>
- <span class="cstat-no" title="statement not covered" > data: { totalChapters: chapterNumber },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '大纲已保存,章节树已重建',</span>
- <span class="cstat-no" title="statement not covered" > data: { chapterCount: chapterNumber },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Interactive] 保存 outline 失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '保存失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- /**
- * POST /api/book-generator/langgraph/books/:id/interactive/generate
- * 运行并行内容生成 + 连贯性编辑
- */
- <span class="cstat-no" title="statement not covered" >router.post('/books/:id/interactive/generate', optionalAuth, async (ctx: Context) => {</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > const bookId = ctx.params.id;</span>
- <span class="cstat-no" title="statement not covered" > const book = await prisma.book.findUnique({ where: { id: parseInt(bookId) } });</span>
- <span class="cstat-no" title="statement not covered" > if (!book) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 404;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: '书籍不存在' };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- <span class="cstat-no" title="statement not covered" > const userId = book.userId || parseInt(TEST_USER_ID);</span>
-
- // 配额检查
- <span class="cstat-no" title="statement not covered" > const scaleConfig = getScaleConfig(book.bookScale || '1000');</span>
- <span class="cstat-no" title="statement not covered" > const totalWords = scaleConfig.totalWords;</span>
- <span class="cstat-no" title="statement not covered" > const audioQuota = await checkAudioQuota(userId, totalWords);</span>
- <span class="cstat-no" title="statement not covered" > if (!audioQuota.allowed) {</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 403;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: audioQuota.reason };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > }</span>
-
- // 构造 minimal state
- <span class="cstat-no" title="statement not covered" > const initState: any = {</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > topic: book.description,</span>
- <span class="cstat-no" title="statement not covered" > bookScale: book.bookScale || '1000',</span>
- <span class="cstat-no" title="statement not covered" > genLevel: (book as any).genLevel || 2,</span>
- <span class="cstat-no" title="statement not covered" > description: book.description,</span>
- <span class="cstat-no" title="statement not covered" > title: book.title,</span>
- <span class="cstat-no" title="statement not covered" > userId,</span>
- <span class="cstat-no" title="statement not covered" > bookPlan: book.bookAnalysis || '',</span>
- <span class="cstat-no" title="statement not covered" > outline: book.outlineJson || '',</span>
- <span class="cstat-no" title="statement not covered" > completedChapters: [],</span>
- <span class="cstat-no" title="statement not covered" > failedChapters: [],</span>
- <span class="cstat-no" title="statement not covered" > };</span>
-
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 开始并行生成内容: bookId=${bookId}`);</span>
-
- // ===== 直接异步生成(跳过队列) =====
- <span class="cstat-no" title="statement not covered" > const { langGraphGenerator } = await import('./index.js');</span>
- <span class="cstat-no" title="statement not covered" > langGraphGenerator.generate(</span>
- <span class="cstat-no" title="statement not covered" > bookId,</span>
- <span class="cstat-no" title="statement not covered" > book.description,</span>
- <span class="cstat-no" title="statement not covered" > book.bookScale || '1000',</span>
- <span class="cstat-no" title="statement not covered" > (book as any).genLevel || 2</span>
- <span class="cstat-no" title="statement not covered" > ).then(() => {</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 生成完成: bookId=${bookId}`);</span>
- <span class="cstat-no" title="statement not covered" > }).catch(err => {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Interactive] 生成失败: bookId=${bookId}`, err);</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: parseInt(bookId) },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'generating_content' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '内容生成已启动',</span>
- <span class="cstat-no" title="statement not covered" > data: { bookId, genStage: 'generating_content', mode: 'direct' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > return;</span>
- <span class="cstat-no" title="statement not covered" > try {</span>
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: parseInt(bookId) },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'generating_content' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
-
- // Step 1: 并行生成内容
- <span class="cstat-no" title="statement not covered" > const contentResult = await writeChaptersParallelNode(initState);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 并行内容生成完成: bookId=${bookId}`);</span>
-
- // Step 2: 连贯性编辑
- <span class="cstat-no" title="statement not covered" > const mergeState = { ...initState, ...contentResult };</span>
- <span class="cstat-no" title="statement not covered" > await continuityEditNode(mergeState);</span>
- <span class="cstat-no" title="statement not covered" > console.log(`[Interactive] 连贯性编辑完成: bookId=${bookId}`);</span>
-
- <span class="cstat-no" title="statement not covered" > ctx.body = {</span>
- <span class="cstat-no" title="statement not covered" > code: 0,</span>
- <span class="cstat-no" title="statement not covered" > message: '内容生成完成',</span>
- <span class="cstat-no" title="statement not covered" > data: { bookId, genStage: 'completed', mode: 'sync' },</span>
- <span class="cstat-no" title="statement not covered" > };</span>
- <span class="cstat-no" title="statement not covered" > } catch (generateError) {</span>
- <span class="cstat-no" title="statement not covered" > console.error(`[Interactive] 内容生成失败: bookId=${bookId}`, generateError);</span>
- <span class="cstat-no" title="statement not covered" > await prisma.book.update({</span>
- <span class="cstat-no" title="statement not covered" > where: { id: parseInt(bookId) },</span>
- <span class="cstat-no" title="statement not covered" > data: { genStage: 'failed', errorMsg: generateError instanceof Error ? generateError.message : '生成失败' },</span>
- <span class="cstat-no" title="statement not covered" > });</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: generateError instanceof Error ? generateError.message : '生成失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" > } catch (error) {</span>
- <span class="cstat-no" title="statement not covered" > console.error('[Interactive] generate 失败:', error);</span>
- <span class="cstat-no" title="statement not covered" > ctx.status = 500;</span>
- <span class="cstat-no" title="statement not covered" > ctx.body = { code: 1, message: error instanceof Error ? error.message : '生成失败' };</span>
- <span class="cstat-no" title="statement not covered" > }</span>
- <span class="cstat-no" title="statement not covered" >});</span>
-
- <span class="cstat-no" title="statement not covered" >export default router;</span>
- </pre></td></tr></table></pre>
- <div class='push'></div><!-- for sticky footer -->
- </div><!-- /wrapper -->
- <div class='footer quiet pad2 space-top1 center small'>
- Code coverage generated by
- <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
- at 2026-05-19T14:27:48.313Z
- </div>
- <script src="../../prettify.js"></script>
- <script>
- window.onload = function () {
- prettyPrint();
- };
- </script>
- <script src="../../sorter.js"></script>
- <script src="../../block-navigation.js"></script>
- </body>
- </html>
-
|