From 7b0a40c6a910c9af2c89027a32ec16c2749d7065 Mon Sep 17 00:00:00 2001 From: chaxus Date: Thu, 16 Jul 2026 22:22:54 +0800 Subject: [PATCH 01/54] feat: add chapter detection plan and pnpm workspace configuration - Introduced a comprehensive implementation plan for TXT chapter detection and title extraction, detailing the architecture, phases, and acceptance criteria. - Added a new pnpm workspace configuration file to manage build settings for esbuild and unrs-resolver. --- assets/books/JaneEyre/JaneEyre.txt | 76 +- assets/books/camelXiangzi/camelXiangzi.txt | 48 +- assets/books/princekin/princekin.txt | 54 +- .../theThreeKingdoms/theThreeKingdoms.txt | 240 +- .../theWealthOfNations/theWealthOfNations.txt | 128 +- docs/chapter-detection-plan.md | 112 + package.json | 58 +- pnpm-lock.yaml | 3550 +++++++---------- pnpm-workspace.yaml | 3 + 9 files changed, 1864 insertions(+), 2405 deletions(-) create mode 100644 docs/chapter-detection-plan.md create mode 100644 pnpm-workspace.yaml diff --git a/assets/books/JaneEyre/JaneEyre.txt b/assets/books/JaneEyre/JaneEyre.txt index 9da9a90..fb562c9 100755 --- a/assets/books/JaneEyre/JaneEyre.txt +++ b/assets/books/JaneEyre/JaneEyre.txt @@ -34,7 +34,7 @@ I avail myself of the opportunity which a third edition of Jane Eyre affords m This explanation will serve to rectify mistakes which may already have been made, and to prevent future errors. CURRER BELL. April 13th, 1848. -Chapter 1 +Chapter 1 There was no possibility of taking a walk that day. We had been wandering, indeed, in the leafless shrubbery an hour in the morning; but since dinner (Mrs. Reed, when there was no company, dined early) the cold winter wind had brought with it clouds so sombre, and a rain so penetrating, that further out-door exercise was now out of the question. I was glad of it: I never liked long walks, especially on chilly afternoons: dreadful to me was the coming home in the raw twilight, with nipped fingers and toes, and a heart saddened by the chidings of Bessie, the nurse, and humbled by the consciousness of my physical inferiority to Eliza, John, and Georgiana Reed. The said Eliza, John, and Georgiana were now clustered round their mama in the drawing-room: she lay reclined on a sofa by the fireside, and with her darlings about her (for the time neither quarrelling nor crying) looked perfectly happy. Me, she had dispensed from joining the group; saying, She regretted to be under the necessity of keeping me at a distance; but that until she heard from Bessie, and could discover by her own observation, that I was endeavouring in good earnest to acquire a more sociable and childlike disposition, a more attractive and sprightly manner something lighter, franker, more natural, as it were she really must exclude me from privileges intended only for contented, happy, little children. @@ -80,7 +80,7 @@ He ran headlong at me: I felt him grasp my hair and my shoulder: he had closed w Did ever anybody see such a picture of passion! Then Mrs. Reed subjoined Take her away to the red-room, and lock her in there. Four hands were immediately laid upon me, and I was borne upstairs. -Chapter 2 +Chapter 2 I resisted all the way: a new thing for me, and a circumstance which greatly strengthened the bad opinion Bessie and Miss Abbot were disposed to entertain of me. The fact is, I was a trifle beside myself; or rather out of myself, as the French would say: I was conscious that a moment s mutiny had already rendered me liable to strange penalties, and, like any other rebel slave, I felt resolved, in my desperation, to go all lengths. Hold her arms, Miss Abbot: she s like a mad cat. For shame! for shame! cried the lady s-maid. What shocking conduct, Miss Eyre, to strike a young gentleman, your benefactress s son! Your young master. @@ -124,7 +124,7 @@ A singular notion dawned upon me. I doubted not never doubted that if Mr. Reed O aunt! have pity! Forgive me! I cannot endure it let me be punished some other way! I shall be killed if Silence! This violence is all most repulsive: and so, no doubt, she felt it. I was a precocious actress in her eyes; she sincerely looked on me as a compound of virulent passions, mean spirit, and dangerous duplicity. Bessie and Abbot having retreated, Mrs. Reed, impatient of my now frantic anguish and wild sobs, abruptly thrust me back and locked me in, without farther parley. I heard her sweeping away; and soon after she was gone, I suppose I had a species of fit: unconsciousness closed the scene. -Chapter 3 +Chapter 3 The next thing I remember is, waking up with a feeling as if I had had a frightful nightmare, and seeing before me a terrible red glare, crossed with thick black bars. I heard voices, too, speaking with a hollow sound, and as if muffled by a rush of wind or water: agitation, uncertainty, and an all-predominating sense of terror confused my faculties. Ere long, I became aware that some one was handling me; lifting me up and supporting me in a sitting posture, and that more tenderly than I had ever been raised or upheld before. I rested my head against a pillow or an arm, and felt easy. In five minutes more the cloud of bewilderment dissolved: I knew quite well that I was in my own bed, and that the red glare was the nursery fire. It was night: a candle burnt on the table; Bessie stood at the bed-foot with a basin in her hand, and a gentleman sat in a chair near my pillow, leaning over me. I felt an inexpressible relief, a soothing conviction of protection and security, when I knew that there was a stranger in the room, an individual not belonging to Gateshead., and not related to Mrs. Reed. Turning from Bessie (though her presence was far less obnoxious to me than that of Abbot, for instance, would have been), I scrutinised the face of the gentleman: I knew him; it was Mr. Lloyd, an apothecary, sometimes called in by Mrs. Reed when the servants were ailing: for herself and the children she employed a physician. @@ -230,7 +230,7 @@ Bessie, when she heard this narrative, sighed and said, Poor Miss Jane is to be Not a great deal, to be sure, agreed Bessie: at any rate, a beauty like Miss Georgiana would be more moving in the same condition. Yes, I doat on Miss Georgiana! cried the fervent Abbot. Little darling! with her long curls and her blue eyes, and such a sweet colour as she has; just as if she were painted! Bessie, I could fancy a Welsh rabbit for supper. So could I with a roast onion. Come, we ll go down. They went. -Chapter 4 +Chapter 4 From my discourse with Mr. Lloyd, and from the above reported conference between Bessie and Abbot, I gathered enough of hope to suffice as a motive for wishing to get well: a change seemed near, I desired and waited it in silence. It tarried, however: days and weeks passed: I had regained my normal state of health, but no new allusion was made to the subject over which I brooded. Mrs. Reed surveyed me at times with a severe eye, but seldom addressed me: since my illness, she had drawn a more marked line of separation than ever between me and her own children; appointing me a small closet to sleep in by myself, condemning me to take my meals alone, and pass all my time in the nursery, while my cousins were constantly in the drawing-room. Not a hint, however, did she drop about sending me to school: still I felt an instinctive certainty that she would not long endure me under the same roof with her; for her glance, now more than ever, when turned on me, expressed an insuperable and rooted aversion. Eliza and Georgiana, evidently acting according to orders, spoke to me as little as possible: John thrust his tongue in his cheek whenever he saw me, and once attempted chastisement; but as I instantly turned against him, roused by the same sentiment of deep ire and desperate revolt which had stirred my corruption before, he thought it better to desist, and ran from me tittering execrations, and vowing I had burst his nose. I had indeed levelled at that prominent feature as hard a blow as my knuckles could inflict; and when I saw that either that or my look daunted him, I had the greatest inclination to follow up my advantage to purpose; but he was already with his mama. I heard him in a blubbering tone commence the tale of how that nasty Jane Eyre had flown at him like a mad cat: he was stopped rather harshly Don t talk to me about her, John: I told you not to go near her; she is not worthy of notice; I do not choose that either you or your sisters should associate with her. @@ -354,7 +354,7 @@ I nodded. Not at all, Bessie; indeed, just now I m rather sorry. Just now! and rather! How coolly my little lady says it! I dare say now if I were to ask you for a kiss you wouldn t give it me: you d say you d rather not. I ll kiss you and welcome: bend your head down. Bessie stooped; we mutually embraced, and I followed her into the house quite comforted. That afternoon lapsed in peace and harmony; and in the evening Bessie told me some of her most enchaining stories, and sang me some of her sweetest songs. Even for me life had its gleams of sunshine. -Chapter 5 +Chapter 5 Five o clock had hardly struck on the morning of the 19th of January, when Bessie brought a candle into my closet and found me already up and nearly dressed. I had risen half-an-hour before her entrance, and had washed my face, and put on my clothes by the light of a half-moon just setting, whose rays streamed through the narrow window near my crib. I was to leave Gateshead that day by a coach which passed the lodge gates at six a.m. Bessie was the only person yet risen; she had lit a fire in the nursery, where she now proceeded to make my breakfast. Few children can eat when excited with the thoughts of a journey; nor could I. Bessie, having pressed me in vain to take a few spoonfuls of the boiled milk and bread she had prepared for me, wrapped up some biscuits in a paper and put them into my bag; then she helped me on with my pelisse and bonnet, and wrapping herself in a shawl, she and I left the nursery. As we passed Mrs. Reed s bedroom, she said, Will you go in and bid Missis good-bye? No, Bessie: she came to my crib last night when you were gone down to supper, and said I need not disturb her in the morning, or my cousins either; and she told me to remember that she had always been my best friend, and to speak of her and be grateful to her accordingly. What did you say, Miss? @@ -466,7 +466,7 @@ But at that moment the summons sounded for dinner; all re-entered the house. The After dinner, we immediately adjourned to the schoolroom: lessons recommenced, and were continued till five o clock. The only marked event of the afternoon was, that I saw the girl with whom I had conversed in the verandah dismissed in disgrace by Miss Scatcherd from a history class, and sent to stand in the middle of the large schoolroom. The punishment seemed to me in a high degree ignominious, especially for so great a girl she looked thirteen or upwards. I expected she would show signs of great distress and shame; but to my surprise she neither wept nor blushed: composed, though grave, she stood, the central mark of all eyes. How can she bear it so quietly so firmly? I asked of myself. Were I in her place, it seems to me I should wish the earth to open and swallow me up. She looks as if she were thinking of something beyond her punishment beyond her situation: of something not round her nor before her. I have heard of day-dreams is she in a day-dream now? Her eyes are fixed on the floor, but I am sure they do not see it her sight seems turned in, gone down into her heart: she is looking at what she can remember, I believe; not at what is really present. I wonder what sort of a girl she is whether good or naughty. Soon after five p.m. we had another meal, consisting of a small mug of coffee, and half-a-slice of brown bread. I devoured my bread and drank my coffee with relish; but I should have been glad of as much more I was still hungry. Half-an-hour s recreation succeeded, then study; then the glass of water and the piece of oat-cake, prayers, and bed. Such was my first day at Lowood. -Chapter 6 +Chapter 6 The next day commenced as before, getting up and dressing by rushlight; but this morning we were obliged to dispense with the ceremony of washing; the water in the pitchers was frozen. A change had taken place in the weather the preceding evening, and a keen north-east wind, whistling through the crevices of our bedroom windows all night long, had made us shiver in our beds, and turned the contents of the ewers to ice. Before the long hour and a half of prayers and Bible-reading was over, I felt ready to perish with cold. Breakfast-time came at last, and this morning the porridge was not burnt; the quality was eatable, the quantity small. How small my portion seemed! I wished it had been doubled. In the course of the day I was enrolled a member of the fourth class, and regular tasks and occupations were assigned me: hitherto, I had only been a spectator of the proceedings at Lowood; I was now to become an actor therein. At first, being little accustomed to learn by heart, the lessons appeared to me both long and difficult; the frequent change from task to task, too, bewildered me; and I was glad when, about three o clock in the afternoon, Miss Smith put into my hands a border of muslin two yards long, together with needle, thimble, &c., and sent me to sit in a quiet corner of the schoolroom, with directions to hem the same. At that hour most of the others were sewing likewise; but one class still stood round Miss Scatcherd s chair reading, and as all was quiet, the subject of their lessons could be heard, together with the manner in which each girl acquitted herself, and the animadversions or commendations of Miss Scatcherd on the performance. It was English history: among the readers I observed my acquaintance of the verandah: at the commencement of the lesson, her place had been at the top of the class, but for some error of pronunciation, or some inattention to stops, she was suddenly sent to the very bottom. Even in that obscure position, Miss Scatcherd continued to make her an object of constant notice: she was continually addressing to her such phrases as the following: @@ -532,7 +532,7 @@ Helen heard me patiently to the end: I expected she would then make a remark, bu Helen s head, always drooping, sank a little lower as she finished this sentence. I saw by her look she wished no longer to talk to me, but rather to converse with her own thoughts. She was not allowed much time for meditation: a monitor, a great rough girl, presently came up, exclaiming in a strong Cumberland accent Helen Burns, if you don t go and put your drawer in order, and fold up your work this minute, I ll tell Miss Scatcherd to come and look at it! Helen sighed as her reverie fled, and getting up, obeyed the monitor without reply as without delay. -Chapter 7 +Chapter 7 My first quarter at Lowood seemed an age; and not the golden age either; it comprised an irksome struggle with difficulties in habituating myself to new rules and unwonted tasks. The fear of failure in these points harassed me worse than the physical hardships of my lot; though these were no trifles. During January, February, and part of March, the deep snows, and, after their melting, the almost impassable roads, prevented our stirring beyond the garden walls, except to go to church; but within these limits we had to pass an hour every day in the open air. Our clothing was insufficient to protect us from the severe cold: we had no boots, the snow got into our shoes and melted there: our ungloved hands became numbed and covered with chilblains, as were our feet: I remember well the distracting irritation I endured from this cause every evening, when my feet inflamed; and the torture of thrusting the swelled, raw, and stiff toes into my shoes in the morning. Then the scanty supply of food was distressing: with the keen appetites of growing children, we had scarcely sufficient to keep alive a delicate invalid. From this deficiency of nourishment resulted an abuse, which pressed hardly on the younger pupils: whenever the famished great girls had an opportunity, they would coax or menace the little ones out of their portion. Many a time I have shared between two claimants the precious morsel of brown bread distributed at tea-time; and after relinquishing to a third half the contents of my mug of coffee, I have swallowed the remainder with an accompaniment of secret tears, forced from me by the exigency of hunger. Sundays were dreary days in that wintry season. We had to walk two miles to Brocklebridge Church, where our patron officiated. We set out cold, we arrived at church colder: during the morning service we became almost paralysed. It was too far to return to dinner, and an allowance of cold meat and bread, in the same penurious proportion observed in our ordinary meals, was served round between the services. @@ -588,7 +588,7 @@ Now came a pause of ten minutes, during which I, by this time in perfect possess With this sublime conclusion, Mr. Brocklehurst adjusted the top button of his surtout, muttered something to his family, who rose, bowed to Miss Temple, and then all the great people sailed in state from the room. Turning at the door, my judge said Let her stand half-an-hour longer on that stool, and let no one speak to her during the remainder of the day. There was I, then, mounted aloft; I, who had said I could not bear the shame of standing on my natural feet in the middle of the room, was now exposed to general view on a pedestal of infamy. What my sensations were no language can describe; but just as they all rose, stifling my breath and constricting my throat, a girl came up and passed me: in passing, she lifted her eyes. What a strange light inspired them! What an extraordinary sensation that ray sent through me! How the new feeling bore me up! It was as if a martyr, a hero, had passed a slave or victim, and imparted strength in the transit. I mastered the rising hysteria, lifted up my head, and took a firm stand on the stool. Helen Burns asked some slight question about her work of Miss Smith, was chidden for the triviality of the inquiry, returned to her place, and smiled at me as she again went by. What a smile! I remember it now, and I know that it was the effluence of fine intellect, of true courage; it lit up her marked lineaments, her thin face, her sunken grey eye, like a reflection from the aspect of an angel. Yet at that moment Helen Burns wore on her arm the untidy badge; scarcely an hour ago I had heard her condemned by Miss Scatcherd to a dinner of bread and water on the morrow because she had blotted an exercise in copying it out. Such is the imperfect nature of man! such spots are there on the disc of the clearest planet; and eyes like Miss Scatcherd s can only see those minute defects, and are blind to the full brightness of the orb. -Chapter 8 +Chapter 8 Ere the half-hour ended, five o clock struck; school was dismissed, and all were gone into the refectory to tea. I now ventured to descend: it was deep dusk; I retired into a corner and sat down on the floor. The spell by which I had been so far supported began to dissolve; reaction took place, and soon, so overwhelming was the grief that seized me, I sank prostrate with my face to the ground. Now I wept: Helen Burns was not here; nothing sustained me; left to myself I abandoned myself, and my tears watered the boards. I had meant to be so good, and to do so much at Lowood: to make so many friends, to earn respect and win affection. Already I had made visible progress: that very morning I had reached the head of my class; Miss Miller had praised me warmly; Miss Temple had smiled approbation; she had promised to teach me drawing, and to let me learn French, if I continued to make similar improvement two months longer: and then I was well received by my fellow-pupils; treated as an equal by those of my own age, and not molested by any; now, here I lay again crushed and trodden on; and could I ever rise more? Never, I thought; and ardently I wished to die. While sobbing out this wish in broken accents, some one approached: I started up again Helen Burns was near me; the fading fires just showed her coming up the long, vacant room; she brought my coffee and bread. Come, eat something, she said; but I put both away from me, feeling as if a drop or a crumb would have choked me in my present condition. Helen regarded me, probably with surprise: I could not now abate my agitation, though I tried hard; I continued to weep aloud. She sat down on the ground near me, embraced her knees with her arms, and rested her head upon them; in that attitude she remained silent as an Indian. I was the first who spoke @@ -651,7 +651,7 @@ About a week subsequently to the incidents above narrated, Miss Temple, who had Thus relieved of a grievous load, I from that hour set to work afresh, resolved to pioneer my way through every difficulty: I toiled hard, and my success was proportionate to my efforts; my memory, not naturally tenacious, improved with practice; exercise sharpened my wits; in a few weeks I was promoted to a higher class; in less than two months I was allowed to commence French and drawing. I learned the first two tenses of the verb etre, and sketched my first cottage (whose walls, by-the-bye, outrivalled in slope those of the leaning tower of Pisa), on the same day. That night, on going to bed, I forgot to prepare in imagination the Barmecide supper of hot roast potatoes, or white bread and new milk, with which I was wont to amuse my inward cravings: I feasted instead on the spectacle of ideal drawings, which I saw in the dark; all the work of my own hands: freely pencilled houses and trees, picturesque rocks and ruins, Cuyp-like groups of cattle, sweet paintings of butterflies hovering over unblown roses, of birds picking at ripe cherries, of wren s nests enclosing pearl-like eggs, wreathed about with young ivy sprays. I examined, too, in thought, the possibility of my ever being able to translate currently a certain little French story which Madame Pierrot had that day shown me; nor was that problem solved to my satisfaction ere I fell sweetly asleep. Well has Solomon said Better is a dinner of herbs where love is, than a stalled ox and hatred therewith. I would not now have exchanged Lowood with all its privations for Gateshead and its daily luxuries. -Chapter 9 +Chapter 9 But the privations, or rather the hardships, of Lowood lessened. Spring drew on: she was indeed already come; the frosts of winter had ceased; its snows were melted, its cutting winds ameliorated. My wretched feet, flayed and swollen to lameness by the sharp air of January, began to heal and subside under the gentler breathings of April; the nights and mornings no longer by their Canadian temperature froze the very blood in our veins; we could now endure the play-hour passed in the garden: sometimes on a sunny day it began even to be pleasant and genial, and a greenness grew over those brown beds, which, freshening daily, suggested the thought that Hope traversed them at night, and left each morning brighter traces of her steps. Flowers peeped out amongst the leaves; snow-drops, crocuses, purple auriculas, and golden-eyed pansies. On Thursday afternoons (half-holidays) we now took walks, and found still sweeter flowers opening by the wayside, under the hedges. I discovered, too, that a great pleasure, an enjoyment which the horizon only bounded, lay all outside the high and spike-guarded walls of our garden: this pleasure consisted in prospect of noble summits girdling a great hill-hollow, rich in verdure and shadow; in a bright beck, full of dark stones and sparkling eddies. How different had this scene looked when I viewed it laid out beneath the iron sky of winter, stiffened in frost, shrouded with snow! when mists as chill as death wandered to the impulse of east winds along those purple peaks, and rolled down ing and holm till they blended with the frozen fog of the beck! That beck itself was then a torrent, turbid and curbless: it tore asunder the wood, and sent a raving sound through the air, often thickened with wild rain or whirling sleet; and for the forest on its banks, that showed only ranks of skeletons. April advanced to May: a bright serene May it was; days of blue sky, placid sunshine, and soft western or southern gales filled up its duration. And now vegetation matured with vigour; Lowood shook loose its tresses; it became all green, all flowery; its great elm, ash, and oak skeletons were restored to majestic life; woodland plants sprang up profusely in its recesses; unnumbered varieties of moss filled its hollows, and it made a strange ground-sunshine out of the wealth of its wild primrose plants: I have seen their pale gold gleam in overshadowed spots like scatterings of the sweetest lustre. All this I enjoyed often and fully, free, unwatched, and almost alone: for this unwonted liberty and pleasure there was a cause, to which it now becomes my task to advert. @@ -713,7 +713,7 @@ Again I questioned, but this time only in thought. Where is that region? Does i She kissed me, and I her, and we both soon slumbered. When I awoke it was day: an unusual movement roused me; I looked up; I was in somebody s arms; the nurse held me; she was carrying me through the passage back to the dormitory. I was not reprimanded for leaving my bed; people had something else to think about; no explanation was afforded then to my many questions; but a day or two afterwards I learned that Miss Temple, on returning to her own room at dawn, had found me laid in the little crib; my face against Helen Burns s shoulder, my arms round her neck. I was asleep, and Helen was dead. Her grave is in Brocklebridge churchyard: for fifteen years after her death it was only covered by a grassy mound; but now a grey marble tablet marks the spot, inscribed with her name, and the word Resurgam. -Chapter 10 +Chapter 10 Hitherto I have recorded in detail the events of my insignificant existence: to the first ten years of my life I have given almost as many chapters. But this is not to be a regular autobiography. I am only bound to invoke Memory where I know her responses will possess some degree of interest; therefore I now pass a space of eight years almost in silence: a few lines only are necessary to keep up the links of connection. When the typhus fever had fulfilled its mission of devastation at Lowood, it gradually disappeared from thence; but not till its virulence and the number of its victims had drawn public attention on the school. Inquiry was made into the origin of the scourge, and by degrees various facts came out which excited public indignation in a high degree. The unhealthy nature of the site; the quantity and quality of the children s food; the brackish, fetid water used in its preparation; the pupils wretched clothing and accommodations all these things were discovered, and the discovery produced a result mortifying to Mr. Brocklehurst, but beneficial to the institution. Several wealthy and benevolent individuals in the county subscribed largely for the erection of a more convenient building in a better situation; new regulations were made; improvements in diet and clothing introduced; the funds of the school were intrusted to the management of a committee. Mr. Brocklehurst, who, from his wealth and family connections, could not be overlooked, still retained the post of treasurer; but he was aided in the discharge of his duties by gentlemen of rather more enlarged and sympathising minds: his office of inspector, too, was shared by those who knew how to combine reason with strictness, comfort with economy, compassion with uprightness. The school, thus improved, became in time a truly useful and noble institution. I remained an inmate of its walls, after its regeneration, for eight years: six as pupil, and two as teacher; and in both capacities I bear my testimony to its value and importance. @@ -799,7 +799,7 @@ There was one in the room; Bessie went and opened it, and then asked me to sit d Yes; he did not stay many minutes in the house: Missis was very high with him; she called him afterwards a sneaking tradesman. My Robert believes he was a wine-merchant. Very likely, I returned; or perhaps clerk or agent to a wine- merchant. Bessie and I conversed about old times an hour longer, and then she was obliged to leave me: I saw her again for a few minutes the next morning at Lowton, while I was waiting for the coach. We parted finally at the door of the Brocklehurst Arms there: each went her separate way; she set off for the brow of Lowood Fell to meet the conveyance which was to take her back to Gateshead, I mounted the vehicle which was to bear me to new duties and a new life in the unknown environs of Millcote. -Chapter 11 +Chapter 11 A new chapter in a novel is something like a new scene in a play; and when I draw up the curtain this time, reader, you must fancy you see a room in the George Inn at Millcote, with such large figured papering on the walls as inn rooms have; such a carpet, such furniture, such ornaments on the mantelpiece, such prints, including a portrait of George the Third, and another of the Prince of Wales, and a representation of the death of Wolfe. All this is visible to you by the light of an oil lamp hanging from the ceiling, and by that of an excellent fire, near which I sit in my cloak and bonnet; my muff and umbrella lie on the table, and I am warming away the numbness and chill contracted by sixteen hours exposure to the rawness of an October day: I left Lowton at four o clock a.m., and the Millcote town clock is now just striking eight. Reader, though I look comfortably accommodated, I am not very tranquil in my mind. I thought when the coach stopped here there would be some one to meet me; I looked anxiously round as I descended the wooden steps the boots placed for my convenience, expecting to hear my name pronounced, and to see some description of carriage waiting to convey me to Thornfield. Nothing of the sort was visible; and when I asked a waiter if any one had been to inquire after a Miss Eyre, I was answered in the negative: so I had no resource but to request to be shown into a private room: and here I am waiting, while all sorts of doubts and fears are troubling my thoughts. It is a very strange sensation to inexperienced youth to feel itself quite alone in the world, cut adrift from every connection, uncertain whether the port to which it is bound can be reached, and prevented by many impediments from returning to that it has quitted. The charm of adventure sweetens that sensation, the glow of pride warms it; but then the throb of fear disturbs it; and fear with me became predominant when half-an-hour elapsed and still I was alone. I bethought myself to ring the bell. @@ -925,7 +925,7 @@ The door nearest me opened, and a servant came out, a woman of between thirty an The conversation, thus turned on Ad le, continued till we reached the light and cheerful region below. Ad le came running to meet us in the hall, exclaiming Mesdames, vous etes servies! adding, J ai bien faim, moi! We found dinner ready, and waiting for us in Mrs. Fairfax s room. -Chapter 12 +Chapter 12 The promise of a smooth career, which my first calm introduction to Thornfield Hall seemed to pledge, was not belied on a longer acquaintance with the place and its inmates. Mrs. Fairfax turned out to be what she appeared, a placid-tempered, kind-natured woman, of competent education and average intelligence. My pupil was a lively child, who had been spoilt and indulged, and therefore was sometimes wayward; but as she was committed entirely to my care, and no injudicious interference from any quarter ever thwarted my plans for her improvement, she soon forgot her little freaks, and became obedient and teachable. She had no great talents, no marked traits of character, no peculiar development of feeling or taste which raised her one inch above the ordinary level of childhood; but neither had she any deficiency or vice which sunk her below it. She made reasonable progress, entertained for me a vivacious, though perhaps not very profound, affection; and by her simplicity, gay prattle, and efforts to please, inspired me, in return, with a degree of attachment sufficient to make us both content in each other s society. This, par parenth se, will be thought cool language by persons who entertain solemn doctrines about the angelic nature of children, and the duty of those charged with their education to conceive for them an idolatrous devotion: but I am not writing to flatter parental egotism, to echo cant, or prop up humbug; I am merely telling the truth. I felt a conscientious solicitude for Ad le s welfare and progress, and a quiet liking for her little self: just as I cherished towards Mrs. Fairfax a thankfulness for her kindness, and a pleasure in her society proportionate to the tranquil regard she had for me, and the moderation of her mind and character. Anybody may blame me who likes, when I add further, that, now and then, when I took a walk by myself in the grounds; when I went down to the gates and looked through them along the road; or when, while Ad le played with her nurse, and Mrs. Fairfax made jellies in the storeroom, I climbed the three staircases, raised the trap-door of the attic, and having reached the leads, looked out afar over sequestered field and hill, and along dim sky-line that then I longed for a power of vision which might overpass that limit; which might reach the busy world, towns, regions full of life I had heard of but never seen that then I desired more of practical experience than I possessed; more of intercourse with my kind, of acquaintance with variety of character, than was here within my reach. I valued what was good in Mrs. Fairfax, and what was good in Ad le; but I believed in the existence of other and more vivid kinds of goodness, and what I believed in I wished to behold. @@ -995,7 +995,7 @@ I hastened to Mrs. Fairfax s room; there was a fire there too, but no candle, an Yes, coming down-hill; it slipped on some ice. Ah! Bring me a candle will you Leah? Leah brought it; she entered, followed by Mrs. Fairfax, who repeated the news; adding that Mr. Carter the surgeon was come, and was now with Mr. Rochester: then she hurried out to give orders about tea, and I went upstairs to take off my things. -Chapter 13 +Chapter 13 Mr. Rochester, it seems, by the surgeon s orders, went to bed early that night; nor did he rise soon next morning. When he did come down, it was to attend to business: his agent and some of his tenants were arrived, and waiting to speak with him. Ad le and I had now to vacate the library: it would be in daily requisition as a reception-room for callers. A fire was lit in an apartment upstairs, and there I carried our books, and arranged it for the future schoolroom. I discerned in the course of the morning that Thornfield Hall was a changed place: no longer silent as a church, it echoed every hour or two to a knock at the door, or a clang of the bell; steps, too, often traversed the hall, and new voices spoke in different keys below; a rill from the outer world was flowing through it; it had a master: for my part, I liked it better. Ad le was not easy to teach that day; she could not apply: she kept running to the door and looking over the banisters to see if she could get a glimpse of Mr. Rochester; then she coined pretexts to go downstairs, in order, as I shrewdly suspected, to visit the library, where I knew she was not wanted; then, when I got a little angry, and made her sit still, she continued to talk incessantly of her ami, Monsieur Edouard Fairfax de Rochester, as she dubbed him (I had not before heard his prenomens), and to conjecture what presents he had brought her: for it appears he had intimated the night before, that when his luggage came from Millcote, there would be found amongst it a little box in whose contents she had an interest. @@ -1132,7 +1132,7 @@ Ad le went to kiss him before quitting the room: he endured the caress, but scar Why should he shun it? Perhaps he thinks it gloomy. The answer was evasive. I should have liked something clearer; but Mrs. Fairfax either could not, or would not, give me more explicit information of the origin and nature of Mr. Rochester s trials. She averred they were a mystery to herself, and that what she knew was chiefly from conjecture. It was evident, indeed, that she wished me to drop the subject, which I did accordingly. -Chapter 14 +Chapter 14 For several subsequent days I saw little of Mr. Rochester. In the mornings he seemed much engaged with business, and, in the afternoon, gentlemen from Millcote or the neighbourhood called, and sometimes stayed to dine with him. When his sprain was well enough to admit of horse exercise, he rode out a good deal; probably to return these visits, as he generally did not come back till late at night. During this interval, even Ad le was seldom sent for to his presence, and all my acquaintance with him was confined to an occasional rencontre in the hall, on the stairs, or in the gallery, when he would sometimes pass me haughtily and coldly, just acknowledging my presence by a distant nod or a cool glance, and sometimes bow and smile with gentlemanlike affability. His changes of mood did not offend me, because I saw that I had nothing to do with their alternation; the ebb and flow depended on causes quite disconnected with me. One day he had had company to dinner, and had sent for my portfolio; in order, doubtless, to exhibit its contents: the gentlemen went away early, to attend a public meeting at Millcote, as Mrs. Fairfax informed me; but the night being wet and inclement, Mr. Rochester did not accompany them. Soon after they were gone he rang the bell: a message came that I and Ad le were to go downstairs. I brushed Ad le s hair and made her neat, and having ascertained that I was myself in my usual Quaker trim, where there was nothing to retouch all being too close and plain, braided locks included, to admit of disarrangement we descended, Ad le wondering whether the petit coffre was at length come; for, owing to some mistake, its arrival had hitherto been delayed. She was gratified: there it stood, a little carton, on the table when we entered the dining-room. She appeared to know it by instinct. @@ -1241,7 +1241,7 @@ Ere long, Ad le s little foot was heard tripping across the hall. She entered, t And spreading out her dress, she chass ed across the room till, having reached Mr. Rochester, she wheeled lightly round before him on tip-toe, then dropped on one knee at his feet, exclaiming Monsieur, je vous remercie mille fois de votre bont ; then rising, she added, C est comme cela que maman faisait, n est-ce pas, monsieur? Pre-cise-ly! was the answer; and, comme cela, she charmed my English gold out of my British breeches pocket. I have been green, too, Miss Eyre, ay, grass green: not a more vernal tint freshens you now than once freshened me. My Spring is gone, however, but it has left me that French floweret on my hands, which, in some moods, I would fain be rid of. Not valuing now the root whence it sprang; having found that it was of a sort which nothing but gold dust could manure, I have but half a liking to the blossom, especially when it looks so artificial as just now. I keep it and rear it rather on the Roman Catholic principle of expiating numerous sins, great or small, by one good work. I ll explain all this some day. Good- night. -Chapter 15 +Chapter 15 Mr. Rochester did, on a future occasion, explain it. It was one afternoon, when he chanced to meet me and Ad le in the grounds: and while she played with Pilot and her shuttlecock, he asked me to walk up and down a long beech avenue within sight of her. He then said that she was the daughter of a French opera-dancer, C line Varens, towards whom he had once cherished what he called a grande passion. This passion C line had professed to return with even superior ardour. He thought himself her idol, ugly as he was: he believed, as he said, that she preferred his taille d athl te to the elegance of the Apollo Belvidere. And, Miss Eyre, so much was I flattered by this preference of the Gallic sylph for her British gnome, that I installed her in an hotel; gave her a complete establishment of servants, a carriage, cashmeres, diamonds, dentelles, &c. In short, I began the process of ruining myself in the received style, like any other spoony. I had not, it seems, the originality to chalk out a new road to shame and destruction, but trode the old track with stupid exactness not to deviate an inch from the beaten centre. I had as I deserved to have the fate of all other spoonies. Happening to call one evening when C line did not expect me, I found her out; but it was a warm night, and I was tired with strolling through Paris, so I sat down in her boudoir; happy to breathe the air consecrated so lately by her presence. No, I exaggerate; I never thought there was any consecrating virtue about her: it was rather a sort of pastille perfume she had left; a scent of musk and amber, than an odour of sanctity. I was just beginning to stifle with the fumes of conservatory flowers and sprinkled essences, when I bethought myself to open the window and step out on to the balcony. It was moonlight and gaslight besides, and very still and serene. The balcony was furnished with a chair or two; I sat down, and took out a cigar, I will take one now, if you will excuse me. @@ -1318,7 +1318,7 @@ Strange energy was in his voice, strange fire in his look. I think I hear Mrs. Fairfax move, sir, said I. Well, leave me: he relaxed his fingers, and I was gone. I regained my couch, but never thought of sleep. Till morning dawned I was tossed on a buoyant but unquiet sea, where billows of trouble rolled under surges of joy. I thought sometimes I saw beyond its wild waters a shore, sweet as the hills of Beulah; and now and then a freshening gale, wakened by hope, bore my spirit triumphantly towards the bourne: but I could not reach it, even in fancy a counteracting breeze blew off land, and continually drove me back. Sense would resist delirium: judgment would warn passion. Too feverish to rest, I rose as soon as day dawned. -Chapter 16 +Chapter 16 I both wished and feared to see Mr. Rochester on the day which followed this sleepless night: I wanted to hear his voice again, yet feared to meet his eye. During the early part of the morning, I momentarily expected his coming; he was not in the frequent habit of entering the schoolroom, but he did step in for a few minutes sometimes, and I had the impression that he was sure to visit it that day. But the morning passed just as usual: nothing happened to interrupt the quiet course of Ad le s studies; only soon after breakfast, I heard some bustle in the neighbourhood of Mr. Rochester s chamber, Mrs. Fairfax s voice, and Leah s, and the cook s that is, John s wife and even John s own gruff tones. There were exclamations of What a mercy master was not burnt in his bed! It is always dangerous to keep a candle lit at night. How providential that he had presence of mind to think of the water-jug! I wonder he waked nobody! It is to be hoped he will not take cold with sleeping on the library sofa, &c. To much confabulation succeeded a sound of scrubbing and setting to rights; and when I passed the room, in going downstairs to dinner, I saw through the open door that all was again restored to complete order; only the bed was stripped of its hangings. Leah stood up in the window-seat, rubbing the panes of glass dimmed with smoke. I was about to address her, for I wished to know what account had been given of the affair: but, on advancing, I saw a second person in the chamber a woman sitting on a chair by the bedside, and sewing rings to new curtains. That woman was no other than Grace Poole. @@ -1396,7 +1396,7 @@ That a greater fool than Jane Eyre had never breathed the breath of life; that a I ll do it, I resolved: and having framed this determination, I grew calm, and fell asleep. I kept my word. An hour or two sufficed to sketch my own portrait in crayons; and in less than a fortnight I had completed an ivory miniature of an imaginary Blanche Ingram. It looked a lovely face enough, and when compared with the real head in chalk, the contrast was as great as self-control could desire. I derived benefit from the task: it had kept my head and hands employed, and had given force and fixedness to the new impressions I wished to stamp indelibly on my heart. Ere long, I had reason to congratulate myself on the course of wholesome discipline to which I had thus forced my feelings to submit. Thanks to it, I was able to meet subsequent occurrences with a decent calm, which, had they found me unprepared, I should probably have been unequal to maintain, even externally. -Chapter 17 +Chapter 17 A week passed, and no news arrived of Mr. Rochester: ten days, and still he did not come. Mrs. Fairfax said she should not be surprised if he were to go straight from the Leas to London, and thence to the Continent, and not show his face again at Thornfield for a year to come; he had not unfrequently quitted it in a manner quite as abrupt and unexpected. When I heard this, I was beginning to feel a strange chill and failing at the heart. I was actually permitting myself to experience a sickening sense of disappointment; but rallying my wits, and recollecting my principles, I at once called my sensations to order; and it was wonderful how I got over the temporary blunder how I cleared up the mistake of supposing Mr. Rochester s movements a matter in which I had any cause to take a vital interest. Not that I humbled myself by a slavish notion of inferiority: on the contrary, I just said You have nothing to do with the master of Thornfield, further than to receive the salary he gives you for teaching his prot g e, and to be grateful for such respectful and kind treatment as, if you do your duty, you have a right to expect at his hands. Be sure that is the only tie he seriously acknowledges between you and him; so don t make him the object of your fine feelings, your raptures, agonies, and so forth. He is not of your order: keep to your caste, and be too self-respecting to lavish the love of the whole heart, soul, and strength, where such a gift is not wanted and would be despised. I went on with my day s business tranquilly; but ever and anon vague suggestions kept wandering across my brain of reasons why I should quit Thornfield; and I kept involuntarily framing advertisements and pondering conjectures about new situations: these thoughts I did not think check; they might germinate and bear fruit if they could. @@ -1553,7 +1553,7 @@ He looked at me for a minute. And a little depressed, he said. What about? Tell me. Nothing nothing, sir. I am not depressed. But I affirm that you are: so much depressed that a few more words would bring tears to your eyes indeed, they are there now, shining and swimming; and a bead has slipped from the lash and fallen on to the flag. If I had time, and was not in mortal dread of some prating prig of a servant passing, I would know what all this means. Well, to-night I excuse you; but understand that so long as my visitors stay, I expect you to appear in the drawing-room every evening; it is my wish; don t neglect it. Now go, and send Sophie for Ad le. Good-night, my He stopped, bit his lip, and abruptly left me. -Chapter 18 +Chapter 18 Merry days were these at Thornfield Hall; and busy days too: how different from the first three months of stillness, monotony, and solitude I had passed beneath its roof! All sad feelings seemed now driven from the house, all gloomy associations forgotten: there was life everywhere, movement all day long. You could not now traverse the gallery, once so hushed, nor enter the front chambers, once so tenantless, without encountering a smart lady s-maid or a dandy valet. The kitchen, the butler s pantry, the servants hall, the entrance hall, were equally alive; and the saloons were only left void and still when the blue sky and halcyon sunshine of the genial spring weather called their occupants out into the grounds. Even when that weather was broken, and continuous rain set in for some days, no damp seemed cast over enjoyment: indoor amusements only became more lively and varied, in consequence of the stop put to outdoor gaiety. I wondered what they were going to do the first evening a change of entertainment was proposed: they spoke of playing charades, but in my ignorance I did not understand the term. The servants were called in, the dining-room tables wheeled away, the lights otherwise disposed, the chairs placed in a semicircle opposite the arch. While Mr. Rochester and the other gentlemen directed these alterations, the ladies were running up and down stairs ringing for their maids. Mrs. Fairfax was summoned to give information respecting the resources of the house in shawls, dresses, draperies of any kind; and certain wardrobes of the third storey were ransacked, and their contents, in the shape of brocaded and hooped petticoats, satin sacques, black modes, lace lappets, &c., were brought down in armfuls by the abigails; then a selection was made, and such things as were chosen were carried to the boudoir within the drawing-room. @@ -1656,7 +1656,7 @@ In the midst of the tumult, and while my eyes and ears were fully engaged in the Oh, I will go by all means, I answered: and I was glad of the unexpected opportunity to gratify my much-excited curiosity. I slipped out of the room, unobserved by any eye for the company were gathered in one mass about the trembling trio just returned and I closed the door quietly behind me. If you like, miss, said Sam, I ll wait in the hall for you; and if she frightens you, just call and I ll come in. No, Sam, return to the kitchen: I am not in the least afraid. Nor was I; but I was a good deal interested and excited. -Chapter 19 +Chapter 19 The library looked tranquil enough as I entered it, and the Sibyl if Sibyl she were was seated snugly enough in an easy-chair at the chimney-corner. She had on a red cloak and a black bonnet: or rather, a broad-brimmed gipsy hat, tied down with a striped handkerchief under her chin. An extinguished candle stood on the table; she was bending over the fire, and seemed reading in a little black book, like a prayer-book, by the light of the blaze: she muttered the words to herself, as most old women do, while she read; she did not desist immediately on my entrance: it appeared she wished to finish a paragraph. I stood on the rug and warmed my hands, which were rather cold with sitting at a distance from the drawing-room fire. I felt now as composed as ever I did in my life: there was nothing indeed in the gipsy s appearance to trouble one s calm. She shut her book and slowly looked up; her hat-brim partially shaded her face, yet I could see, as she raised it, that it was a strange one. It looked all brown and black: elf-locks bristled out from beneath a white band which passed under her chin, and came half over her cheeks, or rather jaws: her eye confronted me at once, with a bold and direct gaze. Well, and you want your fortune told? she said, in a voice as decided as her glance, as harsh as her features. @@ -1802,7 +1802,7 @@ He half smiled. But if I were to go to them, and they only looked at me coldly, I did his behest. The company all stared at me as I passed straight among them. I sought Mr. Mason, delivered the message, and preceded him from the room: I ushered him into the library, and then I went upstairs. At a late hour, after I had been in bed some time, I heard the visitors repair to their chambers: I distinguished Mr. Rochester s voice, and heard him say, This way, Mason; this is your room. He spoke cheerfully: the gay tones set my heart at ease. I was soon asleep. -Chapter 20 +Chapter 20 I had forgotten to draw my curtain, which I usually did, and also to let down my window-blind. The consequence was, that when the moon, which was full and bright (for the night was fine), came in her course to that space in the sky opposite my casement, and looked in at me through the unveiled panes, her glorious gaze roused me. Awaking in the dead of night, I opened my eyes on her disk silver- white and crystal clear. It was beautiful, but too solemn; I half rose, and stretched my arm to draw the curtain. Good God! What a cry! The night its silence its rest, was rent in twain by a savage, a sharp, a shrilly sound that ran from end to end of Thornfield Hall. @@ -1970,7 +1970,7 @@ He got up instantly, went quite to the other end of the walk, and when he came b A strapper a real strapper, Jane: big, brown, and buxom; with hair just such as the ladies of Carthage must have had. Bless me! there s Dent and Lynn in the stables! Go in by the shrubbery, through that wicket. As I went one way, he went another, and I heard him in the yard, saying cheerfully Mason got the start of you all this morning; he was gone before sunrise: I rose at four to see him off. -Chapter 21 +Chapter 21 Presentiments are strange things! and so are sympathies; and so are signs; and the three combined make one mystery to which humanity has not yet found the key. I never laughed at presentiments in my life, because I have had strange ones of my own. Sympathies, I believe, exist (for instance, between far-distant, long-absent, wholly estranged relatives asserting, notwithstanding their alienation, the unity of the source to which each traces his origin) whose workings baffle mortal comprehension. And signs, for aught we know, may be but the sympathies of Nature with man. When I was a little girl, only six years old, I one night heard Bessie Leaven say to Martha Abbot that she had been dreaming about a little child; and that to dream of children was a sure sign of trouble, either to one s self or one s kin. The saying might have worn out of my memory, had not a circumstance immediately followed which served indelibly to fix it there. The next day Bessie was sent for home to the deathbed of her little sister. Of late I had often recalled this saying and this incident; for during the past week scarcely a night had gone over my couch that had not brought with it a dream of an infant, which I sometimes hushed in my arms, sometimes dandled on my knee, sometimes watched playing with daisies on a lawn, or again, dabbling its hands in running water. It was a wailing child this night, and a laughing one the next: now it nestled close to me, and now it ran from me; but whatever mood the apparition evinced, whatever aspect it wore, it failed not for seven successive nights to meet me the moment I entered the land of slumber. @@ -2166,7 +2166,7 @@ Poor, suffering woman! it was too late for her to make now the effort to change The nurse now entered, and Bessie followed. I yet lingered half-an- hour longer, hoping to see some sign of amity: but she gave none. She was fast relapsing into stupor; nor did her mind again rally: at twelve o clock that night she died. I was not present to close her eyes, nor were either of her daughters. They came to tell us the next morning that all was over. She was by that time laid out. Eliza and I went to look at her: Georgiana, who had burst out into loud weeping, said she dared not go. There was stretched Sarah Reed s once robust and active frame, rigid and still: her eye of flint was covered with its cold lid; her brow and strong traits wore yet the impress of her inexorable soul. A strange and solemn object was that corpse to me. I gazed on it with gloom and pain: nothing soft, nothing sweet, nothing pitying, or hopeful, or subduing did it inspire; only a grating anguish for her woes not my loss and a sombre tearless dismay at the fearfulness of death in such a form. Eliza surveyed her parent calmly. After a silence of some minutes she observed With her constitution she should have lived to a good old age: her life was shortened by trouble. And then a spasm constricted her mouth for an instant: as it passed away she turned and left the room, and so did I. Neither of us had dropt a tear. -Chapter 22 +Chapter 22 Mr. Rochester had given me but one week s leave of absence: yet a month elapsed before I quitted Gateshead. I wished to leave immediately after the funeral, but Georgiana entreated me to stay till she could get off to London, whither she was now at last invited by her uncle, Mr. Gibson, who had come down to direct his sister s interment and settle the family affairs. Georgiana said she dreaded being left alone with Eliza; from her she got neither sympathy in her dejection, support in her fears, nor aid in her preparations; so I bore with her feeble-minded wailings and selfish lamentations as well as I could, and did my best in sewing for her and packing her dresses. It is true, that while I worked, she would idle; and I thought to myself, If you and I were destined to live always together, cousin, we would commence matters on a different footing. I should not settle tamely down into being the forbearing party; I should assign you your share of labour, and compel you to accomplish it, or else it should be left undone: I should insist, also, on your keeping some of those drawling, half-insincere complaints hushed in your own breast. It is only because our connection happens to be very transitory, and comes at a peculiarly mournful season, that I consent thus to render it so patient and compliant on my part. At last I saw Georgiana off; but now it was Eliza s turn to request me to stay another week. Her plans required all her time and attention, she said; she was about to depart for some unknown bourne; and all day long she stayed in her own room, her door bolted within, filling trunks, emptying drawers, burning papers, and holding no communication with any one. She wished me to look after the house, to see callers, and answer notes of condolence. One morning she told me I was at liberty. And, she added, I am obliged to you for your valuable services and discreet conduct! There is some difference between living with such an one as you and with Georgiana: you perform your own part in life and burden no one. To-morrow, she continued, I set out for the Continent. I shall take up my abode in a religious house near Lisle a nunnery you would call it; there I shall be quiet and unmolested. I shall devote myself for a time to the examination of the Roman Catholic dogmas, and to a careful study of the workings of their system: if I find it to be, as I half suspect it is, the one best calculated to ensure the doing of all things decently and in order, I shall embrace the tenets of Rome and probably take the veil. @@ -2205,7 +2205,7 @@ I walked on so fast that even he could hardly have overtaken me had he tried. Li I that evening shut my eyes resolutely against the future: I stopped my cars against the voice that kept warning me of near separation and coming grief. When tea was over and Mrs. Fairfax had taken her knitting, and I had assumed a low seat near her, and Ad le, kneeling on the carpet, had nestled close up to me, and a sense of mutual affection seemed to surround us with a ring of golden peace, I uttered a silent prayer that we might not be parted far or soon; but when, as we thus sat, Mr. Rochester entered, unannounced, and looking at us, seemed to take pleasure in the spectacle of a group so amicable when he said he supposed the old lady was all right now that she had got her adopted daughter back again, and added that he saw Ad le was prete e croquer sa petite maman Anglaise I half ventured to hope that he would, even after his marriage, keep us together somewhere under the shelter of his protection, and not quite exiled from the sunshine of his presence. A fortnight of dubious calm succeeded my return to Thornfield Hall. Nothing was said of the master s marriage, and I saw no preparation going on for such an event. Almost every day I asked Mrs. Fairfax if she had yet heard anything decided: her answer was always in the negative. Once she said she had actually put the question to Mr. Rochester as to when he was going to bring his bride home; but he had answered her only by a joke and one of his queer looks, and she could not tell what to make of him. One thing specially surprised me, and that was, there were no journeyings backward and forward, no visits to Ingram Park: to be sure it was twenty miles off, on the borders of another county; but what was that distance to an ardent lover? To so practised and indefatigable a horseman as Mr. Rochester, it would be but a morning s ride. I began to cherish hopes I had no right to conceive: that the match was broken off; that rumour had been mistaken; that one or both parties had changed their minds. I used to look at my master s face to see if it were sad or fierce; but I could not remember the time when it had been so uniformly clear of clouds or evil feelings. If, in the moments I and my pupil spent with him, I lacked spirits and sank into inevitable dejection, he became even gay. Never had he called me more frequently to his presence; never been kinder to me when there and, alas! never had I loved him so well. -Chapter 23 +Chapter 23 A splendid Midsummer shone over England: skies so pure, suns so radiant as were then seen in long succession, seldom favour even singly, our wave-girt land. It was as if a band of Italian days had come from the South, like a flock of glorious passenger birds, and lighted to rest them on the cliffs of Albion. The hay was all got in; the fields round Thornfield were green and shorn; the roads white and baked; the trees were in their dark prime; hedge and wood, full-leaved and deeply tinted, contrasted well with the sunny hue of the cleared meadows between. On Midsummer-eve, Ad le, weary with gathering wild strawberries in Hay Lane half the day, had gone to bed with the sun. I watched her drop asleep, and when I left her, I sought the garden. It was now the sweetest hour of the twenty-four:- Day its fervid fires had wasted, and dew fell cool on panting plain and scorched summit. Where the sun had gone down in simple state pure of the pomp of clouds spread a solemn purple, burning with the light of red jewel and furnace flame at one point, on one hill-peak, and extending high and wide, soft and still softer, over half heaven. The east had its own charm or fine deep blue, and its own modest gem, a casino and solitary star: soon it would boast the moon; but she was yet beneath the horizon. @@ -2326,7 +2326,7 @@ The rain rushed down. He hurried me up the walk, through the grounds, and into t Hasten to take off your wet things, said he; and before you go, good-night good-night, my darling! He kissed me repeatedly. When I looked up, on leaving his arms, there stood the widow, pale, grave, and amazed. I only smiled at her, and ran upstairs. Explanation will do for another time, thought I. Still, when I reached my chamber, I felt a pang at the idea she should even temporarily misconstrue what she had seen. But joy soon effaced every other feeling; and loud as the wind blew, near and deep as the thunder crashed, fierce and frequent as the lightning gleamed, cataract-like as the rain fell during a storm of two hours duration, I experienced no fear and little awe. Mr. Rochester came thrice to my door in the course of it, to ask if I was safe and tranquil: and that was comfort, that was strength for anything. Before I left my bed in the morning, little Ad le came running in to tell me that the great horse-chestnut at the bottom of the orchard had been struck by lightning in the night, and half of it split away. -Chapter 24 +Chapter 24 As I rose and dressed, I thought over what had happened, and wondered if it were a dream. I could not be certain of the reality till I had seen Mr. Rochester again, and heard him renew his words of love and promise. While arranging my hair, I looked at my face in the glass, and felt it was no longer plain: there was hope in its aspect and life in its colour; and my eyes seemed as if they had beheld the fount of fruition, and borrowed beams from the lustrous ripple. I had often been unwilling to look at my master, because I feared he could not be pleased at my look; but I was sure I might lift my face to his now, and not cool his affection by its expression. I took a plain but clean and light summer dress from my drawer and put it on: it seemed no attire had ever so well become me, because none had I ever worn in so blissful a mood. I was not surprised, when I ran down into the hall, to see that a brilliant June morning had succeeded to the tempest of the night; and to feel, through the open glass door, the breathing of a fresh and fragrant breeze. Nature must be gladsome when I was so happy. A beggar-woman and her little boy pale, ragged objects both were coming up the walk, and I ran down and gave them all the money I happened to have in my purse some three or four shillings: good or bad, they must partake of my jubilee. The rooks cawed, and blither birds sang; but nothing was so merry or so musical as my own rejoicing heart. @@ -2546,7 +2546,7 @@ From less to more, I worked him up to considerable irritation; then, after he ha The system thus entered on, I pursued during the whole season of probation; and with the best success. He was kept, to be sure, rather cross and crusty; but on the whole I could see he was excellently entertained, and that a lamb-like submission and turtle- dove sensibility, while fostering his despotism more, would have pleased his judgment, satisfied his common-sense, and even suited his taste less. In other people s presence I was, as formerly, deferential and quiet; any other line of conduct being uncalled for: it was only in the evening conferences I thus thwarted and afflicted him. He continued to send for me punctually the moment the clock struck seven; though when I appeared before him now, he had no such honeyed terms as love and darling on his lips: the best words at my service were provoking puppet, malicious elf, sprite, changeling, &c. For caresses, too, I now got grimaces; for a pressure of the hand, a pinch on the arm; for a kiss on the cheek, a severe tweak of the ear. It was all right: at present I decidedly preferred these fierce favours to anything more tender. Mrs. Fairfax, I saw, approved me: her anxiety on my account vanished; therefore I was certain I did well. Meantime, Mr. Rochester affirmed I was wearing him to skin and bone, and threatened awful vengeance for my present conduct at some period fast coming. I laughed in my sleeve at his menaces. I can keep you in reasonable check now, I reflected; and I don t doubt to be able to do it hereafter: if one expedient loses its virtue, another must be devised. Yet after all my task was not an easy one; often I would rather have pleased than teased him. My future husband was becoming to me my whole world; and more than the world: almost my hope of heaven. He stood between me and every thought of religion, as an eclipse intervenes between man and the broad sun. I could not, in those days, see God for His creature: of whom I had made an idol. -Chapter 25 +Chapter 25 The month of courtship had wasted: its very last hours were being numbered. There was no putting off the day that advanced the bridal day; and all preparations for its arrival were complete. I, at least, had nothing more to do: there were my trunks, packed, locked, corded, ranged in a row along the wall of my little chamber; to-morrow, at this time, they would be far on their road to London: and so should I (D.V.), or rather, not I, but one Jane Rochester, a person whom as yet I knew not. The cards of address alone remained to nail on: they lay, four little squares, in the drawer. Mr. Rochester had himself written the direction, Mrs. Rochester, Hotel, London, on each: I could not persuade myself to affix them, or to have them affixed. Mrs. Rochester! She did not exist: she would not be born till to-morrow, some time after eight o clock a.m.; and I would wait to be assured she had come into the world alive before I assigned to her all that property. It was enough that in yonder closet, opposite my dressing-table, garments said to be hers had already displaced my black stuff Lowood frock and straw bonnet: for not to me appertained that suit of wedding raiment; the pearl-coloured robe, the vapoury veil pendent from the usurped portmanteau. I shut the closet to conceal the strange, wraith-like apparel it contained; which, at this evening hour nine o clock gave out certainly a most ghostly shimmer through the shadow of my apartment. I will leave you by yourself, white dream, I said. I am feverish: I hear the wind blowing: I will go out of doors and feel it. It was not only the hurry of preparation that made me feverish; not only the anticipation of the great change the new life which was to commence to-morrow: both these circumstances had their share, doubtless, in producing that restless, excited mood which hurried me forth at this late hour into the darkening grounds: but a third cause influenced my mind more than they. I had at heart a strange and anxious thought. Something had happened which I could not comprehend; no one knew of or had seen the event but myself: it had taken place the preceding night. Mr. Rochester that night was absent from home; nor was he yet returned: business had called him to a small estate of two or three farms he possessed thirty miles off business it was requisite he should settle in person, previous to his meditated departure from England. I waited now his return; eager to disburthen my mind, and to seek of him the solution of the enigma that perplexed me. Stay till he comes, reader; and, when I disclose my secret to him, you shall share the confidence. @@ -2655,7 +2655,7 @@ It was. Half heaven was pure and stainless: the clouds, now trooping before the The night is serene, sir; and so am I. And you will not dream of separation and sorrow to-night; but of happy love and blissful union. This prediction was but half fulfilled: I did not indeed dream of sorrow, but as little did I dream of joy; for I never slept at all. With little Ad le in my arms, I watched the slumber of childhood so tranquil, so passionless, so innocent and waited for the coming day: all my life was awake and astir in my frame: and as soon as the sun rose I rose too. I remember Ad le clung to me as I left her: I remember I kissed her as I loosened her little hands from my neck; and I cried over her with strange emotion, and quitted her because I feared my sobs would break her still sound repose. She seemed the emblem of my past life; and he I was now to array myself to meet, the dread, but adored, type of my unknown future day. -Chapter 26 +Chapter 26 Sophie came at seven to dress me: she was very long indeed in accomplishing her task; so long that Mr. Rochester, grown, I suppose, impatient of my delay, sent up to ask why I did not come. She was just fastening my veil (the plain square of blond after all) to my hair with a brooch; I hurried from under her hands as soon as I could. Stop! she cried in French. Look at yourself in the mirror: you have not taken one peep. So I turned at the door: I saw a robed and veiled figure, so unlike my usual self that it seemed almost the image of a stranger. Jane! called a voice, and I hastened down. I was received at the foot of the stairs by Mr. Rochester. @@ -2748,7 +2748,7 @@ Jane Eyre, who had been an ardent, expectant woman almost a bride, was a cold, s My eyes were covered and closed: eddying darkness seemed to swim round me, and reflection came in as black and confused a flow. Self-abandoned, relaxed, and effortless, I seemed to have laid me down in the dried-up bed of a great river; I heard a flood loosened in remote mountains, and felt the torrent come: to rise I had no will, to flee I had no strength. I lay faint, longing to be dead. One idea only still throbbed life-like within me a remembrance of God: it begot an unuttered prayer: these words went wandering up and down in my rayless mind, as something that should be whispered, but no energy was found to express them Be not far from me, for trouble is near: there is none to help. It was near: and as I had lifted no petition to Heaven to avert it as I had neither joined my hands, nor bent my knees, nor moved my lips it came: in full heavy swing the torrent poured over me. The whole consciousness of my life lorn, my love lost, my hope quenched, my faith death-struck, swayed full and mighty above me in one sullen mass. That bitter hour cannot be described: in truth, the waters came into my soul; I sank in deep mire: I felt no standing; I came into deep waters; the floods overflowed me. -Chapter 27 +Chapter 27 Some time in the afternoon I raised my head, and looking round and seeing the western sun gilding the sign of its decline on the wall, I asked, What am I to do? But the answer my mind gave Leave Thornfield at once was so prompt, so dread, that I stopped my ears. I said I could not bear such words now. That I am not Edward Rochester s bride is the least part of my woe, I alleged: that I have wakened out of most glorious dreams, and found them all void and vain, is a horror I could bear and master; but that I must leave him decidedly, instantly, entirely, is intolerable. I cannot do it. But, then, a voice within me averred that I could do it and foretold that I should do it. I wrestled with my own resolution: I wanted to be weak that I might avoid the awful passage of further suffering I saw laid out for me; and Conscience, turned tyrant, held Passion by the throat, told her tauntingly, she had yet but dipped her dainty foot in the slough, and swore that with that arm of iron he would thrust her down to unsounded depths of agony. @@ -2912,7 +2912,7 @@ A mile off, beyond the fields, lay a road which stretched in the contrary direct I skirted fields, and hedges, and lanes till after sunrise. I believe it was a lovely summer morning: I know my shoes, which I had put on when I left the house, were soon wet with dew. But I looked neither to rising sun, nor smiling sky, nor wakening nature. He who is taken out to pass through a fair scene to the scaffold, thinks not of the flowers that smile on his road, but of the block and axe-edge; of the disseverment of bone and vein; of the grave gaping at the end: and I thought of drear flight and homeless wandering and oh! with agony I thought of what I left. I could not help it. I thought of him now in his room watching the sunrise; hoping I should soon come to say I would stay with him and be his. I longed to be his; I panted to return: it was not too late; I could yet spare him the bitter pang of bereavement. As yet my flight, I was sure, was undiscovered. I could go back and be his comforter his pride; his redeemer from misery, perhaps from ruin. Oh, that fear of his self-abandonment far worse than my abandonment how it goaded me! It was a barbed arrow-head in my breast; it tore me when I tried to extract it; it sickened me when remembrance thrust it farther in. Birds began singing in brake and copse: birds were faithful to their mates; birds were emblems of love. What was I? In the midst of my pain of heart and frantic effort of principle, I abhorred myself. I had no solace from self- approbation: none even from self-respect. I had injured wounded left my master. I was hateful in my own eyes. Still I could not turn, nor retrace one step. God must have led me on. As to my own will or conscience, impassioned grief had trampled one and stifled the other. I was weeping wildly as I walked along my solitary way: fast, fast I went like one delirious. A weakness, beginning inwardly, extending to the limbs, seized me, and I fell: I lay on the ground some minutes, pressing my face to the wet turf. I had some fear or hope that here I should die: but I was soon up; crawling forwards on my hands and knees, and then again raised to my feet as eager and as determined as ever to reach the road. When I got there, I was forced to sit to rest me under the hedge; and while I sat, I heard wheels, and saw a coach come on. I stood up and lifted my hand; it stopped. I asked where it was going: the driver named a place a long way off, and where I was sure Mr. Rochester had no connections. I asked for what sum he would take me there; he said thirty shillings; I answered I had but twenty; well, he would try to make it do. He further gave me leave to get into the inside, as the vehicle was empty: I entered, was shut in, and it rolled on its way. Gentle reader, may you never feel what I then felt! May your eyes never shed such stormy, scalding, heart-wrung tears as poured from mine. May you never appeal to Heaven in prayers so hopeless and so agonised as in that hour left my lips; for never may you, like me, dread to be the instrument of evil to what you wholly love. -Chapter 28 +Chapter 28 Two days are passed. It is a summer evening; the coachman has set me down at a place called Whitcross; he could take me no farther for the sum I had given, and I was not possessed of another shilling in the world. The coach is a mile off by this time; I am alone. At this moment I discover that I forgot to take my parcel out of the pocket of the coach, where I had placed it for safety; there it remains, there it must remain; and now, I am absolutely destitute. Whitcross is no town, nor even a hamlet; it is but a stone pillar set up where four roads meet: whitewashed, I suppose, to be more obvious at a distance and in darkness. Four arms spring from its summit: the nearest town to which these point is, according to the inscription, distant ten miles; the farthest, above twenty. From the well-known names of these towns I learn in what county I have lighted; a north-midland shire, dusk with moorland, ridged with mountain: this I see. There are great moors behind and on each hand of me; there are waves of mountains far beyond that deep valley at my feet. The population here must be thin, and I see no passengers on these roads: they stretch out east, west, north, and south white, broad, lonely; they are all cut in the moor, and the heather grows deep and wild to their very verge. Yet a chance traveller might pass by; and I wish no eye to see me now: strangers would wonder what I am doing, lingering here at the sign-post, evidently objectless and lost. I might be questioned: I could give no answer but what would sound incredible and excite suspicion. Not a tie holds me to human society at this moment not a charm or hope calls me where my fellow-creatures are none that saw me would have a kind thought or a good wish for me. I have no relative but the universal mother, Nature: I will seek her breast and ask repose. I struck straight into the heath; I held on to a hollow I saw deeply furrowing the brown moorside; I waded knee-deep in its dark growth; I turned with its turnings, and finding a moss-blackened granite crag in a hidden angle, I sat down under it. High banks of moor were about me; the crag protected my head: the sky was over that. @@ -3057,7 +3057,7 @@ Somehow, now that I had once crossed the threshold of this house, and once was b I looked at her. She had, I thought, a remarkable countenance, instinct both with power and goodness. I took sudden courage. Answering her compassionate gate with a smile, I said I will trust you. If I were a masterless and stray dog, I know that you would not turn me from your hearth to-night: as it is, I really have no fear. Do with me and for me as you like; but excuse me from much discourse my breath is short I feel a spasm when I speak. All three surveyed me, and all three were silent. Hannah, said Mr. St. John, at last, let her sit there at present, and ask her no questions; in ten minutes more, give her the remainder of that milk and bread. Mary and Diana, let us go into the parlour and talk the matter over. They withdrew. Very soon one of the ladies returned I could not tell which. A kind of pleasant stupor was stealing over me as I sat by the genial fire. In an undertone she gave some directions to Hannah. Ere long, with the servant s aid, I contrived to mount a staircase; my dripping clothes were removed; soon a warm, dry bed received me. I thanked God experienced amidst unutterable exhaustion a glow of grateful joy and slept. -Chapter 29 +Chapter 29 The recollection of about three days and nights succeeding this is very dim in my mind. I can recall some sensations felt in that interval; but few thoughts framed, and no actions performed. I knew I was in a small room and in a narrow bed. To that bed I seemed to have grown; I lay on it motionless as a stone; and to have torn me from it would have been almost to kill me. I took no note of the lapse of time of the change from morning to noon, from noon to evening. I observed when any one entered or left the apartment: I could even tell who they were; I could understand what was said when the speaker stood near to me; but I could not answer; to open my lips or move my limbs was equally impossible. Hannah, the servant, was my most frequent visitor. Her coming disturbed me. I had a feeling that she wished me away: that she did not understand me or my circumstances; that she was prejudiced against me. Diana and Mary appeared in the chamber once or twice a day. They would whisper sentences of this sort at my bedside It is very well we took her in. Yes; she would certainly have been found dead at the door in the morning had she been left out all night. I wonder what she has gone through? @@ -3184,7 +3184,7 @@ But when St. John had mused a few moments he recommenced as imperturbably and wi I will be a dressmaker; I will be a plain-workwoman; I will be a servant, a nurse-girl, if I can be no better, I answered. Right, said Mr. St. John, quite coolly. If such is your spirit, I promise to aid you, in my own time and way. He now resumed the book with which he had been occupied before tea. I soon withdrew, for I had talked as much, and sat up as long, as my present strength would permit. -Chapter 30 +Chapter 30 The more I knew of the inmates of Moor House, the better I liked them. In a few days I had so far recovered my health that I could sit up all day, and walk out sometimes. I could join with Diana and Mary in all their occupations; converse with them as much as they wished, and aid them when and where they would allow me. There was a reviving pleasure in this intercourse, of a kind now tasted by me for the first time-the pleasure arising from perfect congeniality of tastes, sentiments, and principles. I liked to read what they liked to read: what they enjoyed, delighted me; what they approved, I reverenced. They loved their sequestered home. I, too, in the grey, small, antique structure, with its low roof, its latticed casements, its mouldering walls, its avenue of aged firs all grown aslant under the stress of mountain winds; its garden, dark with yew and holly and where no flowers but of the hardiest species would bloom found a charm both potent and permanent. They clung to the purple moors behind and around their dwelling to the hollow vale into which the pebbly bridle-path leading from their gate descended, and which wound between fern- banks first, and then amongst a few of the wildest little pasture- fields that ever bordered a wilderness of heath, or gave sustenance to a flock of grey moorland sheep, with their little mossy-faced lambs:- they clung to this scene, I say, with a perfect enthusiasm of attachment. I could comprehend the feeling, and share both its strength and truth. I saw the fascination of the locality. I felt the consecration of its loneliness: my eye feasted on the outline of swell and sweep on the wild colouring communicated to ridge and dell by moss, by heath-bell, by flower-sprinkled turf, by brilliant bracken, and mellow granite crag. These details were just to me what they were to them so many pure and sweet sources of pleasure. The strong blast and the soft breeze; the rough and the halcyon day; the hours of sunrise and sunset; the moonlight and the clouded night, developed for me, in these regions, the same attraction as for them wound round my faculties the same spell that entranced theirs. Indoors we agreed equally well. They were both more accomplished and better read than I was; but with eagerness I followed in the path of knowledge they had trodden before me. I devoured the books they lent me: then it was full satisfaction to discuss with them in the evening what I had perused during the day. Thought fitted thought; opinion met opinion: we coincided, in short, perfectly. @@ -3255,7 +3255,7 @@ He folded the letter, locked it in his desk, and again went out. For some minutes no one spoke. Diana then turned to me. Jane, you will wonder at us and our mysteries, she said, and think us hard-hearted beings not to be more moved at the death of so near a relation as an uncle; but we have never seen him or known him. He was my mother s brother. My father and he quarrelled long ago. It was by his advice that my father risked most of his property in the speculation that ruined him. Mutual recrimination passed between them: they parted in anger, and were never reconciled. My uncle engaged afterwards in more prosperous undertakings: it appears he realised a fortune of twenty thousand pounds. He was never married, and had no near kindred but ourselves and one other person, not more closely related than we. My father always cherished the idea that he would atone for his error by leaving his possessions to us; that letter informs us that he has bequeathed every penny to the other relation, with the exception of thirty guineas, to be divided between St. John, Diana, and Mary Rivers, for the purchase of three mourning rings. He had a right, of course, to do as he pleased: and yet a momentary damp is cast on the spirits by the receipt of such news. Mary and I would have esteemed ourselves rich with a thousand pounds each; and to St. John such a sum would have been valuable, for the good it would have enabled him to do. This explanation given, the subject was dropped, and no further reference made to it by either Mr. Rivers or his sisters. The next day I left Marsh End for Morton. The day after, Diana and Mary quitted it for distant B-. In a week, Mr. Rivers and Hannah repaired to the parsonage: and so the old grange was abandoned. -Chapter 31 +Chapter 31 My home, then, when I at last find a home, is a cottage; a little room with whitewashed walls and a sanded floor, containing four painted chairs and a table, a clock, a cupboard, with two or three plates and dishes, and a set of tea-things in delf. Above, a chamber of the same dimensions as the kitchen, with a deal bedstead and chest of drawers; small, yet too large to be filled with my scanty wardrobe: though the kindness of my gentle and generous friends has increased that, by a modest stock of such things as are necessary. It is evening. I have dismissed, with the fee of an orange, the little orphan who serves me as a handmaid. I am sitting alone on the hearth. This morning, the village school opened. I had twenty scholars. But three of the number can read: none write or cipher. Several knit, and a few sew a little. They speak with the broadest accent of the district. At present, they and I have a difficulty in understanding each other s language. Some of them are unmannered, rough, intractable, as well as ignorant; but others are docile, have a wish to learn, and evince a disposition that pleases me. I must not forget that these coarsely-clad little peasants are of flesh and blood as good as the scions of gentlest genealogy; and that the germs of native excellence, refinement, intelligence, kind feeling, are as likely to exist in their hearts as in those of the best-born. My duty will be to develop these germs: surely I shall find some happiness in discharging that office. Much enjoyment I do not expect in the life opening before me: yet it will, doubtless, if I regulate my mind, and exert my powers as I ought, yield me enough to live on from day to day. Was I very gleeful, settled, content, during the hours I passed in yonder bare, humble schoolroom this morning and afternoon? Not to deceive myself, I must reply No: I felt desolate to a degree. I felt yes, idiot that I am I felt degraded. I doubted I had taken a step which sank instead of raising me in the scale of social existence. I was weakly dismayed at the ignorance, the poverty, the coarseness of all I heard and saw round me. But let me not hate and despise myself too much for these feelings; I know them to be wrong that is a great step gained; I shall strive to overcome them. To- morrow, I trust, I shall get the better of them partially; and in a few weeks, perhaps, they will be quite subdued. In a few months, it is possible, the happiness of seeing progress, and a change for the better in my scholars may substitute gratification for disgust. @@ -3309,7 +3309,7 @@ She held out her hand. He just touched it. Good evening! he repeated, in a voi Are you well? she asked. Well might she put the question: his face was blanched as her gown. Quite well, he enunciated; and, with a bow, he left the gate. She went one way; he another. She turned twice to gaze after him as she tripped fairy-like down the field; he, as he strode firmly across, never turned at all. This spectacle of another s suffering and sacrifice rapt my thoughts from exclusive meditation on my own. Diana Rivers had designated her brother inexorable as death. She had not exaggerated. -Chapter 32 +Chapter 32 I continued the labours of the village-school as actively and faithfully as I could. It was truly hard work at first. Some time elapsed before, with all my efforts, I could comprehend my scholars and their nature. Wholly untaught, with faculties quite torpid, they seemed to me hopelessly dull; and, at first sight, all dull alike: but I soon found I was mistaken. There was a difference amongst them as amongst the educated; and when I got to know them, and they me, this difference rapidly developed itself. Their amazement at me, my language, my rules, and ways, once subsided, I found some of these heavy-looking, gaping rustics wake up into sharp-witted girls enough. Many showed themselves obliging, and amiable too; and I discovered amongst them not a few examples of natural politeness, and innate self-respect, as well as of excellent capacity, that won both my goodwill and my admiration. These soon took a pleasure in doing their work well, in keeping their persons neat, in learning their tasks regularly, in acquiring quiet and orderly manners. The rapidity of their progress, in some instances, was even surprising; and an honest and happy pride I took in it: besides, I began personally to like some of the best girls; and they liked me. I had amongst my scholars several farmers daughters: young women grown, almost. These could already read, write, and sew; and to them I taught the elements of grammar, geography, history, and the finer kinds of needlework. I found estimable characters amongst them characters desirous of information and disposed for improvement with whom I passed many a pleasant evening hour in their own homes. Their parents then (the farmer and his wife) loaded me with attentions. There was an enjoyment in accepting their simple kindness, and in repaying it by a consideration a scrupulous regard to their feelings to which they were not, perhaps, at all times accustomed, and which both charmed and benefited them; because, while it elevated them in their own eyes, it made them emulous to merit the deferential treatment they received. I felt I became a favourite in the neighbourhood. Whenever I went out, I heard on all sides cordial salutations, and was welcomed with friendly smiles. To live amidst general regard, though it be but the regard of working people, is like sitting in sunshine, calm and sweet; serene inward feelings bud and bloom under the ray. At this period of my life, my heart far oftener swelled with thankfulness than sank with dejection: and yet, reader, to tell you all, in the midst of this calm, this useful existence after a day passed in honourable exertion amongst my scholars, an evening spent in drawing or reading contentedly alone I used to rush into strange dreams at night: dreams many-coloured, agitated, full of the ideal, the stirring, the stormy dreams where, amidst unusual scenes, charged with adventure, with agitating risk and romantic chance, I still again and again met Mr. Rochester, always at some exciting crisis; and then the sense of being in his arms, hearing his voice, meeting his eye, touching his hand and cheek, loving him, being loved by him the hope of passing a lifetime at his side, would be renewed, with all its first force and fire. Then I awoke. Then I recalled where I was, and how situated. Then I rose up on my curtainless bed, trembling and quivering; and then the still, dark night witnessed the convulsion of despair, and heard the burst of passion. By nine o clock the next morning I was punctually opening the school; tranquil, settled, prepared for the steady duties of the day. Rosamond Oliver kept her word in coming to visit me. Her call at the school was generally made in the course of her morning ride. She would canter up to the door on her pony, followed by a mounted livery servant. Anything more exquisite than her appearance, in her purple habit, with her Amazon s cap of black velvet placed gracefully above the long curls that kissed her cheek and floated to her shoulders, can scarcely be imagined: and it was thus she would enter the rustic building, and glide through the dazzled ranks of the village children. She generally came at the hour when Mr. Rivers was engaged in giving his daily catechising lesson. Keenly, I fear, did the eye of the visitress pierce the young pastor s heart. A sort of instinct seemed to warn him of her entrance, even when he did not see it; and when he was looking quite away from the door, if she appeared at it, his cheek would glow, and his marble- seeming features, though they refused to relax, changed indescribably, and in their very quiescence became expressive of a repressed fervour, stronger than working muscle or darting glance could indicate. @@ -3379,7 +3379,7 @@ He drew over the picture the sheet of thin paper on which I was accustomed to re Nothing in the world, was the reply; and, replacing the paper, I saw him dexterously tear a narrow slip from the margin. It disappeared in his glove; and, with one hasty nod and good- afternoon, he vanished. Well! I exclaimed, using an expression of the district, that caps the globe, however! I, in my turn, scrutinised the paper; but saw nothing on it save a few dingy stains of paint where I had tried the tint in my pencil. I pondered the mystery a minute or two; but finding it insolvable, and being certain it could not be of much moment, I dismissed, and soon forgot it. -Chapter 34 +Chapter 34 When Mr. St. John went, it was beginning to snow; the whirling storm continued all night. The next day a keen wind brought fresh and blinding falls; by twilight the valley was drifted up and almost impassable. I had closed my shutter, laid a mat to the door to prevent the snow from blowing in under it, trimmed my fire, and after sitting nearly an hour on the hearth listening to the muffled fury of the tempest, I lit a candle, took down Marmion, and beginning Day set on Norham s castled steep, And Tweed s fair river broad and deep, @@ -3526,7 +3526,7 @@ How I looked while these ideas were taking my spirit by storm, I cannot tell; bu No. I will retain my post of mistress till you get a substitute. He smiled approbation: we shook hands, and he took leave. I need not narrate in detail the further struggles I had, and arguments I used, to get matters regarding the legacy settled as I wished. My task was a very hard one; but, as I was absolutely resolved as my cousins saw at length that my mind was really and immutably fixed on making a just division of the property as they must in their own hearts have felt the equity of the intention; and must, besides, have been innately conscious that in my place they would have done precisely what I wished to do they yielded at length so far as to consent to put the affair to arbitration. The judges chosen were Mr. Oliver and an able lawyer: both coincided in my opinion: I carried my point. The instruments of transfer were drawn out: St. John, Diana, Mary, and I, each became possessed of a competency. -Chapter 33 +Chapter 33 It was near Christmas by the time all was settled: the season of general holiday approached. I now closed Morton school, taking care that the parting should not be barren on my side. Good fortune opens the hand as well as the heart wonderfully; and to give somewhat when we have largely received, is but to afford a vent to the unusual ebullition of the sensations. I had long felt with pleasure that many of my rustic scholars liked me, and when we parted, that consciousness was confirmed: they manifested their affection plainly and strongly. Deep was my gratification to find I had really a place in their unsophisticated hearts: I promised them that never a week should pass in future that I did not visit them, and give them an hour s teaching in their school. Mr. Rivers came up as, having seen the classes, now numbering sixty girls, file out before me, and locked the door, I stood with the key in my hand, exchanging a few words of special farewell with some half-dozen of my best scholars: as decent, respectable, modest, and well-informed young women as could be found in the ranks of the British peasantry. And that is saying a great deal; for after all, the British peasantry are the best taught, best mannered, most self- respecting of any in Europe: since those days I have seen paysannes and Bauerinnen; and the best of them seemed to me ignorant, coarse, and besotted, compared with my Morton girls. Do you consider you have got your reward for a season of exertion? asked Mr. Rivers, when they were gone. Does not the consciousness of having done some real good in your day and generation give pleasure? @@ -3688,7 +3688,7 @@ I have not much pride under such circumstances: I would always rather be happy t Then shake hands, I added. What a cold, loose touch, he impressed on my fingers! He was deeply displeased by what had occurred that day; cordiality would not warm, nor tears move him. No happy reconciliation was to be had with him no cheering smile or generous word: but still the Christian was patient and placid; and when I asked him if he forgave me, he answered that he was not in the habit of cherishing the remembrance of vexation; that he had nothing to forgive, not having been offended. And with that answer he left me. I would much rather he had knocked me down. -Chapter 35 +Chapter 35 He did not leave for Cambridge the next day, as he had said he would. He deferred his departure a whole week, and during that time he made me feel what severe punishment a good yet stern, a conscientious yet implacable man can inflict on one who has offended him. Without one overt act of hostility, one upbraiding word, he contrived to impress me momently with the conviction that I was put beyond the pale of his favour. Not that St. John harboured a spirit of unchristian vindictiveness not that he would have injured a hair of my head, if it had been fully in his power to do so. Both by nature and principle, he was superior to the mean gratification of vengeance: he had forgiven me for saying I scorned him and his love, but he had not forgotten the words; and as long as he and I lived he never would forget them. I saw by his look, when he turned to me, that they were always written on the air between me and him; whenever I spoke, they sounded in my voice to his ear, and their echo toned every answer he gave me. He did not abstain from conversing with me: he even called me as usual each morning to join him at his desk; and I fear the corrupt man within him had a pleasure unimparted to, and unshared by, the pure Christian, in evincing with what skill he could, while acting and speaking apparently just as usual, extract from every deed and every phrase the spirit of interest and approval which had formerly communicated a certain austere charm to his language and manner. To me, he was in reality become no longer flesh, but marble; his eye was a cold, bright, blue gem; his tongue a speaking instrument nothing more. @@ -3787,7 +3787,7 @@ I might have said, Where is it? for it did not seem in the room nor in the ho The hills beyond Marsh Glen sent the answer faintly back Where are you? I listened. The wind sighed low in the firs: all was moorland loneliness and midnight hush. Down superstition! I commented, as that spectre rose up black by the black yew at the gate. This is not thy deception, nor thy witchcraft: it is the work of nature. She was roused, and did no miracle but her best. I broke from St. John, who had followed, and would have detained me. It was my time to assume ascendency. My powers were in play and in force. I told him to forbear question or remark; I desired him to leave me: I must and would be alone. He obeyed at once. Where there is energy to command well enough, obedience never fails. I mounted to my chamber; locked myself in; fell on my knees; and prayed in my way a different way to St. John s, but effective in its own fashion. I seemed to penetrate very near a Mighty Spirit; and my soul rushed out in gratitude at His feet. I rose from the thanksgiving took a resolve and lay down, unscared, enlightened eager but for the daylight. -Chapter 36 +Chapter 36 The daylight came. I rose at dawn. I busied myself for an hour or two with arranging my things in my chamber, drawers, and wardrobe, in the order wherein I should wish to leave them during a brief absence. Meantime, I heard St. John quit his room. He stopped at my door: I feared he would knock no, but a slip of paper was passed under the door. I took it up. It bore these words You left me too suddenly last night. Had you stayed but a little longer, you would have laid your hand on the Christian s cross and the angel s crown. I shall expect your clear decision when I return this day fortnight. Meantime, watch and pray that you enter not into temptation: the spirit, I trust, is willing, but the flesh, I see, is weak. I shall pray for you hourly. Yours, ST. JOHN. My spirit, I answered mentally, is willing to do what is right; and my flesh, I hope, is strong enough to accomplish the will of Heaven, when once that will is distinctly known to me. At any rate, it shall be strong enough to search inquire to grope an outlet from this cloud of doubt, and find the open day of certainty. @@ -3867,7 +3867,7 @@ I had dreaded worse. I had dreaded he was mad. I summoned strength to ask what h Have you any sort of conveyance? We have a chaise, ma am, a very handsome chaise. Let it be got ready instantly; and if your post-boy can drive me to Ferndean before dark this day, I ll pay both you and him twice the hire you usually demand. -Chapter 37 +Chapter 37 The manor-house of Ferndean was a building of considerable antiquity, moderate size, and no architectural pretensions, deep buried in a wood. I had heard of it before. Mr. Rochester often spoke of it, and sometimes went there. His father had purchased the estate for the sake of the game covers. He would have let the house, but could find no tenant, in consequence of its ineligible and insalubrious site. Ferndean then remained uninhabited and unfurnished, with the exception of some two or three rooms fitted up for the accommodation of the squire when he went there in the season to shoot. To this house I came just ere dark on an evening marked by the characteristics of sad sky, cold gale, and continued small penetrating rain. The last mile I performed on foot, having dismissed the chaise and driver with the double remuneration I had promised. Even when within a very short distance of the manor- house, you could see nothing of it, so thick and dark grew the timber of the gloomy wood about it. Iron gates between granite pillars showed me where to enter, and passing through them, I found myself at once in the twilight of close-ranked trees. There was a grass-grown track descending the forest aisle between hoar and knotty shafts and under branched arches. I followed it, expecting soon to reach the dwelling; but it stretched on and on, it would far and farther: no sign of habitation or grounds was visible. I thought I had taken a wrong direction and lost my way. The darkness of natural as well as of sylvan dusk gathered over me. I looked round in search of another road. There was none: all was interwoven stem, columnar trunk, dense summer foliage no opening anywhere. @@ -4128,7 +4128,7 @@ Reader, it was on Monday night near midnight that I too had received the mysteri He put me off his knee, rose, and reverently lifting his hat from his brow, and bending his sightless eyes to the earth, he stood in mute devotion. Only the last words of the worship were audible. I thank my Maker, that, in the midst of judgment, he has remembered mercy. I humbly entreat my Redeemer to give me strength to lead henceforth a purer life than I have done hitherto! Then he stretched his hand out to be led. I took that dear hand, held it a moment to my lips, then let it pass round my shoulder: being so much lower of stature than he, I served both for his prop and guide. We entered the wood, and wended homeward. -Chapter 38 CONCLUSION +Chapter 38 CONCLUSION Reader, I married him. A quiet wedding we had: he and I, the parson and clerk, were alone present. When we got back from church, I went into the kitchen of the manor-house, where Mary was cooking the dinner and John cleaning the knives, and I said Mary, I have been married to Mr. Rochester this morning. The housekeeper and her husband were both of that decent phlegmatic order of people, to whom one may at any time safely communicate a remarkable piece of news without incurring the danger of having one s ears pierced by some shrill ejaculation, and subsequently stunned by a torrent of wordy wonderment. Mary did look up, and she did stare at me: the ladle with which she was basting a pair of chickens roasting at the fire, did for some three minutes hang suspended in air; and for the same space of time John s knives also had rest from the polishing process: but Mary, bending again over the roast, said only Have you, Miss? Well, for sure! diff --git a/assets/books/camelXiangzi/camelXiangzi.txt b/assets/books/camelXiangzi/camelXiangzi.txt index 97280f1..3f7f367 100644 --- a/assets/books/camelXiangzi/camelXiangzi.txt +++ b/assets/books/camelXiangzi/camelXiangzi.txt @@ -2,7 +2,7 @@ ×÷ÕߣºÀÏÉá -һ +һ ÎÒÃÇËùҪ½éÉܵÄÊÇÏé×ӣ¬²»ÊÇÂæÍգ¬ÒòΪ¡°ÂæÍա±ֻÊǸöÍâºţ»ÄÇô£¬ÎÒÃǾÍÏÈ˵Ïé×ӣ¬ËæÊֶù°ÑÂæÍÕÓëÏé×ÓÄǵã¹Øϵ˵¹ýȥ£¬Ҳ¾ÍËãÁˡ£ @@ -56,7 +56,7 @@ ¿ÉÊǣ¬ϣÍû¶à°ëÂä¿գ¬Ïé×ӵÄҲ·ÇÀýÍ⡣ -¶þ +¶þ ÒòΪ¸ßÐˣ¬µ¨×ÓҲ¾ʹóÆðÀ´£»×ԴÓÂòÁ˳µ£¬Ïé×ÓÅܵøü¿ìÁˡ£×Լºµijµ£¬µ±Ȼ¸ñÍâСÐģ¬¿ÉÊÇËû¿´¿´×Լº£¬Ôٿ´¿´×Լºµijµ£¬¾;õµÃÓÐЩ²»ÊÇζ¶ù£¬¼ÙÈô²»¿ìÅܵϰ¡£ @@ -114,7 +114,7 @@ ²»֪µÈÁ˶à¾ã¬ʼÖÕûÈËÀ´À­ÂæÍա£Ëû´ó×ŵ¨×Ó×øÆðÀ´£¬´ÓÂæÍյÄ˫·å¼äÍû¹ýȥ£¬ʲôҲ¿´²»¼û£¬ËÄÍ⼫ºڡ£ÌӰɣ¡²»¹ÜÊǼªÊÇÐף¬Ìӣ¡ -Èý +Èý Ïé×ÓÒѾ­Åܳö¶þÈýʮ²½ȥ£¬¿ÉÓֲ»¿ÏÅÜÁˣ¬ËûÉ᲻µÃÄǼ¸ƥÂæÍա£ËûÔÚÊÀ½çÉϵIJƲú£¬ÏÖÔڣ¬ֻʣÏÂÁË×ԼºµÄһÌõÃü¡£¾ÍÊǵØÉϵÄһ¸ùÂéÉþ£¬ËûҲÀÖÒâʰÆðÀ´£¬¼´ʹûÓ㬻¹ÄÜÉÔ΢°²οËûһÏ£¬ÖÁÉÙËûÊÖÖÐÓÐÌõÂéÉþ£¬²»ÍêȫÊǿյġ£ÌÓÃüÊÇҪ½ôµģ¬¿ÉÊdzàÂãÂãµÄһÌõÃüÓÐʲôÓÃÄأ¿Ëûµôø×ßÕ⼸ƥÉü¿ڣ¬ËäȻ»¹ûÏëÆðÂæÍÕÄÜÓÐʲôÓô¦£¬¿ÉÊÇ×ܵÃËãÊǼ¸¼þ¶«Î÷£¬¶øÇÒÊǿé¶ù²»СµĶ«Î÷¡£ @@ -210,7 +210,7 @@ Ïé×ӺÈÁËһÆøÁ¹ˮ£¬ȻºóÄÃ×ÅÈýʮÎå¿éºÜÁÁµÄÏÖÑó£¬Á½¸ö°ô×ÓÃæ±ý×ӣ¬´©×Ž«»¤µ½ÐؼʵÄһ¼þÆư×С¹ӣ¬Ҫһ²½Âõµ½³ÇÀïȥ£¡ -ËÄ +ËÄ Ïé×ÓÔں£µéµÄһ¼ÒСµêÀïÌÉÁËÈýÌ죬ÉíÉϺöÀäºöÈȣ¬ÐÄÖÐÃÔÃԺöºö£¬ÑÀ´²ÉÏÆðÁËһÁï×ÏÅݣ¬ֻÏëºÈˮ£¬²»Ïë³Ôʲô¡£¶öÁËÈýÌ죬»ðÆø½µÏÂȥ£¬ÉíÉÏÈíµÃÏóƤÌÇËƵġ£¿ÖžÍÊÇÔÚÕâÈýÌìÀËûÓëÈýƥÂæÍյĹØϵÓÉÃλ°»òºú»°Öб»È˼ÒÌýÁËȥ¡£һÇåÐѹýÀ´£¬ËûÒѾ­Êǡ°ÂæÍÕÏé×ӡ±Áˡ£ @@ -300,7 +300,7 @@ ¡°û´í£¡¡±Ïé×ÓÁ¢ÆðÀ´£º¡°˯¾õȥ¡£Ë͸øÄãÀÏÈ˼Òһ°üÑó»𣡡±Ëû·ÅÔÚ×À×ÓÉÏһ°ü»ð²ñ£¬ÓÖÀãÁËÀ㣺¡°²»ÓöԱðÈË˵£¬ÂæÍյÄÊ£¡¡± -Îå +Îå ÁõÀÏͷ×ӵÄȷûÌæÏé×ÓÐû´«£¬¿ÉÊÇÂæÍյĹÊʺܿìµÄÓɺ£µ鴫½ø³ÇÀïÀ´¡£ÒÔǰ£¬´ó¼ÒËäÕҲ»³öÏé×ӵÄ벡£¬µ«ÊÇÒÔËûÄǹÉ×Ӹɾóµľ¢¶ù£¬ËûÃǶàÉÙÒÔΪËû²»´óºÏȺ£¬±ðŤ¡£×Դӡ°ÂæÍÕÏé×ӡ±´«¿ªÁËÒԺó£¬Ïé×ÓËäȻ»¹ÊÇÃÆ×Åͷ¶ù¸ɣ¬²»´óºÍÆø£¬´ó¼ҶÔËûȴÓеãÁíÑۿ´´ýÁˡ£ÓÐÈË˵ËûʰÁ˸ö½ð±í£¬ÓÐÈË˵Ëû°×ŪÁËÈý°ٿé´óÑó£¬ÄÇ×ÔÐÅ֪µÀµÃ×îÏêȷµIJŵã×Åͷ˵£¬Ëû´ÓÎ÷ɽÀ­»ØÈýʮƥÂæÍգ¡˵·¨ËäȻ²»ͬ£¬½áÂÛÊÇһÑùµġª¡ªÏé×ӷ¢ÁËа²ƣ¡¶ÔÓڷ¢а²ƵÄÈˣ¬²»¹ÜÕâ¼һïÊÇÔõÑùµġ°²»µøç¶ùÃǡ±¢٣¬´ó¼ÒÕÕÀýÊÇҪ¾´Öصġ£ÂôÁ¦ÆøÕõǮ¼ÈÊÇÄÇô²»ÈÝÒף¬ÈËÈËÅÎÍû·¢µãа²ƣ»а²ƼÈÊÇÄÇôǧÔØÄÑÓö£¬ËùÒÔÓÐЩ²ÊÆøµıض¨ÊÇÓëÖڲ»ͬ£¬¸£´óÃü´ó¡£Òò´ˣ¬Ïé×ӵijÁĬÓ벻ºÏȺ£¬һ±ä±ä³ÉÁ˹óÈËÓï³٣»ËûӦµ±ÕâÑù£¬¶øËûÃÇÀí¸øÏ×ÅËûȥÀ­£¡£¡°µÃÁˣ¬Ïé×ӣ¡˵˵£¬˵˵ÄãÔõô·¢µIJƣ¿¡±ÕâÑùµĻ°£¬Ïé×ÓÌìÌìÌýµ½¡£ËûһÉù²»Ï졣ֱµ½±Ƽ±Áˣ¬ËûµÄÄǿé°ÌÓе㷢ºìÁˣ¬²Å˵£¬¡°·¢²ƣ¬ÂèµÄÎҵijµÄĶùȥÁˣ¿¡± @@ -354,7 +354,7 @@ Ïé×ӵÄÁ³ºöȻ×ÏÁˣ¬ͦÁËͦÑü£¬ºÃÏóͷҪ¶¥ס·¿Áº£¬һ°ÑץÆðÄÇÕÅëƱ£¬ˤÔÚ̫̫µÄÅÖÁ³Éϣº¡°¸øÎÒËÄÌìµĹ¤Ǯ£¡¡±¡°ÔõÂðÔý£¿¡±̫̫˵ÍêÕâ¸ö£¬Óֿ´ÁËÏé×ÓһÑۣ¬²»ÑÔÓïÁˣ¬°ÑËÄÌìµĹ¤Ǯ¸øÁËËû¡£À­×ÅÆ̸ǸÕһ³ö½ÖÃţ¬ËûÌý¼ûԺÀïÆƿÚÂîÉÏÁˡ£ -Áù +Áù ³õÇïµÄҹÍí£¬ÐǹâҶӰÀïÕóÕóµÄС·磬Ïé×Ó̧Æðͷ£¬¿´×ŸßԶµÄÌìºӣ¬̾Á˿ÚÆø¡£ÕâôÁ¹ˬµÄÌ죬ËûµÄÐظ¬ÓÖÊÇÄÇô¿í£¬¿ÉÊÇËû¾õµ½¿ÕÆø··𲻹»£¬ÐØÖзdz£±ïÃơ£ËûÏë×øÏÂʹ¿Þһ³¡¡£ÒÔ×ԼºµÄÌå¸ñ£¬ÒÔ×ԼºµÄÈÌÐԣ¬ÒÔ×ԼºµÄҪǿ£¬»áÈÃÈ˵±×÷Öí¹·£¬»áά³ֲ»סһ¸öÊÂÇ飬Ëû²»ֻԹºÞÑî¼ÒÄÇһ»ïÈˣ¬¶øÃìãµľõµ½һÖÖÎÞÍû£¬¿ÖÅÂ×Լºһ±²×Ӳ»»áÔÙÓÐʲôÆðɫÁˡ£À­×ÅÆ̸Ǿí£¬ËûԽ×ßԽÂý£¬ºÃÏó×ԼºÒѾ­²»ÊÇÄÃÆðÍȾÍÄÜÅܸöʮÀï°ËÀïµÄÏé×ÓÁˡ£ @@ -444,7 +444,7 @@ »¢¹ÃÄï¹ýÀ´£¬°ÑǮץÔÚÊÖÖУ¬ÍùËûµÄÒ´üÀïÈû£º¡°ÕâÁ½ÌìÁ¬³µ´øÈ˶¼°×ËÍÁˣ¡ÄãÕâС×ÓÓеãÔËÆø£¡±ðÍü¶÷¸ºÒå¾͵ÃÁˣ¡¡±˵Í꣬ËýһתÉí°ÑÃŵ¹ËøÉϡ£ -Æß +Æß Ïé×ÓÉÏÁ˲Üլ¡£ @@ -530,7 +530,7 @@ Ïé×ӵÄÓÒÖâºÜÌۣ¬°ëҹҲû˯ך£µßËãÁËÆ߿ª°˵ã¬Ëû¾õµøßÂèµĻ°ÓÐÀí¡£ʲôҲÊǼٵģ¬ֻÓÐǮÊÇÕæµġ£ʡǮÂ򳵣»¹һ𵱲»Á˳Է¹£¡Ï뵽Õ⣬À´ÁËһµãƽ°²µÄ˯Ò⡣ -°Ë +°Ë ²ÜÏÈÉú°ѳµÊÕʰºã¬²¢û¿ÛÏé×ӵŤǮ¡£²Ü̫̫¸øËûÁ½Í衰Èý»Ʊ¦À¯¡±£¬ËûҲû³ԡ£ËûûÔÙÌá´ǹ¤µÄÊ¡£ËäȻºü¸Ìì×ܾõµò»´óºÃÒâ˼£¬¿ÉÊǸßÂèµĻ°µõ½×îºóµÄʤÀû¡£¹ýÁËЩÈÕ×ӣ¬Éú»îÓֺÏÁËÕޣ¬Ëû°ÑÕâ¼þʽ¥½¥Íüµô£¬һÇеÄϣÍûÓÖÖØÐ·¢ÁËѿ¡£¶À×øÔÚÎÝÖеÄʱºò£¬ËûµÄÑ۷¢×ÅÁÁ¹⣬ȥÅÌËãÔõÑùʡǮ£¬ÔõÑùÂ򳵣»×ìÀﻹ²»סµÄà½à죬ÏóÓеãÐIJ¡ËƵġ£ËûµÄË㷨ºܲ»¸ßÃ÷£¬¿ÉÊÇÐÄÖкÍ×ìÉϳ£³£Äîך°ÁùÁùÈýʮÁù¡±£»ÕⲢÓëËûµÄǮÊýû¶àÉٹØϵ£¬²»¹ýÊÇÕâôÄîµÀ£¬ÐÄÖкÃÏóÊdzäʵһЩ£¬ÕæÏóÓÐһ±¾ÕËËƵġ£ @@ -592,7 +592,7 @@ Ïé×ӵÄÁ³ºöȻºìµÃÏó°ü×ÅһÍŻð£¬Ëû֪µÀÊÂÇéҪ»µ£¡ -¾Å +¾Å Ïé×Ӽ¸ºõûÓÐÁ¦Á¿Âõ³ö´óÃſ²ȥ¡£»èͷ´òÄԵ쬽ݹÔÚÃſ²Äڣ¬½è׎ÖÉϵĵƹ⣬Òѿ´¼ûÁËÁõ¹ÃÄËýµÄÁ³Éϴó¸ÅÓֲÁÁ˷ۣ¬±»µƹâÕյÃÏԳöµã»ÒÂÌɫ£¬ÏóºڿÝÁ˵ÄÊ÷ҶÉϹÒ×Ųã˪¡£Ïé×Ӳ»¸ÒÕýÑۿ´Ëý¡£ @@ -686,7 +686,7 @@ ÃðÁ˵ƣ¬°ÑͷÍêȫ¸ÇÔڱ»×ÓÀËûÏë¾ÍÕâô˯ȥ¡£»¹ÊÇ˯²»×ţ¬Ïƿª±»¿´¿´£¬´°ֽ±»ԺÖеÄÔ¹âӳµ÷¢Ç࣬ÏóÌìҪÁÁµÄÑù×ӡ£±Ǽâ¾õµ½ÎÝÖеĺ®À䣬º®ÆøÖдø×ÅЩ¾Æζ¡£ËûÃ͵Ä×øÆðÀ´£¬Ãþס¾ÆÍ룬ÍÌÁËһ´ó¿ڣ¡ -ʮ +ʮ ¸ö±ðµĽâ¾ö£¬Ïé×ÓûÄÇô´ÏÃ÷¡£ȫÅ̵ÄÇåË㣬ËûûÄǸöÆÇÁ¦¡£ÓÚÊǣ¬һµã¶ù°취ûÓУ¬ÕûÌì¼ÊȦ×ÅÂú¶Ç×ÓίÇü¡£ÕýºÍһÇеÄÉúÃüͬÑù£¬ÊÜÁËËðº¦֮ºó£¬Î޿ÉÈçºεÄֻÏëÓÉ×ԼºȥÊÕʰ²о֡£ÄǶ·ÂäÁ˴óÍȵÄó¬󰣬»¹ÏëÓÃÄÇЩСÍȶùÅÀ¡£Ïé×ÓûÓÐһ¶¨µÄÖ÷Ò⣬ֻÏëÂýÂýµÄһÌìÌ죬һ¼þ¼þµİ¤¹ýȥ£¬ÅÀµ½ÄĶùËãÄĶù£¬¸ù±¾²»ÏëÍùÆðÌøÁˡ£ @@ -786,7 +786,7 @@ µçӰɢÁˣ¬Ëû¼±æµİÑСˮͲ°²ºã¬µã×ÅÁ˵ơ£Á¬СÃްÀҲÍÑÁˣ¬ֻʣÁ˼þС¹ӣ¬ËûÏë·ÉÅÜһÆø£¬ÅÜÍüÁËһÇУ¬ˤËÀҲû¶à´ó¹Øϵ£¡ -ʮһ +ʮһ һÏ뵽ÄǸöÀÏÕßÓëСÂí¶ù£¬Ïé×ӾͰÑһÇеÄϣÍû¶¼Ҫ·ÅÏ£¬¶øÏëÀÖһÌìÊÇһÌì°ɣ¬¸ÉÂð³ÉÌì¼Êҧ×ÅÑÀ¸ú×Լº¹ý²»ȥÄأ¿£¡ÇîÈ˵ÄÃü¡¢ËûËƺõ¿´Ã÷°×Áˣ¬ÊÇÔæº˶ùÁ½ͷ¼⣺Ó×СµÄʱºòÄܲ»¶öËÀ£¬ÍòÐң»µ½ÀÏÁËÄܲ»¶öËÀ£¬ºÜÄѡ£ֻÓÐÖмäµÄһ¶Σ¬ÄêÇáÁ¦׳£¬²»Å¼¢±¥À͵£¬»¹ÄÜÏó¸öÈ˶ùËƵġ£ÔÚÕâһ¶ÎÀ¸ÿì»î¿ì»îµÄʱº򻹲»¸Òȥ¸ɣ¬µصÀµÄɵ×ӣ»¹ýÁËÕâ´å±ãûÓÐÕâµ꣡ÕâôһÏ룬ËûÁ¬»¢椵ÄÄǻØÊ¶ù¶¼²»Ï뷢³îÁˡ£ @@ -906,7 +906,7 @@ ѩÒÑÏÂÁ˴ç¶àºñ£¬Ïé×ӵÍ×Åͷ×ߡ£´¦´¦½à°ף¬ֻÓÐËûµÄÉíºóÁô×ÅЩ´óºڽÅӡ¡£ -ʮ¶þ +ʮ¶þ Ïé×ÓÏëÕҸöµط½×øÏ£¬°ÑǰǰºóºóϸÏëһ±飬ÄÄÅÂÏëÍêֻÄܿÞһ³¡Äأ¬ҲºÃ֪µÀ¿޵ÄÊÇʲô£»ÊÂÇé±仯µÃ̫¿ìÁˣ¬ËûµÄÄÔ×ÓÒÑ׷¸ϲ»Éϡ£ûÓеط½¸øËû×ø£¬µ½´¦ÊÇѩ¡£С²è¹ÝÃÇÒѶ¼ÉÏÁËÃţ¬ʮµã¶àÁˣ»¾ÍÊǿª×ţ¬ËûҲ²»¿Ͻøȥ£¬ËûԸÒâÕҸöÇ徲µط½£¬Ëû֪µÀ×ԼºÑۿôÖÐת×ŵÄÀáËæʱ¿ÉÒÔÂäÏÂÀ´¡£¼Èûµط½×øһ×ø£¬ֻºÃÂýÂýµÄ×߰ɣ»¿ÉÊǣ¬ÉÏÄÄÀïȥÄأ¿Õâ¸öÒø°׵ÄÊÀ½磬ûÓÐËû×øÏµĵط½£¬ҲûÓÐËûµÄȥ´¦£»°×ããµÄһƬ£¬ֻÓжö×ŶÇ×ӵÄСÄñ£¬Óë×ßͶÎÞ·µÄÈˣ¬֪µÀʲô½Ð×÷°§̾¡£ @@ -1032,7 +1032,7 @@ ¡°ÐУ¡¡± -ʮÈý +ʮÈý ÒòÓÐѩ¹⣬Ìì··ðÁÁµÃÔçÁËЩ¡£¿쵽Äêµף¬²»ÉÙÈ˼ÒÂòÀ´¼¦ι×ţ¬¼¦µÄÃùÉù±ÈÍùÈնàÁ˼¸±¶¡£´¦´¦¼¦Ì䣬´óÓÐЩ·áÄêÈðѩµľ°¿ö¡£Ïé×ӿÉÊÇһҹû˯ºá£µ½ºó°ëҹ£¬ËûÈÌÁ˼¸¸öíï¶ù£¬ÃÔÃԺýºýµģ¬ËÆ˯²»˯µģ¬Ïó¸¡ÔÚˮÉÏÄÇÑùºöÆðºöÂ䣬ÐÄÖв»°²¡£Խ˯ԽÀ䣬Ìýµ½ÁËËÄÍâµļ¦½У¬ËûʵÔڳŲ»סÁˡ£²»Ը¾ª¶¯Àϳ̣¬Ëûòé×ÅÍȣ¬Óñ»×ӶÂÉÏ×ì¿ÈËԣ¬»¹²»¸ÒÆðÀ´¡£ @@ -1150,7 +1150,7 @@ ´ó¼ҵÄŭÆø··ðºöȻÕҵ½Á˳ö·£¬¶¼µÉ×ÅÏé×ӵĺóӰ¡£ÕâÁ½ÌìÁˣ¬´ó¼Ҷ¼¾õµÃÏé×ÓÊÇÁõ¼ҵÄ×߹·£¬ËÀÃüµİͽᣬÈÎÀÍÈÎԹµĵ±Ëé´ߢڡ£Ïé×ÓһµãҲ²»֪µÀÕâ¸ö£¬°ïÖúÁõ¼Ò×÷Ê£¬ΪÊÇ֧×ßÐÄÖеķ³Äգ»ÍíÉÏû»°ºʹó¼Ò˵£¬ÒòΪ±¾À´û»°¿É˵¡£ËûÃDz»֪µÀËûµÄίÇü£¬¶øÒÔΪËûÊǰͽáÉÏÁËÁõËÄү£¬ËùÒԲ»мÓںÍËûÃǽ»̸¡£»¢椵ÄÕÕӦÏé×ӣ¬Ôڴó¼ÒÐÄÖÐÌرðµķ¢×ŵãËá棬Ï뵽ĿǰµÄÊ£¬ÁõËÄү²»׼ËûÃÇÔÚϲÅïÀïÀ´Íù£¬¿ÉÊÇÏé×Óһ¶¨¿ÉÒԳÔһÕûÌìºõģ»ͬÊÇÀ­³µµģ¬ΪʲôÓÐÈýÁù¾ŵÈÄأ¿¿´£¬Áõ¹ÃÄïÓְÑÏé×ӽгöȥ£¡´ó¼ҵÄÑ۸ú×ÅÏé×ӣ¬ÍÈҲÏ붯£¬¶¼´îڨ×Å×߳öÀ´¡£Áõ¹ÃÄïÕýºÍÏé×ÓÔÚúÆøµƵ×ÏÂ˵»°Äأ¬´ó¼ұ˴˵ãÁ˵ãͷ¡£ -ʮËÄ +ʮËÄ Áõ¼ҵÄʰìµúÜÈÈÄ֡£ÁõËÄүºÜÂúÒâÓÐÕâô¶àÈËÀ´¸øËû¿ÄͷףÊ١£¸ü×ãÒÔ×԰ÁµÄÊÇÐí¶àÀÏÅóÓÑҲ¸Ï×ÅÀ´ºØϲ¡£ÓÉÕâЩÀÏÓѣ¬Ëû¿´³ö×ԼºÕⳡʲ»µ«°ìµÃÈÈÄ֣¬¶øÇҡ°¸ÄÁ¼¡±¡£ÄÇЩÀÏÓѵĴ©´÷ÒѾ­ÂäÎ飬¶øËÄүµÄƤÅÛÂí¹Ӷ¼ÊÇÐÂ×÷µġ£ÒÔְҵ˵£¬Óкü¸λÅóÓÑÔڵ±Ä궼±ÈËûÀ«£¬¿ÉÊÇÏÖÔڡª¡ª¾­¹ýÕâ¶þÈýʮÄêÀ´µıäǨ¡ª¡ªÒÑԽ»ìԽµͣ¬ÓеÄÒѺÜÄѳÔÉϱ¥·¹¡£¿´×ÅËûÃǣ¬Ôٿ´¿´×ԼºµÄϲÅÊÙÌ㬻­×ų¤ÛàÆµĹÒÆÁ£¬ÓëÈý¸öº£ÍëµÄϯÃ棬Ëû¾õµÃ×ԼºȷÊǸ߳öËûÃÇһͷ£¬Ëû¡°¸ÄÁËÁ¼¡±¡£Á¬¶ÄǮ£¬Ëû¶¼Ԥ±¸ÏÂÂ齫Åƣ¬±ÈѺ±¦¾Í͸×ÅÎÄÑÅÁËÐí¶ࡣ¿ÉÊǣ¬ÔÚÕâ¸öÈÈÄֵľÖÃæÖУ¬ËûҲ¸оõµ½һµãÆàÁ¹Äѹý¡£¹ý¹ßÁ˶ÀÉíµÄÉú»ËûԭÏëÔÚÊÙÈÕÀ´µÄÈ˲»¹ýÊÇÆ̻§ÖеÄÕƹñÓëÏÈÉúÃǣ¬ºÍÍùÈս»ÏµÄÍⳡ¹â¹÷¡£ûÏ뵽»áҲÀ´ÁËЩŮ¿͡£ËäȻ»¢æ¤ÄÜÌæËûÕдý£¬¿ÉÊÇËûºöȻ¸е½×ԼҵŶÀ£¬ûÓÐÀϰé¶ù£¬ֻÓиöٶù£¬¶øÇҳ¤µÃÏó¸öÄÐ×ӡ£¼ÙÈô»¢æ¤ÊǸöÄÐ×ӣ¬µ±ȻÔçÒѳÉÁ˼ң¬ÓÐÁËСº¢£¬¼´ʹ×ԼºÊǸöÀÏ÷¤·򣬻òÕßҲ¾Ͳ»Õâô¹¿àÁæØêµÄÁˡ£Êǵģ¬×ԼºʲôҲ²»ȱ£¬ֻȱ¸ö¶ù×ӡ£×ԼºµÄÊÙÊýԽ´ó£¬Óжù×ӵÄϣÍû±ãԽС£¬ףÊٱ¾ÊǼþϲÊ£¬¿ÉÊÇÓÖËƺõӦÂäÀᡣ²»¹Ü×ԼºÔõÑù¸ÄÁËÁ¼£¬ûÈ˼ÌÐø×ԼºµÄÊÂҵ£¬һÇл¹²»Êǰ×Èģ¿ @@ -1244,7 +1244,7 @@ Ïé×ÓֱͦͦµÄÁ¢ÔÚÄÇÀûÓÐһ¾仰¿É˵¡£ -ʮÎå +ʮÎå ½²¶¯Î䣬Ïé×Ӳ»Äܴò¸öÀÏÈˣ¬Ҳ²»Äܴò¸ö¹ÃÄËûµÄÁ¦Á¿ûµط½Óá£ˣÎÞÀµ£¬ֻÄÜÏëÏ룬ˣ²»³ö¡£Âۻ¢æ¤Õâ¸öÈˣ¬ËûÂú¿ÉÒԶå½ÅһÅܡ£ΪĿǰÕâһ³¡£¬Ëý¼ÈȻº͸¸Ç×Äַ­£¬¶øÇÒԸÒâ¸úËû×ߣ»¹Ç×ÓÀïµÄÊÂûÈËÏþµã¬±íÃæÉÏËýÊÇΪÏé×ӶøÎþÉü£»µ±×Ŵó¼ÒÃæǰ£¬Ëûû·¨²»ÄóöµãӢÐÛÆø¶ùÀ´¡£Ëûû»°¿É˵£¬ֻÄÜÁ¢ÔÚÄÇÀµȸöˮÂäʯ³ö£»ÖÁÉÙËûµÃ×÷µ½Õâ¸ö£¬²ÅÄÜÏó¸öÄÐ×Ӻº¡£ @@ -1342,7 +1342,7 @@ Ïé×ÓÓÖûÁ˻°¡£ -ʮÁù +ʮÁù Ïе½ԪÏü½ڣ¬Ïé×Óû·¨ÔÙÈÌÏÂȥÁˡ£ @@ -1426,7 +1426,7 @@ Ïé×ÓÐÄÖкܸßÐˡ£¼ÙÈôÕâ¸öÖ÷ÒâÄÜʵÏ֣¬ËûËãÊÇÓÖÀ­ÉÏÁË×Լºµijµ¡£ËäȻÊÇÀÏÆŸøÂòµģ¬¿ÉÊÇÂýÂýµÄÔÜǮ£¬×Լº»¹ÄÜÔÙÂ򳵡£ֱµ½Õâ¸öʱºò£¬Ëû²žõ³öÀ´»¢æ¤ҲÓеãºô¦£¬Ëû¾ÓȻÏòËýЦÁËЦ£¬һ¸öÌìÕæµģ¬·¢×ÔÄÚÐĵÄЦ£¬··ð°ÑÒÔǰµÄÀ§¿àȫһ±ʹ´Ïú£¬¶øЦׯ»Á˸öеÄÊÀ½磬Ïó»»һ¼þÒ·þÄÇôÈÝÒף¬ʹ¿죡 -ʮÆß +ʮÆß Ïé×ÓÂýÂýµİÑÈ˺ͳ§µÄÊ´òÌýÃ÷°ףºÁõËÄү°Ñһ²¿·ֳµÂô³öȥ£¬ʣϵÄȫµ¹¸øÁËÎ÷³ÇÓÐÃûµÄһ¼ҳµÖ÷¡£Ïé×ÓÄܲÂÏëµóö£¬ÀÏͷ×ӵÄËêÊýµ½Áˣ¬ûÓÐٶù°ïËûµÄ棬ËûŪ²»תÕâ¸öӪҵ£¬ËùÒԸɴà°ÑËüÊÕÁˣ¬×ԼºÄÃ×ÅǮȥÏí¸£¡£Ëûµ½ÄÄÀïȥÁËÄأ¿Ïé×ӿÉÊÇûÓдòÌý³öÀ´¡£ @@ -1498,7 +1498,7 @@ Ïé×ÓʲôҲ²»֪µÀ£¬¿ÉÊÇËûÓÖ˯²»ºþõÁˡ£»¢椡°³Éȫ¡±ÁËС¸£×ӣ¬ҲҪÔÚÏé×ÓÉíÉÏÕҵ½ʧȥÁ˵ÄÇഺ¡£ -ʮ°Ë +ʮ°Ë µ½ÁËÁùÔ£¬´óÔÓԺÀïÔڰ×Ìì¼òֱûʲôÈËÉù¡£º¢×ÓÃÇץÔç¶ùÌá×ÅÆƿðȥʰËùÄÜʰµ½µĶ«Î÷£»µ½Á˾ŵ㣬¶¾»¨»¨µÄ̫ÑôÒÑҪ½«ËûÃǵÄÊݼ¹±³ɹÁѣ¬ֻºÃÄûØÀ´ËùʰµõĶ«Î÷£¬³ÔЩ´óÈËËùÄܸøËûÃǵÄʳÎȻº󣬴óһµãµÄҪÊÇÄÜÕҵ½ÊÀ½çÉÏ×îСµÄ×ʱ¾£¬±ãȥÁ¬Âò´øʰ£¬´ÕЩ±ùºËȥÂô¡£ÈôÕҲ»µ½Õâµã×ʱ¾£¬±ã½á°é³ö³ǵ½»¤³ǺÓÀïȥϴÔ裬˳ÊֶùÔڳµվÉÏ͵¼¸¿éú£¬»ò׽ЩòßòÑÓë֪Á˶ùÂôÓëÄǸ»¹óÈ˼ҵÄС¶ù¡£ÄÇСЩµģ¬²»¸ÒÍùԶ´¦Åܣ¬¶¼µ½ÃÅÍâÓÐÊ÷µĵط½£¬ʰ»±³棬Íڡ°½ð¸֡±¢ÙʲôµÄȥÍ档º¢×Ӷ¼³öȥ£¬ÄÐÈËҲ¶¼³öȥ£¬¸¾ŮÃǶ¼³àÁ˱³ÔÚÎÝÖУ¬˭Ҳ²»¿ϳöÀ´£»²»ÊÇÅÂÄѿ´£¬¶øÊÇÒòΪԺÖеĵØÒѾ­ɹµÃÌ̽š£ @@ -1566,7 +1566,7 @@ Ïé×Ӳ¡Áˡ£´óÔÓԺÀïµIJ¡È˲¢²»ֹÓÚËûһ¸ö¡£ -ʮ¾Å +ʮ¾Å Ïé×ӻè»è³Á³ÁµÄ˯ÁËÁ½Öçҹ£¬»¢æ¤×ÅÁ˻𣵽ÄïÄïÃí£¬ËýÇóÁ˸öÉ񷽣ºһµãÏã»Ò֮Í⣬»¹ÓÐÁ½Èýζ²Ýҩ¡£¸øËû¹àÏÂȥ£¬ËûµÄȷÕö¿ªÑۿ´Á˿´£¬¿ÉÊǴýÁËһ»á¶ùÓÖ˯×ÅÁˣ¬×ìÀïßóß󹾹¾µIJ»ÏþµÃ˵ÁËЩʲô¡£»¢æ¤Õâ²ÅÏëÆðȥÇë´ó·ò¡£ÔúÁËÁ½Õ룬·þÁ˼Áҩ£¬ËûÇåÐѹýÀ´£¬һÕöÑ۱ãÎʣº¡°»¹ÏÂÓêÂ𣿡± @@ -1654,7 +1654,7 @@ »¢æ¤ÔÚҹÀïʮ¶þµ㣬´ø×ŸöËÀº¢×ӣ¬¶ÏÁËÆø¡£ -¶þʮ +¶þʮ Ïé×ӵijµÂôÁˣ¡ @@ -1752,7 +1752,7 @@ ËûºÜÏë´ǹ¤²»¸ÉÁˡ£¿ÉÊǣ¬ΪÕâµ㲻¿¿±ߵÄʶø´ǹ¤£¬Óַ·ð²»Ï󻰣»Îüך°»Æʨ×ӡ±£¬Ëû×ÔÑÔ×ÔÓïµÄ˵£¬¡°¹ܱðÈ˵ÄÏÐʸÉÂ𣿣¡¡± -¶þʮһ +¶þʮһ ¾ջ¨ÏÂÊеÄʱºò£¬ÏÄ̫̫ÒòΪÂòÁËËÄÅ軨£¬¶ø±»ŮÆÍÑîÂèˤÁËһÅ裬¾ͺÍÑîÂ賳ÄÖÆðÀ´¡£ÑîÂèÀ´×ÔÏç¼䣬¸ù±¾ÒÔΪ»¨²ÝË㲻ÁËʲôÖØҪµĶ«Î÷£»²»¹ý£¬¼ÈÊǴòÁËÈ˼ҵÄÎï¼þ£¬²»¹ÜÔõô²»ÖØҪ£¬×ÜÊÇ×Լº´ÖÐĴóÒ⣬ËùÒԾÍһÉùû¸ҳö¡£¼°ÖÁÏÄ̫̫ÄÖÉÏûÍ꣬´åµÄҰµÄһ¾¢¶ù½ÐÂÑîÂèµĻð¶ùÔÙҲ°´²»ס£¬¿ɾͻ¹Á˿ڡ£ÏçÏÂÈ˼±Áˣ¬²»»áÄÃ×ųߴç˵»°£¬Ëý¶¶×ŵ׶ù°Ñ×î´ÖҰµÄÂî³öÀ´¡£ÏÄ̫̫Ìø×ŽŶùÂîÁËһÕ󣬽ÌÑîÂèÂíÉϾíÆ̸ǹöµ°¡£ @@ -1846,7 +1846,7 @@ Ëû×߳öÀÏԶ£¬»Øͷ¿´Á˿´£¬ÀÏͷ×ӡª¡ªһ¸ö´óºÚӰËƵġª¡ª»¹ÔÚÄǶùվ×ÅÄء£ -¶þʮ¶þ +¶þʮ¶þ Ïé×ÓÍüÁËÊÇÍùÄÄÀï×ßÄء£Ëû°º×Åͷ£¬˫Êֽô½ôÎÕס³µ°ѣ¬Ñ۷Å׏⣬Âõ×Ŵó²½Íùǰ×ߣ»ֻ¹˵Ã×ߣ¬²»¹ܷ½ÏòÓëĿµĵء£ËûÐÄÖÐʹ¿죬ÉíÉÏÇáËɣ¬··ð°Ñ×ԴÓȢÁ˻¢æ¤֮ºóËùÓеĵ¹ùһ¹É£×ܶ¼ÅçÔÚÁõËÄүÉíÉϡ£ÍüÁËÀ䣬ÍüÁËÕÅÂÞÂòÂô£¬ËûֻÏëÍùǰ×ߣ¬··ð×ߵ½ʲôµط½Ëû±ØÄÜÕһØԭÀ´µÄ×Լº£¬ÄǸöÎÞǣÎ޹ң¬´¿½࣬Ҫǿ£¬´¦´¦ŬÁ¦µÄÏé×ӡ£ÏëÆðºúͬÖÐÁ¢×ŵÄÄǿéºÚӰ£¬ÄǸöÀÏÈˣ¬ËƺõʲôҲ²»±ØÔÙ˵Áˣ¬սʤÁËÁõËıãÊÇսʤÁËһÇС£ËäȻû´òÕâ¸öÀϼһïһȭ£¬ûõßËûһ½ţ¬¿ÉÊÇÀÏͷ×ÓʧȥΨһµÄÇ×Èˣ¬¶øÏé×ӷ´µ¹åÐң×ÔÔڣ»˭˵ÕⲻÊDZ¨ӦÄأ¡ÀÏͷ×ÓÆø²»ËÀ£¬ҲµÃÀëËÀ²Զ£¡ÁõÀÏͷ×ÓÓÐһÇУ¬Ïé×ÓʲôҲûÓУ»¶ø½ñ£¬Ïé×ӻ¹¿ÉÒԸ߸ßÐËÐ˵ÄÀ­³µ£¬¶øÀÏͷ×ÓÁ¬Ů¶ùµķØҲÕҲ»µ½£¡ºðɣ¬ËæÄãÀÏͷ×ÓÓгɶѵÄÑóǮ£¬ÓëÌì´óµÄƢÆø£¬ÄãÖβ»·þÕâ¸öһÌìÏֻìÁ½¸ö±¥µÄÇî¹⵰£¡ @@ -1942,7 +1942,7 @@ Ñ̾ÆÓֳÉÁËËûµÄÅóÓѡ£²»ÎüÑÌÔõÄÜ˼Ë÷Äأ¿²»ºÈ×íÔõÄÜֹͣס˼Ë÷Äأ¿ -¶þʮÈý +¶þʮÈý Ïé×ÓÔڽÖÉÏɥµ¨ÓλêµÄ×ߣ¬Óö¼ûÁËСÂí¶ùµÄ×游¡£ÀÏͷ×ÓÒѲ»À­³µ£¬ÉíÉϵÄÒÂÉѱÈÒÔǰ¸ü±¡¸üÆƣ¬¿¸×ŸùÁøľ¹÷×ӣ¬ǰͷ¹Òןö´óÍߺø£¬ºóÃæÐüןöÆÆԪ±¦¿ð×ӣ¬¿ð×ÓÀïÓÐЩÉձýÓ͹íºÍһ´ó¿éשͷ¡£Ëû»¹ÈÏʶÏé×ӡ£ @@ -2004,7 +2004,7 @@ ÂýÂýµİÑլÃŶ¼´®¾»£¬ËûÓִ®Á˸öµڶþ»أ¬Õâ´οɾÍÒѾ­²»ºÜÁéÑéÁˡ£Ëû¿´³öÀ´£¬ÕâÌõ·×Ӳ»Äܿ¿³¤£¬µÃÁíÏëÖ÷Ò⣬µÃÏë±ÈÀ­³µÈÝÒ×ÕõǮµÄÖ÷Ò⡣ÔÚÏÈǰ£¬ËûΨһµÄָÍû±ãÊÇÀ­³µ£»ÏÖÔڣ¬ËûÌÖÑáÀ­³µ¡£×ÔȻËûһʱ²»ÄÜÍêȫºͳµ¶Ͼø¹Øϵ£¬¿ÉÊÇֻҪÓз¨×ÓÄÜÔÝʱ¶Ը¶Èý²ͣ¬Ëû±㲻¿ÏȥÃþ³µ°ѡ£ËûµÄÉí×ÓÀÁ£¬¶ø¶ú¶äºܼ⣬ÓиöÏûϢ£¬Ëû¾ÍÅܵ½ǰÃæȥ¡£ʲô¹«ÃñÍÅß֣¬ʲôÇëԸÍÅß֣¬·²ÊÇÓÐÈ˳öǮµÄÊ£¬Ëûȫ¸ɡ£ÈýëҲºã¬Á½ëҲºã¬ËûÀÖÒâȥ´òһÌìÆì×ӣ¬Ëæ×ÅÈËȺÂÒ×ߡ£Ëû¾õµÃÕâÎÞÂÛÔõÑùҲ±ÈÀ­³µǿ£¬ÕõǮ²»¶࣬¿ÉÊDz»ÓÃÂôÁ¦ÆøÄء£´ò×ÅÃæСÆ죬ËûµÍ×Åͷ£¬×ìÀïµð×ÅÑ̾í£¬ËÆЦ·ÇЦµÄËæ×Ŵó¼Ò×ߣ¬һÉùҲ²»³ö¡£µ½·Ǻ°½м¸Éù²»¿ɵÄʱºò£¬Ëû»áÕſª´ó×죬¶øÍêȫûÉù£¬Ëû°®ϧ×ԼºµÄɤ×ӡ£¶ÔʲôÊÂËûҲ²»ÏëÓÃÁ¦£¬ÒòΪÒÔǰÂô¹ýÁ¦Æø¶ø²¢ûÓзֺÁµĺô¦¡£ÔÚÕâÖִòÆìÄź°µÄʱºò£¬ÉèÈôÓö¼ûµãʲôΣÏգ¬Ëûͷһ¸öÏÈÅܿª£¬¶øÇÒÅܵúܿ졣ËûµÄÃü¿ÉÒԻÙÔÚ×ԼºÊÖÀÔÙҲ²»ΪÈκÎÈËÎþÉüʲô¡£Ϊ¸öÈËŬÁ¦µÄҲ֪µÀÔõÑù»ÙÃð¸öÈˣ¬ÕâÊǸöÈËÖ÷ÒåµÄÁ½¶ˡ£ -¶þʮËÄ +¶þʮËÄ Óֵ½Á˳¯¶¥½øÏãµÄʱ½ڣ¬ÌìÆø±©ÈÈÆðÀ´¡£ diff --git a/assets/books/princekin/princekin.txt b/assets/books/princekin/princekin.txt index 0cc1df5..87b564a 100644 --- a/assets/books/princekin/princekin.txt +++ b/assets/books/princekin/princekin.txt @@ -22,7 +22,7 @@ LE PETIT PRINCE С Íõ ×Ó - I + I µ±Îһ¹ֻÓÐÁùËêµÄʱºò£¬ÔÚһ±¾ÃèдԭʼɭÁֵÄÃû½С¶ÕæʵµĹÊÊ¡·µÄÊéÖУ¬ @@ -80,7 +80,7 @@ LE PETIT PRINCE ÊǴóÈËÃǾÍʮ·ָßÐËÄÜÈÏʶÎÒÕâÑùһ¸öͨÇé´ïÀíµÄÈˡ£ - II + II ÎҾÍÕâÑù¹¶ÀµØÉú»î×ţ¬ûÓÐһ¸öÄÜÕæÕý̸µÃÀ´µÄÈˣ¬һֱµ½ÁùÄêǰÔÚÈö¹þ @@ -190,7 +190,7 @@ LE PETIT PRINCE ¾ÍÕâÑù£¬ÎÒÈÏʶÁËСÍõ×ӡ£ - III + III ÎҷÑÁ˺ó¤ʱ¼ä²ÅŪÇå³þËûÊǴÓÄÄÀïÀ´µġ£СÍõ×ÓÏòÎÒÌá³öÁ˺ܶàÎÊÌ⣬¿É @@ -269,7 +269,7 @@ LE PETIT PRINCE ¡°һֱ³¯ǰ×ߣ¬Ҳ²»»á×߳ö¶àԶ¡­¡± - IV + IV Îһ¹Á˽⵽Áíһ¼þÖØҪµÄÊ£¬¾ÍÊÇËûÀϼÒËùÔڵÄÄǸöÐÇÇò±Èһ×ù·¿×Ӵó²»ÁË @@ -358,7 +358,7 @@ LE PETIT PRINCE ÈËÃDz¶ࡣÎÒһ¶¨ÊDZäÀÏÁˡ£ - V + V ÿÌìÎҶ¼Á˽⵽һЩ¹ØÓÚСÍõ×ӵÄÐÇÇò£¬Ëûµijö×ߺÍÂÃÐеÈÊÂÇ顣ÕâЩ¶¼ÊÇ @@ -446,7 +446,7 @@ LE PETIT PRINCE һÖּ±ÇеÄÐÄÇéÔڼ¤Àø×ÅÎҡ£ - VI + VI °¡£¡СÍõ×ӣ¬¾ÍÕâÑù£¬ÎÒÖ𽥶®µÃÁËÄãÄÇÓÇÓôµÄÉú»¹ýȥÏ൱³¤µÄʱ¼äÀï @@ -482,7 +482,7 @@ LE PETIT PRINCE СÍõ×ÓûÓлشð¡£ - VII + VII µÚÎåÌ죬»¹ÊÇÑòµÄÊ£¬°ÑСÍõ×ӵÄÉú»îÃØÃÜÏòÎҽҿªÁˡ£ºÃÏóĬĬµØ˼Ë÷ÁË @@ -589,7 +589,7 @@ LE PETIT PRINCE ´ﵽËûµľ³½磬ÔõÑù²ÅÄÜÔٽøÈëËûµľ³½硭°¦£¬ÀáˮµÄÊÀ½çÊǶàôÉñÃذ¡£¡ - VIII + VIII ºܿìÎҾͽøһ²½Á˽âÁËÕâ¶仨¶ù¡£ÔÚСÍõ×ӵÄÐÇÇòÉϣ¬¹ýȥһֱ¶¼Éú³¤×Åһ @@ -687,7 +687,7 @@ LE PETIT PRINCE - IX + IX ÎÒÏëСÍõ×Ӵó¸ÅÊÇÀûÓÃһȺºòÄñǨáãµĻú»áÅܳöÀ´µġ£ÔÚËû³ö·¢µÄÄÇÌìÔçÉϣ¬ @@ -741,7 +741,7 @@ LE PETIT PRINCE ËýÊÇÅÂСÍõ×ӿ´¼ûËýÔڿޡ£ËýÊÇһ¶ä·dz£½¾°ÁµĻ¨¡­ - X + X Ôڸ½½üµÄÓîÖæÖУ¬»¹ÓÐ 325¡¢326¡¢327¡¢328¡¢329¡¢330 µȼ¸¿ÅСÐÐÐǡ£Ëû @@ -911,7 +911,7 @@ LE PETIT PRINCE СÍõ×ÓÔÚÂÃ;ÖÐ×ÔÑÔ×ÔÓïµØ˵£º¡°ÕâЩ´óÈËÕæÆæ¹֡£¡± - XI + XI µڶþ¸öÐÐÐÇÉÏס×Åһ¸ö°®ÐéÈٵÄÈˡ£ @@ -963,7 +963,7 @@ LE PETIT PRINCE СÍõ×ÓÔÚ·ÉÏ×ÔÑÔ×ÔÓïµØ˵ÁËһ¾䣺¡°ÕâЩ´óÈˣ¬¿϶¨ÊÇʮ·ֹŹֵġ£¡± - XII + XII СÍõ×ÓËù·ÃÎʵÄÏÂһ¸öÐÇÇòÉÏס×Åһ¸ö¾ƹí¡£·ÃÎÊʱ¼ä·dz£¶̣¬¿ÉÊÇËüȴʹ @@ -993,7 +993,7 @@ LE PETIT PRINCE ÔÚÂÃ;ÖУ¬Ëû×ÔÑÔ×ÔÓïµØ˵µÀ£º¡°ÕâЩ´óÈËȷʵÕæ½й֡£¡± - XIII + XIII µÚËĸöÐÐÐÇÊÇһ¸öʵҵ¼ҵÄÐÇÇò¡£Õâ¸öÈËæµò»¿ɿª½»£¬СÍõ×ӵ½À´µÄʱºò£¬ @@ -1135,7 +1135,7 @@ LE PETIT PRINCE ÔÚÂÃ;ÖУ¬СÍõ×ÓֻÊÇ×ÔÑÔ×ÔÓïµØ˵ÁËһ¾䣺¡°ÕâЩ´óÈËÃÇÕæÊÇÆæ¹ּ«Áˡ£¡± - XIV + XIV µÚÎå¿ÅÐÐÐǷdz£Ææ¹֣¬ÊÇÕâЩÐÇÐÇÖÐ×îСµÄһ¿š£ÐÐÐÇÉϸպÃÄÜÈݵÃÏÂһյ @@ -1245,7 +1245,7 @@ LE PETIT PRINCE ÿ¶þʮËÄСʱ¾ÍÓÐһǧËİÙËÄʮ´ÎÈÕÂ䣡 - XV + XV µÚÁù¿ÅÐÐÐÇÔòҪ´óʮ±¶¡£ÉÏÃæס×ÅһλÀÏÏÈÉú£¬ËûÔÚд×÷´ó²¿ͷµÄÊ顣 @@ -1378,7 +1378,7 @@ LE PETIT PRINCE ÓÚÊÇСÍõ×ӾÍ×ßÁˣ¬Ëûһ±ß×ßһ±ßÏë×ÅËûµĻ¨¡£ - XVI + XVI µÚÆ߸öÐÐÐǣ¬ÓÚÊǾÍÊǵØÇòÁˡ£ @@ -1410,7 +1410,7 @@ LE PETIT PRINCE ¹ý×ÅÏÐÒݡ¢ÀÁɢµÄÉú»ËûÃÇÿÄêֻ¹¤×÷Á½´Ρ£ - XVII + XVII µ±ÈËÃÇÏëҪ˵µÃÇÎƤЩµÄʱºò£¬˵»°¾ͿÉÄܻ᲻´óʵÔڡ£ÔڸøÄãÃǽ²µãµÆÈË @@ -1496,7 +1496,7 @@ LE PETIT PRINCE ÓÚÊÇËûÃÇÓֶ¼³ÁĬÆðÀ´¡£ - XVIII + XVIII СÍõ×Ӵ©¹ýɳĮ¡£Ëûֻ¼û¹ýһ¶仨£¬һ¸öÓÐ×ÅÈýö»¨°êµĻ¨¶䣬һ¶äºܲ»Æð @@ -1524,7 +1524,7 @@ LE PETIT PRINCE ¡°Ôټû¡£¡±»¨˵¡£ - XIX + XIX СÍõ×ÓÅÀÉÏһ×ù¸ßɽ¡£¹ýȥËûËù¼û¹ýµÄɽ¾ÍÊÇÄÇÈý×ùֻÓÐËûϥ¸ÇÄÇô¸ߵĻð @@ -1552,7 +1552,7 @@ LE PETIT PRINCE ¶仨¡£Ëý×ÜÊÇ×ԼºÏÈ˵»°¡­¡± - XX + XX ÔÚɳĮ¡¢ÑÒʯ¡¢ѩµØÉÏÐÐ×ßÁ˺ܳ¤µÄʱ¼äÒԺó£¬СÍõ×ÓÖÕÓڷ¢ÏÖÁËһÌõ´ó·¡£ @@ -1590,7 +1590,7 @@ LE PETIT PRINCE ÆüÆðÀ´¡£ - XXI + XXI ¾ÍÔÚÕ⵱¶ù£¬ÅÜÀ´ÁËһֻºüÀꡣ @@ -1792,7 +1792,7 @@ LE PETIT PRINCE ¡°ÎÒҪ¶ÔÎҵÄõ¹帺Ô𡭡±СÍõ×ÓÓÖÖظ´×š­¡­ - XXII + XXII ¡°Äãºá£¡±СÍõ×Ó˵µÀ¡£ @@ -1836,7 +1836,7 @@ LE PETIT PRINCE ¡°ËûÃÇÕæÐÒÔˡ£¡±°âµÀ¹¤˵¡£ - XXIII + XXIII ¡°Äãºá£¡±СÍõ×Ó˵¡£ @@ -1858,7 +1858,7 @@ LE PETIT PRINCE Ȫ×ßȥ¡­¡± - XXIV + XXIV ÕâÊÇÎÒÔÚɳĮÉϳöÁËʹʵĵڰËÌ졣ÎÒÌý×ÅÓйØÕâ¸öÉÌÈ˵ĹÊÊ£¬ºÈÍêÁËÎÒ @@ -1960,7 +1960,7 @@ LE PETIT PRINCE ÓÚÊǣ¬¾ÍÕâÑù×ß×ţ¬ÎÒÔÚÀèÃ÷ʱ·¢ÏÖÁËˮ¾®¡£ - XXV + XXV ¡°ÄÇЩÈËÃǣ¬ËûÃÇÍù¿쳵Àïӵ¼·£¬µ«ÊÇËûÃÇȴ²»֪µÀҪѰÕÒʲô¡£ÓÚÊǣ¬Ëû @@ -2086,7 +2086,7 @@ LE PETIT PRINCE µ«Êǣ¬ÎҷÅÐIJ»Ï¡£ÎÒÏëÆðÁ˺üÀêµĻ°¡£Èç¹û±»ÈËѱ·þÁˣ¬¾ͿÉÄܻáҪ¿޵ġ­ - XXVI + XXVI Ôھ®ÅԱßÓÐһ¶²ÐȱµÄʯǽ¡£µڶþÌìÍíÉÏÎҹ¤×÷»ØÀ´µÄʱºò£¬ÎÒԶԶµؿ´¼û @@ -2329,7 +2329,7 @@ LE PETIT PRINCE ÓС£ - XXVII + XXVII µ½ÏÖÔڣ¬һµ㲻´í£¬ÒѾ­ÓÐÁùÄêÁˡ­Îһ¹´Óδ½²¹ýÕâ¸ö¹ÊÊ¡£ͬ°éÃÇÖØÐ¼û diff --git a/assets/books/theThreeKingdoms/theThreeKingdoms.txt b/assets/books/theThreeKingdoms/theThreeKingdoms.txt index 798704d..debfcb7 100644 --- a/assets/books/theThreeKingdoms/theThreeKingdoms.txt +++ b/assets/books/theThreeKingdoms/theThreeKingdoms.txt @@ -1,4 +1,4 @@ -第1章 宴桃园豪杰三结义 斩黄巾英雄首立功 +第1章 宴桃园豪杰三结义 斩黄巾英雄首立功   滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山依旧在,几度夕阳红。 白发渔樵江渚上,惯看秋月春风。一壶浊酒喜相逢。古今多少事,都付笑谈中。 ——调寄《临江仙》 @@ -23,7 +23,7 @@ 三人救了董卓回寨。卓问三人现居何职。玄德曰:“白身。”卓甚轻之,不为礼。玄德出,张飞大怒曰:“我等亲赴血战,救了这厮,他却如此无礼。若不杀之,难消我气!”便要提刀入帐来杀董卓。正是:人情势利古犹今,谁识英雄是白身?安得快人如翼德,尽诛世上负心人! 毕竟董卓性命如何,且听下文分解。 (本章完) -第2章 张翼德怒鞭督邮 何国舅谋诛宦竖 +第2章 张翼德怒鞭督邮 何国舅谋诛宦竖   且说董卓字仲颖,陇西临洮人也,官拜河东太守,自来骄傲。当日怠慢了玄德,张飞性发,便欲杀之。玄德与关公急止之曰;“他是朝廷命官,岂可擅杀?”飞曰:“若不杀这厮,反要在他部下听令,其实不甘!二兄要便住在此,我自投别处去也!”玄德曰:“我三人义同生死,岂可相离?不若都投别处去便了。”飞曰:“若如此,稍解吾恨。” 于是三人连夜引军来投朱儁。儁待之甚厚,合兵一处,进讨张宝。是时曹操自跟皇甫嵩讨张梁,大战于曲阳。这里朱儁进攻张宝。张宝引贼众八九万,屯于山后。儁令玄德为其先锋,与贼对敌。张宝遣副将高升出马搦战,玄德使张飞击之。飞纵马挺矛,与升交战,不数合,刺升落马。玄德麾军直冲过去。张宝就马上披发仗剑,作起妖法。只见风雷大作,一股黑气从天而降,黑气中似有无限人马杀来。玄德连忙回军,军中大乱。败阵而归,与朱儁计议。儁曰:“彼用妖术,我来日可宰猪羊狗血,令军士伏于山头;候贼赶来,从高坡上泼之,其法可解。”玄德听令,拨关公、张飞各引军一千,伏于山后高冈之上,盛猪羊狗血并秽物准备。次日,张宝摇旗擂鼓,引军搦战,玄德出迎。交锋之际,张宝作法,风雷大作,飞砂走石,黑气漫天,滚滚人马,自天而下。玄德拨马便走,张宝驱兵赶来。将过山头,关、张伏军放起号炮,秽物齐泼。但见空中纸人草马,纷纷坠地;风雷顿息,砂石不飞。 张宝见解了法,急欲退军。左关公,右张飞,两军都出,背后玄德、朱儁一齐赶上,贼兵大败。玄德望见“地公将军”旗号,飞马赶来,张宝落荒而走。玄德发箭,中其左臂。张宝带箭逃脱,走入阳城,坚守不出。 @@ -43,7 +43,7 @@ 袁绍迎问曰:“大事若何?”进曰:“太后不允,如之奈何?”绍曰:“可召四方英雄之士,勒兵来京,尽诛阉竖。此时事急,不容太后不从。”进曰:“此计大妙!”便发檄至各镇,召赴京师。主薄陈琳曰:“不可!俗云:掩目而捕燕雀,是自欺也,微物尚不可欺以得志,况国家大事乎?今将军仗皇威,掌兵要,龙骧虎步,高下在心:若欲诛宦官,如鼓洪炉燎毛发耳。但当速发雷霆,行权立断,则天人顺之。却反外檄大臣,临犯京阙,英雄聚会,各怀一心:所谓倒持干戈,授人以柄,功必不成,反生乱矣。”何进笑曰:“此懦夫之见也!”旁边一人鼓掌大笑曰:“此事易如反掌,何必多议!”视之,乃曹操也。正是:欲除君侧宵人乱,须听朝中智士谋。 不知曹操说出甚话来,且听下文分解。 (本章完) -第3章 议温明董卓叱丁原 馈金珠李肃说吕布 +第3章 议温明董卓叱丁原 馈金珠李肃说吕布   且说曹操当日对何进曰:“宦官之祸,古今皆有;但世主不当假之权宠,使至于此。若欲治罪,当除元恶,但付一狱吏足矣,何必纷纷召外兵乎?欲尽诛之,事必宣露。吾料其必败也。”何进怒曰:“孟德亦怀私意耶?”操退曰:“乱天下者,必进也。”进乃暗差使命,赍密诏星夜往各镇去。 却说前将军、鳌乡侯、西凉刺史董卓,先为破黄巾无功,朝议将治其罪,因贿赂十常侍幸免;后又结托朝贵,遂任显官,统西州大军二十万,常有不臣之心。是时得诏大喜,点起军马,陆续便行;使其婿中郎将牛辅;守住陕西,自己却带李傕、郭汜、张济、樊稠等提兵望洛阳进发。 卓婿谋士李儒曰:“今虽奉诏,中间多有暗味。何不差人上表,名正言顺,大事可图。”卓大喜,遂上表。其略曰:“窃闻天下所以乱逆不止者,皆由黄门常侍张让等侮慢天常之故。臣闻扬汤止沸,不如去薪;溃痈虽痛,胜于养毒。臣敢鸣钟鼓入洛阳,请除让等。社稷幸甚!天下幸甚!” @@ -62,7 +62,7 @@ 李儒劝卓早定废立之计。卓乃于省中设宴,会集公卿,令吕布将甲士千余,侍卫左右。是日,太傅袁隗与百官皆到。酒行数巡,卓按剑曰“今上暗弱,不可以奉宗庙;吾将依伊尹、霍光故事,废帝为弘农王,立陈留王为帝。有不从者斩!”群臣惶怖莫敢对。中军校尉袁绍挺身出曰:“今上即位未几,并无失德;汝欲废嫡立庶,非反而何?”卓怒曰:“天下事在我!我今为之,谁敢不从!汝视我之剑不利否?”袁绍亦拔剑曰:“汝剑利,吾剑未尝不利!”两个在筵上对敌。正是:丁原仗义身先丧,袁绍争锋势又危。 毕竟袁绍性命如何,且听下文分解。 (本章完) -第4章 废汉帝陈留践位 谋董贼孟德献刀 +第4章 废汉帝陈留践位 谋董贼孟德献刀   且说董卓欲杀袁绍,李儒止之曰:“事未可定,不可妄杀。”袁绍手提宝剑,辞别百官而出,悬节东门,奔冀州去了。卓谓太傅袁隗曰:“汝侄无礼,吾看汝面,姑恕之。废立之事若何?”隗曰:“太尉所见是也。”卓曰:“敢有阻大议者,以军法从事!”群臣震恐,皆云一听尊命。宴罢,卓问侍中周毖、校尉伍琼曰:“袁绍此去若何?”周毖曰:“袁绍忿忿而去,若购之急,势必为变。且袁氏树恩四世,门生故吏遍于天下;倘收豪杰以聚徒众,英雄因之而起,山东非公有也。不如赦之,拜为一郡守,则绍喜于免罪,必无患矣。”伍琼曰:“袁绍好谋无断,不足为虑;诚不若加之一郡守,以收民心。”卓从之,即日差人拜绍为渤海太守。 九月朔,请帝升嘉德殿,大会文武。卓拔剑在手,对众曰:“天子暗弱,不足以君天下。今有策文一道,宜为宣读。”乃命李儒读策曰:“孝灵皇帝,早弃臣民;皇帝承嗣,海内侧望。而帝天资轻佻,威仪不恪,居丧慢惰:否德既彰,有忝大位。皇太后教无母仪,统政荒乱。永乐太后暴崩,众论惑焉。三纲之道,天地之纪,毋乃有阙?陈留王协,圣德伟懋,规矩肃然;居丧哀戚,言不以邪;休声美誉,天下所闻,宜承洪业,为万世统。兹废皇帝为弘农王,皇太后还政,请奉陈留王为皇帝,应天顺人,以慰生灵之望。” 李儒读策毕,卓叱左右扶帝下殿,解其玺绶,北面长跪,称臣听命。又呼太后去服候敕。帝后皆号哭,群臣无不悲惨。 @@ -81,7 +81,7 @@ 当夜,行数里,月明中敲开客店门投宿。喂饱了马,曹操先睡。陈宫寻思:“我将谓曹操是好人,弃官跟他;原来是个狼心之徒!今日留之,必为后患。”便欲拔剑来杀曹操。正是:设心狠毒非良士,操卓原来一路人。 毕竟曹操性命如何,且听下文分解。 (本章完) -第5章 发矫诏诸镇应曹公 破关兵三英战吕布 +第5章 发矫诏诸镇应曹公 破关兵三英战吕布   却说陈宫临欲下手杀曹操,忽转念曰:“我为国家跟他到此,杀之不义。不若弃而他往。”插剑上马,不等天明,自投东郡去了。操觉,不见陈宫,寻思:“此人见我说了这两句,疑我不仁,弃我而去;吾当急行,不可久留。”遂连夜到陈留,寻见父亲,备说前事;欲散家资,招募义兵。父言:“资少恐不成事。此间有孝廉卫弘,疏财仗义,其家巨富;若得相助,事可图矣。”操置酒张筵,拜请卫弘到家,告曰:“今汉室无主,董卓专权,欺君害民,天下切齿。操欲力扶社稷,恨力不足。公乃忠义之士,敢求相助!”卫弘曰:“吾有是心久矣,恨未遇英雄耳。既孟德有大志,愿将家资相助。”操大喜;于是先发矫诏,驰报各道,然后招集义兵,竖起招兵白旗一面,上书“忠义”二字。不数日间,应募之士,如雨骈集。 一日,有一个阳平卫国人,姓乐,名进,字文谦,来投曹操。又有一个山阳巨鹿人,姓李,名典,字曼成,也来投曹操。操皆留为帐前吏。又有沛国谯人夏侯惇,字元让,乃夏侯婴之后;自小习枪棒;年十四从师学武,有人辱骂其师,惇杀之,逃于外方;闻知曹操起兵,与其族弟夏侯渊两个,各引壮士千人来会。此二人本操之弟兄:操父曹嵩原是夏侯氏之子,过房与曹家,因此是同族。不数日,曹氏兄弟曹仁、曹洪各引兵千余来助。曹仁字子孝,曹洪字子廉:二人弓马熟娴,武艺精通。操大喜,于村中调练军马。卫弘尽出家财,置办衣甲旗幡。四方送粮食者,不计其数。 时袁绍得操矫诏,乃聚麾下文武,引兵三万,离渤海来与曹操会盟。操作檄文以达诸郡。檄文曰:“操等谨以大义布告天下:董卓欺天罔地,灭国弑君;秽乱宫禁,残害生灵;狼戾不仁,罪恶充积!今奉天子密诏,大集义兵,誓欲扫清华夏,剿戮群凶。望兴义师,共泄公愤;扶持王室,拯救黎民。檄文到日,可速奉行!”操发檄文去后,各镇诸侯皆起兵相应:第一镇,后将军南阳太守袁术。第二镇,冀州刺史韩馥。第三镇,豫州刺史孔伷。第四镇,兖州刺史刘岱。第五镇,河内郡太守王匡。第六镇,陈留太守张邈。第七镇,东郡太守乔瑁。第八镇,山阳太守袁遗。第九镇,济北相鲍信。第十镇,北海太守孔融。第十一镇,广陵太守张超。第十二镇,徐州刺史陶谦。第十三镇,西凉太守马腾。第十四镇,北平太守公孙瓒。第十五镇,上党太守张杨。第十六镇,乌程侯长沙太守孙坚。第十七镇,祁乡侯渤海太守袁绍。诸路军马,多少不等,有三万者,有一二万者,各领文官武将,投洛阳来。 @@ -101,7 +101,7 @@ 奸臣董卓废少帝,刘协懦弱魂梦惊。曹操传檄告天下,诸侯奋怒皆兴兵。议立袁绍作盟主,誓扶王室定太平。温侯吕布世无比,雄才四海夸英伟。护躯银铠砌龙鳞,束发金冠簪雉尾。参差宝带兽平吞,错落锦袍飞凤起。龙驹跳踏起天风,画戟荧煌射秋水。出关搦战谁敢当?诸侯胆裂心惶惶。踊出燕人张冀德,手持蛇矛丈八枪。虎须倒竖翻金线,环眼圆睁起电光。酣战未能分胜败,阵前恼起关云长。青龙宝刀灿霜雪,鹦鹉战袍飞蛱蝶。马蹄到处鬼神嚎,目前一怒应流血。枭雄玄德掣双锋,抖擞天威施勇烈。三人围绕战多时,遮拦架隔无休歇。喊声震动天地翻,杀气迷漫牛斗寒。吕布力穷寻走路,遥望家山拍马还。倒拖画杆方天戟,乱散销金五彩幡。顿断绒绦走赤兔,翻身飞上虎牢关。”三人直赶吕布到关下,看见关上西风飘动青罗伞盖。张飞大叫:“此必董卓!追吕布有甚强处?不如先拿董贼,便是斩草除根!”拍马上关,来擒董卓。正是:擒贼定须擒贼首,奇功端的待奇人。 未知胜负如何,且听下文分解。 (本章完) -第6章 焚金阙董卓行凶 匿玉玺孙坚背约 +第6章 焚金阙董卓行凶 匿玉玺孙坚背约   却说张飞拍马赶到关下,关上矢石如雨,不得进而回。八路诸侯,同请玄德、关、张贺功,使人去袁绍寨中报捷。绍遂移檄孙坚,令其进兵。坚引程普、黄盖至袁术寨中相见。坚以杖画地曰:“董卓与我,本无仇隙。今我奋不顾身,亲冒矢石,来决死战者,上为国家讨贼,下为将军家门之私;而将军却听谗言,不发粮草,致坚败绩,将军何安?”术惶恐无言,命斩进谗之人,以谢孙坚。 忽人报坚曰:“关上有一将,乘马来寨中,要见将军。”坚辞袁术,归到本寨,唤来问时,乃董卓爱将李傕。坚曰:“汝来何为?”傕曰:“丞相所敬者,惟将军耳。今特使傕来结亲:丞相有女,欲配将军之子。”坚大怒,叱曰:“董卓逆天无道,荡覆王室,吾欲夷其九族,以谢天下,安肯与逆贼结亲耶!吾不斩汝,汝当速去,早早献关,饶你性命!倘若迟误,粉骨碎身!”李傕抱头鼠窜,回见董卓,说孙坚如此无礼。卓怒,问李儒。儒曰:“温侯新败,兵无战心。不若引兵回洛阳,迁帝于长安,以应童谣。近日街市童谣曰:西头一个汉,东头一个汉。鹿走入长安,方可无斯难。臣思此言‘西头一个汉’,乃应高祖旺于西都长安,传一十二帝;‘东头一个汉’,乃应光武旺于东都洛阳,今亦传一十二帝。天运合回。丞相迁回长安,方可无虞。”卓大喜曰:“非汝言,吾实不悟。”遂引吕布星夜回洛阳,商议迁都。聚文武于朝堂,卓曰:“汉东都洛阳,二百余年,气数已衰。吾观旺气实在长安,吾欲奉驾西幸。汝等各宜促装。”司徒杨彪曰:“关中残破零落。 今无故捐宗庙,弃皇陵,恐百姓惊动。天下动之至易,安之至难。望丞相监察。”卓怒曰:“汝阻国家大计耶?”太尉黄琬曰:“杨司徒之言是也。往者王莽篡逆,更始赤眉之时,焚烧长安,尽为瓦砾之地;更兼人民流移,百无一二。今弃宫室而就荒地,非所宜也。”卓曰:“关东贼起,天下播乱。长安有崤函之险;更近陇右,木石砖瓦,克日可办,宫室营造,不须月余。汝等再休乱言。”司徒荀爽谏曰:“丞相若欲迁都,百姓骚动不宁矣。”卓大怒曰:“吾为天下计,岂惜小民哉!”即日罢杨彪、黄琬、荀爽为庶民。卓出上车,只见二人望车而揖,视之,乃尚书周毖、城门校尉伍琼也。卓问有何事,毖曰:“今闻丞相欲迁都长安,故来谏耳。”卓大怒曰:“我始初听你两个,保用袁绍;今绍已反,是汝等一党!”叱武士推出都门斩首。遂下令迁都,限来日便行。李儒曰:“今钱粮缺少,洛阳富户极多,可籍没入官。但是袁绍等门下,杀其宗党而抄其家赀,必得巨万。”卓即差铁骑五千、遍行捉拿洛阳富户,共数千家,插旗头上大书“反臣逆党”,尽斩于城外,取其金赀。 @@ -116,7 +116,7 @@ 却说荆州刺史刘表,字景升,山阳高平人也,乃汉室宗亲;幼好结纳,与名士七人为友,时号“江夏八俊”。那七人:汝南陈翔,字仲麟;同郡范滂,字孟博;鲁国孔昱,字世元;渤海范康,字仲真,山阳檀敷,字文友;同郡张俭,字元节;南阳岑咥,字公孝。刘表与此七人为友;有延平人蒯良、蒯越,襄阳人蔡瑁为辅。当时看了袁绍书,随令蒯越、蔡瑁引兵一万来截孙坚。坚军方到,蒯越将阵摆开,当先出马。孙坚问曰:“蒯异度何故引兵截吾去路?”越曰:“汝既为汉臣,如何私匿传国之宝?可速留下,放汝归去!”坚大怒,命黄盖出战。蔡瑁舞刀来迎。斗到数合,盖挥鞭打瑁正中护心镜。瑁拨回马走,孙坚乘势杀过界口。山背后金鼓齐鸣、乃刘表亲自引军来到。孙坚就马上施礼曰:“景升何故信袁绍之书,相逼邻郡?”表曰:“汝匿传国玺,将欲反耶?”坚曰:“吾若有此物,死于刀箭之下!”表曰:“汝若要我听信,将随军行李,任我搜看。”坚怒曰:“汝有何力,敢小觑我!”方欲交兵,刘表便退。坚纵马赶去,两山后伏兵齐起,背后蔡瑁、蒯越赶来,将孙坚困在垓心。正是:玉玺得来无用处,反因此宝动刀兵。 毕竟孙坚怎地脱身,且听下文分解。 (本章完) -第7章 袁绍磐河战公孙 孙坚跨江击刘表 +第7章 袁绍磐河战公孙 孙坚跨江击刘表   却说孙坚被刘表围住,亏得程普、黄盖、韩当三将死救得脱,折兵大半,夺路引兵回江东。自此孙坚与刘表结怨。 且说袁绍屯兵河内,缺少粮草。冀州牧韩馥,遣人送粮以资军用。谋士逢纪说绍曰:“大丈夫纵横天下,何待人送粮为食!冀州乃钱粮广盛之地,将军何不取之?”绍曰:“未有良策。”纪曰:“可暗使人驰书与公孙瓒,令进兵取冀州,约以夹攻,瓒必兴兵。韩馥无谋之辈,必请将军领州事;就中取事,唾手可得。”绍大喜,即发书到瓒处。瓒得书,见说共攻冀州,平分其地,大喜,即日兴兵。 绍却使人密报韩馥。馥慌聚荀谌、辛评二谋士商议。谌曰:“公孙瓒将燕、代之众,长驱而来,其锋不可当。兼有刘备、关、张助之,难以抵敌。今袁本初智勇过人,手下名将极广,将军可请彼同治州事,彼必厚待将军,无患公孙瓒矣。”韩馥即差别驾关纯去请袁绍。长史耿武谏曰:“袁绍孤客穷军,仰我鼻息,譬如婴儿在股掌之上,绝其乳哺,立可饿死。奈何欲以州事委之?此引虎入羊群也。”馥曰:“吾乃袁氏之故吏,才能又不如本初。古者择贤者而让之,诸君何嫉妒耶?”耿武叹曰:“冀州休矣!”于是弃职而去者三十余人。独耿武与关纯伏于城外,以待袁绍。 @@ -138,7 +138,7 @@ 刘表军自入城。孙策回到汉水,方知父亲被乱箭射死,尸首已被刘表军士扛抬入城去了,放声大哭。众军俱号泣。策曰:“父尸在彼,安得回乡!”黄盖曰:“今活捉黄祖在此,得一人入城讲和,将黄祖去换主公尸首。”言未毕,军吏桓阶出曰:“某与刘表有旧,愿入城为使。”策许之。桓阶入城见刘表,具说其事。表曰:“文台尸首、吾已用棺木盛贮在此。可速放回黄祖,两家各罢兵,再休侵犯。”桓阶拜谢欲行,阶下蒯良出曰:“不可!不可!吾有一言,今江东诸军片甲不回。请先斩桓阶,然后用计。”正是:追敌孙坚方殒命,求和桓阶又遭殃。 未知桓阶性命如何,且听下文分解。 (本章完) -第8章 王司徒巧使连环计 董太师大闹凤仪亭 +第8章 王司徒巧使连环计 董太师大闹凤仪亭   却说蒯良曰:“今孙坚已丧,其子皆幼。乘此虚弱之时,火速进军,江东一鼓可得。若还尸罢兵,容其养成气力,荆州之患也。”表曰:“吾有黄祖在彼营中,安忍弃之?”良曰:“舍一无谋黄祖而取江东,有何不可?”表曰:“吾与黄祖心腹之交,舍之不义。”遂送桓阶回营,相约以孙坚尸换黄祖。 孙策换回黄祖,迎接灵柩,罢战回江东,葬父于曲阿之原。丧事已毕,引军居江都,招贤纳士,屈己待人,四方豪杰,渐渐投之。不在话下。 却说董卓在长安,闻孙坚已死,乃曰:“吾除却一心腹之患也!”问:“其子年几岁矣?”或答曰十七岁,卓遂不以为意。自此愈加骄横,自号为“尚父”,出入僭天子仪仗;封弟董晃为左将军、鄠侯,侄董璜为侍中,总领禁军。董氏宗族,不问长幼,皆封列侯。离长安城二百五十里,别筑郿坞,役民夫二十五万人筑之:其城郭高下厚薄一如长安,内盖宫室,仓库屯积二十年粮食;选民间少年美女八百人实其中,金玉、彩帛、珍珠堆积不知其数;家属都住在内。卓往来长安,或半月一回,或一月一回,公卿皆候送于横门外;卓常设帐于路,与公卿聚饮。一日,卓出横门,百官皆送,卓留宴,适北地招安降卒数百人到。卓即命于座前,或断其手足,或凿其眼睛,或割其舌,或以大锅煮之。哀号之声震天,百官战慄失箸,卓饮食谈笑自若。又一日,卓于省台大会百官,列坐两行。酒至数巡,吕布径入,向卓耳边言不数句,卓笑曰:“原来如此。”命吕布于筵上揪司空张温下堂。百官失色。不多时,侍从将一红盘,托张温头入献。百官魂不附体。卓笑曰:“诸公勿惊。张温结连袁术,欲图害我,因使人寄书来,错下在吾儿奉先处。故斩之。公等无故,不必惊畏。”众官唯唯而散。 @@ -151,7 +151,7 @@ 却说董卓在殿上,回头不见吕布,心中怀疑,连忙辞了献帝,登车回府;见布马系于府前;问门吏,吏答曰:“温侯入后堂去了。”卓叱退左右,径入后堂中,寻觅不见;唤貂蝉,蝉亦不见。急问侍妾,侍妾曰:“貂蝉在后园看花。”卓寻入后园,正见吕布和貂蝉在凤仪亭下共语,画戟倚在一边。卓怒,大喝一声。布见卓至,大惊,回身便走。卓抢了画戟,挺着赶来。吕布走得快,卓肥胖赶不上,掷戟刺布。布打戟落地。卓拾戟再赶,布已走远。卓赶出园门,一人飞奔前来,与卓胸膛相撞,卓倒于地。正是:冲天怒气高千丈,仆地肥躯做一堆。 未知此人是谁,且听下文分解。 (本章完) -第9章 除暴凶吕布助司徒 犯长安李傕听贾诩 +第9章 除暴凶吕布助司徒 犯长安李傕听贾诩   却说那撞倒董卓的人,正是李儒。当下李儒扶起董卓,至书院中坐定,卓曰:“汝为何来此?”儒曰:“儒适至府门,知太师怒入后园,寻问吕布。因急走来,正遇吕布奔走,云:‘太师杀我!’儒慌赶入园中劝解,不意误撞恩相。死罪!死罪!”卓曰:“叵耐逆贼!戏吾爱姬,誓必杀之!”儒曰:“恩相差矣。昔楚庄王绝缨之会,不究戏爱姬之蒋雄,后为秦兵所困,得其死力相救。今貂蝉不过一女子,而吕布乃太师心腹猛将也。太师若就此机会,以蝉赐布,布感大恩,必以死报太师。太师请自三思。”卓沈吟良久曰:“汝言亦是,我当思之。”儒谢而出。 卓入后堂,唤貂蝉问曰:“汝何与吕布私通耶?”蝉泣曰:“妾在后园看花,吕布突至。妾方惊避,布曰:‘我乃太师之子,何必相避?’提戟赶妾至凤仪亭。妾见其心不良,恐为所逼,欲投荷池自尽,却被这厮抱住。正在生死之间,得太师来,救了性命。”董卓曰:“我今将汝赐与吕布,何如?”貂蝉大惊,哭曰:“妾身已事贵人,今忽欲下赐家奴,妾宁死不辱!”遂掣壁间宝剑欲自刎。卓慌夺剑拥抱曰:“吾戏汝!”貂蝉倒于卓怀,掩面大哭曰:“此必李儒之计也!儒与布交厚,故设此计;却不顾惜太师体面与贱妾性命。妾当生噬其肉!”卓曰:“吾安忍舍汝耶?”蝉曰:“虽蒙太师怜爱,但恐此处不宜久居,必被吕布所害。”卓曰:“吾明日和你归郿坞去,同受快乐,慎勿忧疑。”蝉方收泪拜谢。 次日,李儒入见曰:“今日良辰,可将貂蝉送与吕布。”卓曰:“布与我有父子之分,不便赐与。我只不究其罪。汝传我意,以好言慰之可也。”儒曰:“太师不可为妇人所惑。”卓变色曰:“汝之妻肯与吕布否?貂蝉之事,再勿多言;言则必斩!”李儒出,仰天叹曰:“吾等皆死于妇人之手矣!”后人读书至此。有诗叹之曰:“司徒妙算托红裙。不用干戈不用兵。三战虎牢徒费力,凯歌却奏凤仪亭。” @@ -171,7 +171,7 @@ 李傕、郭汜纵兵大掠。太常卿种拂、太仆鲁馗、大鸿胪周奂、城门校尉崔烈、越骑校尉王颀皆死于国难。贼兵围绕内庭至急,侍臣请天子上宣平门止乱。李傕等望见黄盖,约住军士,口呼“万岁”。献帝倚楼问曰:“卿不候奏请,辄入长安,意欲何为?”李傕、郭汜仰面奏曰:“董太师乃陛下社稷之臣,无端被王允谋杀,臣等特来报仇,非敢造反。但见王允,臣便退兵。”王允时在帝侧,闻知此言,奏曰:“臣本为社稷计。事已至此,陛下不可惜臣,以误国家。臣请下见二贼。”帝徘徊不忍。允自宣平门楼上跳下楼去,大呼曰:“王允在此!”李傕、郭汜拔剑叱曰:“董太师何罪而见杀?”允曰:“董贼之罪,弥天亘地,不可胜言!受诛之日。长安士民,皆相庆贺,汝独不闻乎?”傕、汜曰:“太师有罪;我等何罪,不肯相赦?”王允大骂:“逆贼何必多言!我王允今日有死而已!”二贼手起,把王允杀于楼下。史官有诗赞曰:“王允运机筹,奸臣董卓休。心怀家国恨,眉锁庙堂忧。英气连霄汉,忠诚贯斗牛。至今魂与魄,犹绕凤凰楼。” 众贼杀了王允,一面又差人将王允宗族老幼,尽行杀害。士民无不下泪。当下李傕、郭汜寻思曰:“既到这里,不杀天子谋大事,更待何时?”便持剑大呼,杀入内来。正是:巨魁伏罪灾方息,从贼纵横祸又来。未知献帝性命如何,且听下文分解。 (本章完) -第10章 勤王室马腾举义 报父仇曹操兴师 +第10章 勤王室马腾举义 报父仇曹操兴师   却说李、郭二贼欲弑献帝。张济、樊稠谏曰:“不可。今日若便杀之,恐众人不服,不如仍旧奉之为主,赚诸侯入关,先去其羽翼,然后杀之,天下可图也。”李、郭二人从其言,按住兵器。帝在楼上宣谕曰:“王允既诛,军马何故不退?”李傕、郭汜曰:“臣等有功王室,未蒙赐爵,故不敢退军。”帝曰:“卿欲封何爵?”李、郭、张、樊四人各自写职衔献上,勒要如此官品,帝只得从之。封李傕为车骑将军池阳侯领司隶校尉假节钺,郭汜为后将军美阳侯假节钺,同秉朝政;樊稠为右将军万年侯,张济为骠骑将军平阳侯,领兵屯弘农。其余李蒙、王方等,各为校尉。然后谢恩,领兵出城。又下令追寻董卓尸首,获得些零碎皮骨,以香木雕成形体,安凑停当,大设祭祀,用王者衣冠棺椁,选择吉日,迁葬郿坞。临葬之期,天降大雷雨,平地水深数尺,霹雳震开其棺,尸首提出棺外。李傕候晴再葬,是夜又复如是。三次改葬,皆不能葬,零皮碎骨,悉为雷火消灭。天之怒卓。可谓甚矣! 且说李傕、郭汜既掌大权,残虐百姓;密遣心腹侍帝左右,观其动静。献帝此时举动荆棘。朝廷官员,并由二贼升降。因采人望,特宣朱儁入朝封为太仆,同领朝政。一日,人报西凉太守马腾;并州刺史韩遂二将引军十余万,杀奔长安来,声言讨贼。原来二将先曾使人入长安,结连侍中马宇、谏议大夫种邵、左中郎将刘范三人为内应,共谋贼党。三人密奏献帝,封马腾为征西将军、韩遂为镇西将军,各受密诏,并力讨贼。当下李傕、郭汜、张济、樊稠闻二军将至,一同商议御敌之策。谋士贾诩曰:“二军远来,只宜深沟高垒,坚守以拒之。不过百日,彼兵粮尽,必将自退,然后引兵追之,二将可擒矣。”李蒙、王方出曰:“此非好计。愿借精兵万人,立斩马腾、韩遂之头,献于麾下。”贾诩曰:“今若即战,必当败绩。”李蒙、王方齐声曰:“若吾二人败,情愿斩首;吾若战胜,公亦当输首级与我。”诩谓李傕、郭汜曰:“长安西二百里盩厔山,其路险峻,可使张、樊两将军屯兵于此,坚壁守之;待李蒙、王方自引兵迎敌,可也。”李傕、郭汜从其言,点一万五千人马与李蒙、王方。二人忻喜而去,离长安二百八十里下寨。 西凉兵到,两个引军迎去。西凉军马拦路摆开阵势。马腾、韩遂联辔而出,指李蒙、王方骂曰:“反国之贼!谁去擒之?”言未绝,只见一位少年将军,面如冠玉,眼若流星,虎体猿臂,彪腹狼腰;手执长枪,坐骑骏马,从阵中飞出。原来那将即马腾之子马超,字孟起,年方十七岁,英勇无敌。王方欺他年幼,跃马迎战。战不到数合,早被马超一枪刺于马下。马超勒马便回。李蒙见王方刺死,一骑马从马超背后赶来。超只做不知。马腾在阵门下大叫:“背后有人追赶!”声犹未绝,只见马超已将李蒙擒在马上。原来马超明知李蒙追赶,却故意俄延;等他马近举枪刺来,超将身一闪,李蒙搠个空,两马相并,被马超轻舒猿臂,生擒过去。军士无主,望风奔逃。 @@ -185,7 +185,7 @@ 陶谦入城,与众计议曰:“曹兵势大难敌,吾当自缚往操营,任其剖割,以救徐州一郡百姓之命。”言未绝,一人进前言曰:“府君久镇徐州,人民感恩。今曹兵虽众,未能即破我城。府君与百姓坚守勿出;某虽不才,愿施小策,教曹操死无葬身之地!”众人大惊,便问计将安出。正是:本为纳交反成怨,那知绝处又逢生。 毕竟此人是谁,且听下文分解。 (本章完) -第11章 刘皇叔北海救孔融 吕温侯濮阳破曹操 +第11章 刘皇叔北海救孔融 吕温侯濮阳破曹操   却说献计之人,乃东海朐县人,姓糜,名竺,字子仲。此人家世富豪,尝往洛阳买卖,乘车而回,路遇一美妇人,来求同载,竺乃下车步行,让车与妇人坐。妇人请竺同载。竺上车端坐,目不邪视。行及数里,妇人辞去;临别对竺曰:“我乃南方火德星君也,奉上帝教,往烧汝家。感君相待以礼,故明告君。君可速归,搬出财物。吾当夜来。”言讫不见。竺大惊,飞奔到家,将家中所有,疾忙搬出。是晚果然厨中火起,尽烧其屋。竺因此广舍家财,济贫拔苦。后陶谦聘为别驾从事。当日献计曰:“某愿亲往北海郡,求孔融起兵救援;更得一人往青州田楷处求救:若二处军马齐来,操必退兵矣。”谦从之,遂写书二封,问帐下谁人敢去青州求救。一人应声愿往。众视之,乃广陵人,姓陈,名登,字元龙。陶谦先打发陈元龙往青州去讫,然后命糜竺赍书赴北海,自己率众守城,以备攻击。 却说北海孔融,字文举,鲁国曲阜人也,孔子二十世孙,泰山都尉孔宙之子。自小聪明,年十岁时,往谒河南尹李膺,阍人难之,融曰:“我系李相通家。”及入见,膺问曰:“汝祖与吾祖何亲?”融曰:“昔孔子曾问礼于老子,融与君岂非累世通家?”膺大奇之。少顷,太中大夫陈炜至。膺指融曰:“此奇童也。”炜曰:“小时聪明,大时未必聪明。”融即应声曰:“如君所言,幼时必聪明者。”炜等皆笑曰:“此子长成,必当代之伟器也。”自此得名。后为中郎将,累迁北海太守。极好宾客,常曰:“座上客常满,樽中酒不空:吾之愿也。”在北海六年,甚得民心。当日正与客坐,人报徐州糜竺至。融请入见,问其来意,竺出陶谦书,言:“曹操攻围甚急,望明公垂救。”融曰:“吾与陶恭祖交厚,子仲又亲到此,如何不去?只是曹孟德与我无仇,当先遣人送书解和。如其不从,然后起兵。”竺曰:“曹操倚仗兵威,决不肯和。”融教一面点兵,一面差人送书。正商议间,忽报黄巾贼党管亥部领群寇数万杀奔前来。 孔融大惊,急点本部人马,出城与贼迎战。管亥出马曰:“吾知北海粮广,可借一万石,即便退兵;不然,打破城池,老幼不留!”孔融叱曰:“吾乃大汉之臣,守大汉之地,岂有粮米与贼耶!”管亥大怒,拍马舞刀,直取孔融,融将宗宝挺枪出马;战不数合,被管亥一刀,砍宗宝于马下。孔融兵大乱,奔入城中。管亥分兵四面围城,孔融心中郁闷。糜竺怀愁,更不可言。次日,孔融登城遥望,贼势浩大,倍添忧恼。忽见城外一人挺枪跃马杀入贼阵,左冲右突,如入无人之境,直到城下,大叫“开门”。孔融不识其人,不敢开门。贼众赶到壕边,那人回身连搠十数人下马,贼众倒退,融急命开门引入。其人下马弃枪,径到城上,拜见孔融。融问其姓名,对曰:“某东莱黄县人也,覆姓太史,名慈,字子义。老母重蒙恩顾。某昨自辽东回家省亲,知贼寇城。老母说:‘屡受府君深恩,汝当往救。’某故单马而来。”孔融大喜。原来孔融与太史慈虽未识面,却晓得他是个英雄。因他远出,有老母住在离城二十里之外,融常使人遗以粟帛;母感融德,故特使慈来救。 @@ -208,7 +208,7 @@ 操不能前进,无计可脱,大叫:“谁人救我!”马军队里,一将踊出,乃典韦也,手挺双铁戟,大叫:“主公勿忧!”飞身下马,插住双戟,取短戟十数枝,挟在手中,顾从人曰:“贼来十步乃呼我!”遂放开脚步,冒箭前行。布军数十骑追至。从人大叫曰:“十步矣!”韦曰:“五步乃呼我!”从人又曰:“五步矣!”韦乃飞戟刺之,一戟一人坠马,并无虚发,立杀十数人。众皆奔走。韦复飞身上马,挺一双大铁戟,冲杀入去。郝、曹、成、宋四将不能抵挡,各自逃去。典韦杀散敌军,救出曹操。众将随后也到,寻路归寨。看看天色傍晚,背后喊声起处,吕布骤马提戟赶来,大叫:“操贼休走!”此时人困马乏,大家面面相觑,各欲逃生。正是:虽能暂把重围脱,只怕难当劲敌追。 不知曹操性命如何,且听下文分解。 (本章完) -第12章 陶恭祖三让徐州 曹孟穗大战吕布 +第12章 陶恭祖三让徐州 曹孟穗大战吕布   曹操正慌走间,正南上一彪军到,乃夏侯惇引军来救援,截住吕布大战。斗到黄昏时分,大雨如注,各自引军分散。操回寨,重赏典韦,加为领军都尉。 却说吕布到寨,与陈宫商议。宫曰:“濮阳城中有富户田氏,家僮千百,为一郡之巨室;可令彼密使人往操寨中下书,言‘吕温侯残暴不仁,民心大怨。今欲移兵黎阳,止有高顺在城内。可连夜进兵,我为内应’。操若来,诱之入城,四门放火,外设伏兵。曹操虽有经天纬地之才,到此安能得脱也?”吕布从其计,密谕田氏使人径到操寨。操因新败,正在踌躇,忽报田氏人到,呈上密书云:“吕布已往黎阳,城中空虚。万望速来,当为内应。城上插白旗,大书‘义’字,便是暗号。”操大喜曰:“天使吾得濮阳也!”重赏来人,一面收拾起兵。刘晔曰:“布虽无谋,陈宫多计。只恐其中有诈,不可不防。明公欲去,当分三军为三队:两队伏城外接应,一队入城,方可。”操从其言,分军三队,来至濮阳城下。 操先往观之,见城上遍竖旗幡,西门角上,有一“义”字白旗,心中暗喜。是日午牌,城门开处,两员将引军出战:前军侯成,后军高顺。操即使典韦出马,直取侯成。侯成抵敌不过,回马望城中走。韦赶到吊桥边,高顺亦拦挡不住,都退入城中去了。数内有军人乘势混过阵来见操,说是田氏之使,呈上密书。约云:“今夜初更时分,城上鸣锣为号,便可进兵。某当献门。”操拨夏侯惇引军在左,曹洪引军在右,自己引夏侯渊、李典、乐进、典韦四将,率兵入城。李典曰:“主公且在城外,容某等先入城去。”操喝曰:“我不自往,谁肯向前!”遂当先领兵直入。 @@ -225,7 +225,7 @@ 宫曰:“操多诡计,不可轻敌。”布曰:“吾用火攻,可破伏兵。”乃留陈宫、高顺守城。布次日引大军来,遥见林中有旗,驱兵大进,四面放火,竟无一人。欲投寨中,却闻鼓声大震。正自疑惑不定,忽然寨后一彪军出。吕布纵马赶来。炮响处,堤内伏兵尽出:夏侯惇、夏侯渊、许褚、典韦、李典、乐进骤马杀来。吕布料敌不过,落荒而走。从将成廉,被乐进一箭射死。布军三停去了二停,败卒回报陈宫,宫曰:“空城难守,不若急去。”遂与高顺保着吕布老小,弃定陶而走。曹操将得胜之兵,杀入城中,势如劈竹。张超自刎,张邈投袁术去了。山东一境,尽被曹操所得。安民修城,不在话下。 却说吕布正走,逢诸将皆回。陈宫亦已寻着。布曰:“吾军虽少,尚可破曹。”遂再引军来。正是:兵家胜败真常事,卷甲重来未可知。不知吕布胜负如何,且听下文分解。 (本章完) -第13章 李傕郭汜大交兵 杨奉董承双救驾 +第13章 李傕郭汜大交兵 杨奉董承双救驾   却说曹操大破吕布于定陶,布乃收集败残军马于海滨,众将皆来会集,欲再与曹操决战,陈宫曰:“今曹兵势大,未可与争。先寻取安身之地,那时再来未迟。”布曰:“吾欲再投袁绍,何如?”宫曰:“先使人往冀州探听消息,然后可去。”布从之。且说袁绍在冀州,闻知曹操与吕布相持,谋士审配进曰:“吕布,豺虎也:若得兖州,必图冀州。不若助操攻之,方可无患。”绍遂遣颜良将兵五万,往助曹操。细作探知这个消息,飞报吕布。布大惊,与陈宫商议。宫曰:“闻刘玄德新领徐州,可往投之。”布从其言,竟投徐州来。有人报知玄德。玄德曰:“布乃当今英勇之士,可出迎之。”糜竺曰:“吕布乃虎狼之徒,不可收留;收则伤人矣。”玄德曰:“前者非布袭兖州,怎解此郡之祸。今彼穷而投我,岂有他心!”张飞曰:“哥哥心肠忒好。虽然如此,也要准备。” 玄德领众出城三十里,接着吕布,并马入城。都到州衙厅上,讲礼毕,坐下。布曰:“某自与王司徒计杀董卓之后,又遭傕、汜之变,飘零关东,诸侯多不能相容。近因曹贼不仁,侵犯徐州,蒙使君力救陶谦,布因袭兖州以分其势;不料反堕奸计,败兵折将。今投使君,共图大事,未审尊意如何?”玄德曰:“陶使君新逝,无人管领徐州,因令备权摄州事。今幸将军至此,合当相让”遂将牌印送与吕布。吕布却待要接,只见玄德背后关、张二公各有怒色。布乃佯笑曰:“量吕布一勇夫,何能作州牧乎?”玄德又让。陈宫曰:“强宾不压主,请便君勿疑。”玄德方止。遂设宴相待,收拾宅院安下。次日,吕布回席请玄德,玄德乃与关、张同往。饮酒至半酣,布请玄德入后堂,关、张随入。布令妻女出拜玄德。玄德再三谦让。布曰:“贤弟不必推让。”张飞听了,瞋目大叱曰:“我哥哥是金枝玉叶,你是何等人,敢称我哥哥为贤弟!你来!我和你斗三百合!”玄德连忙喝住,关公劝飞出。玄德与吕布陪话曰:“劣弟酒后狂言,兄勿见责。”布默然无语。须臾席散。布送玄德出门,张飞跃马横枪而来,大叫:“吕布!我和你并三百合!”玄德急令关公劝止。 次日,吕布来辞玄德曰:“蒙使君不弃,但恐令弟辈不能相容。布当别投他处。”玄德曰:“将军若去,某罪大矣。劣弟冒犯,另日当今陪话。近邑小沛,乃备昔日屯兵之处。将军不嫌浅狭,权且歇马,如何?粮食军需,谨当应付。”吕布谢了玄德,自引军投小沛安身去了。玄德自去埋怨张飞不题。 @@ -246,7 +246,7 @@ 李乐等专权,百官稍有触犯,竟于帝前殴骂;故意送浊酒粗食与帝,帝勉强纳之。李乐、韩暹又连名保奏无徒、部曲、巫医、走卒二百余名,并为校尉、御史等官。刻印不及,以锥画之,全不成体统。却说韩融曲说傕、汜二贼。二贼从其言,乃放百官及宫人归。是岁大荒,百姓皆食枣菜,饿莩遍野。河内太守张杨献米肉,河东太守王邑献绢帛,帝稍得宁。董承、杨奉商议,一面差人修洛阳宫院,欲奉车驾还东都。李乐不从。董承谓李乐曰:“洛阳本天子建都之地,安邑乃小地面,如何容得车驾?今奉驾还洛阳是正理。”李乐曰:“汝等奉驾去,我只在此处住。”承、奉乃奉驾起程。李乐暗令人结连李傕、郭汜,一同劫驾。董承、杨奉、韩暹知其谋,连夜摆布军士,护送车驾前奔箕关。李乐闻知,不等傕、汜军到,自引本部人马前来追赶。四更左侧,赶到箕山下,大叫:“车驾休行!李傕、郭汜在此!”吓得献帝心惊胆战。山上火光遍起。正是:前番两贼分为二,今番三贼合为一。 不知汉天子怎离此难,且听下文分解。 (本章完) -第14章 曹孟德移驾幸许都 吕奉先乘夜袭徐郡 +第14章 曹孟德移驾幸许都 吕奉先乘夜袭徐郡   却说李乐引军诈称李傕、郭汜,来遍车驾,天子大惊。杨奉曰:“此李乐也。”遂令徐晃出迎之。李乐亲自出战。两马相交,只一合,被徐晃一斧砍于马下,杀散余党,保护车驾过箕关。太守张杨具粟帛迎驾于轵道。帝封张杨为大司马。杨辞帝屯兵野王去了。帝入洛阳,见宫室烧尽,街市荒芜,满目皆是蒿草,宫院中只有颓墙坏壁。命杨奉且盖小宫居住。百官朝贺,皆立于荆棘之中。诏改兴平为建安元年。是岁又大荒。洛阳居民,仅有数百家,无可为食,尽出城去剥树皮、掘草根食之。尚书郎以下,皆自出城樵采,多有死于颓墙坏壁之间者。汉末气运之衰,无甚于此。后人有诗叹之曰:“血流芒砀白蛇亡,赤帜纵横游四方。秦鹿逐翻兴社稷,楚雅推倒立封疆。天子懦弱奸邪起,气色凋零盗贼狂。看到两京遭难处,铁人无泪也怬惶!”太尉杨彪奏帝曰:“前蒙降诏,未曾发遣。今曹操在山东,兵强将盛,可宣入朝,以辅王室。”帝曰:“朕前既降诏。卿何必再奏,今即差人前去便了。”彪领旨,即差使命赴山东,宣召曹操。却说曹操在山东,闻知车驾已还洛阳,聚谋士商议,荀彧进曰:“昔晋文公纳周襄王,而诸侯服从;汉高祖为义帝发丧,而天下归心。今天子蒙尘,将军诚因此时首倡义兵,奉天子以从众望,不世之略也。若不早图,人将先我而为之矣。”曹操大喜。正要收拾起兵,忽报有天使赍诏宣召。操接诏,克日兴师。却说帝在洛阳,百事未备,城郭崩倒,欲修未能。人报李傕、郭汜领兵将到。帝大惊,问杨奉曰:“山东之使未回,李、郭之兵又至,为之奈何?”杨奉、韩暹曰:“臣愿与贼决死战,以保陛下!”董承曰:“城郭不坚,兵甲不多,战如不胜,当复如何?不若且奉驾往山东避之。”帝从其言,即日起驾望山东进发。百官无马,皆随驾步行。出了洛阳,行无一箭之地,但见尘头蔽日,金鼓喧天,无限人马来到。帝、后战慓不能言。忽见一骑飞来,乃前差往山东之使命也,至车前拜启曰:“曹将军尽起山东之兵,应诏前来。闻李傕、郭汜犯洛阳,先差夏侯惇为先锋,引上将十员,精兵五万,前来保驾。”帝心方安。 少顷,夏侯惇引许褚、典韦等,至驾前面君,俱以军礼见。帝慰谕方毕,忽报正东又有一路军到。帝即命夏侯惇往探之,回妻曰:“乃曹操步军也。”须臾,曹洪、李典、乐进来见驾。通名毕,洪奏曰:“臣兄知贼兵至近,恐夏侯惇孤力难为,故又差臣等倍道而来协助。”帝曰:“曹将军真社稷臣也!”遂命护驾前行。探马来报:“李傕、郭汜领兵长驱而来。”帝令夏侯惇分两路迎之。惇乃与曹洪分为两翼,马军先出,步军后随,尽力攻击。傕、汜贼兵大败,斩首万余。于是请帝还洛阳故宫。夏侯惇屯兵于城外。 次日,曹操引大队人马到来。安营毕,入城见帝、拜于殿阶之下。帝赐平身,宣谕慰劳。操曰:“臣向蒙国恩,刻思图报。今傕、汜二贼,罪恶贯盈;臣有精兵二十余万,以顺讨逆,无不克捷。陛下善保龙体,以社稷为重。”帝乃封操领司隶校尉假节钺录尚书事。 @@ -268,7 +268,7 @@ 却说张飞引数十骑,直到盱眙来见玄德,具说曹豹与吕布里应外合,夜袭徐州。众皆失色。玄德叹曰:“得何足喜,失何足忧!”关公曰:“嫂嫂安在?”飞曰:“皆陷于城中矣。”玄德默然无语。关公顿足埋怨曰:“你当初要守城时说甚来?兄长分付你甚来?今日城池又失了,嫂嫂又陷了,如何是好!”张飞闻言,惶恐无地,掣剑欲自刎。正是:举杯畅饮情何放,拔剑捐生悔已迟! 不知性命如何,且听下文分解。 (本章完) -第15章 太史慈酣斗小霸王 孙伯符大战严白虎 +第15章 太史慈酣斗小霸王 孙伯符大战严白虎   却说张飞拔剑要自刎,玄德向前抱住,夺剑掷地曰:“古人云:‘兄弟如手足,妻子如衣服。衣服破,尚可缝;手足断,安可续?’吾三人桃园结义,不求同生,但愿同死。今虽失了城池家小,安忍教兄弟中道而亡?况城池本非吾有;家眷虽被陷,吕布必不谋害,尚可设计救之。贤弟一时之误,何至遽欲捐生耶!”说罢大哭。关、张俱感泣。 且说袁术知吕布袭了徐州,星夜差人至吕布处,许以粮五万斛、马五百匹、金银一万两、彩缎一千匹,使夹攻刘备。布喜,令高顺领兵五万袭玄德之后。玄德闻得此信,乘阴雨撤兵,弃盱眙而走,思欲东取广陵。比及高顺军来,玄德已去。高顺与纪灵相见,就索所许之物。灵曰:“公且回军,容某见主公计之。”高顺乃别纪灵回军,见吕布具述纪灵语。布正在迟疑,忽有袁术书至。书意云:“高顺虽来,而刘备未除;且待捉了刘备,那时方以所许之物相送。”布怒骂袁术失信,欲起兵伐之。陈宫曰:“不可。术据寿春,兵多粮广,不可轻敌。不如请玄德还屯小沛,使为我羽翼。他日令玄德为先锋,那时先取袁术,后取袁绍,可纵横天下矣。”布听其言,令人赍书迎玄德回。 却说玄德引兵东取广陵,被袁术劫寨,折兵大半。回来正遇吕布之使,呈上书札,玄德大喜。关、张曰:“吕布乃无义之人,不可信也。”玄德曰:“彼既以好情待我,奈何疑之!”遂来到徐州。布恐玄德疑惑,先令人送还家眷。甘、麋二夫人见玄德,具说吕布令兵把定宅门。禁诸人不得入;又常使侍妾送物,未尝有缺。玄德谓关、张曰:“我知吕布必不害我家眷也。”乃入城谢吕布。张飞恨吕布,不肯随往,先奉二嫂往小沛去了。玄德入见吕布拜谢。吕布曰:“我非欲夺城;因令弟张飞在此恃酒杀人,恐有失事,故来守之耳。”玄德曰:“备欲让兄久矣。”布假意仍让玄德。玄德力辞,还屯小沛住扎。关、张心中不忿。玄德曰:“屈身守分,以待天时,不可与命争也。”吕布令人送粮米缎匹。自此两家和好,不在话下。 @@ -294,7 +294,7 @@ 不一日引至。策见其人,童颜鹤发,飘然有出世之姿。乃待为上宾,请视周泰疮。佗曰:“此易事耳。”投之以药,一月而愈。策大喜,厚谢华佗。遂进兵杀除山贼。江南皆平。孙策分拨将士,守把各处隘口,一面写表申奏朝廷;一面结交曹操,一面使人致书与袁术取玉玺。却说袁术暗有称帝之心,乃回书推托不还;急聚长史杨大将,都督张勋、纪灵、桥蕤,上将雷薄、陈芬等三十余人商议,曰:“孙策借我军马起事,今日尽得江东地面;乃不思根本,而反来索玺,殊为无礼。当以何策图之?”长史杨大将曰:“孙策据长江之险,兵精粮广,未可图也。今当先伐刘备,以报前日无故相攻之恨,然后图取孙策未迟。某献一计,使备即日就擒。”正是:不去江东图虎豹,却来徐郡斗蛟龙。 不知其计若何,且听下文分解。 (本章完) -第16章 吕奉先射戟辕门 曹孟德败师淯水 +第16章 吕奉先射戟辕门 曹孟德败师淯水   却说杨大将献计欲攻刘备。袁术曰:“计将安出?”大将曰:“刘备屯军小沛,虽然易取,奈吕布虎踞徐州,前次许他金帛粮马,至今未与,恐其助备;今当令人送与粮食,以结其心,使其按兵不动,则刘备可擒。先擒刘备,后图吕布,徐州可得也。”术喜,便具粟二十万斛,令韩胤赍密书往见吕布。吕布甚喜,重待韩胤。胤回告袁术,术遂遣纪灵为大将,雷薄、陈兰为副将,统兵数万,进攻小沛。玄德闻知此信,聚众商议。张飞要出战。孙韩曰:“今小沛粮寡兵微,如何抵敌?可修书告急于吕布。”张飞曰:“那厮如何肯来!”玄德曰:“乾之言善。”遂修书与吕布。书略曰:“伏自将军垂念,令备于小沛容身,实拜云天之德。今袁术欲报私仇,遣纪灵领兵到县,亡在旦夕,非将军莫能救。望驱一旅之师,以救倒悬之急,不胜幸甚!”吕布看了书,与陈宫计议曰:“前者袁术送粮致书,盖欲使我不救玄德也。今玄德又来求救。吾想玄德屯军小沛,未必遂能为我害;若袁术并了玄德,则北连泰山诸将以图我,我不能安枕矣:不若救玄德。”遂点兵起程。 却说纪灵起兵长驱大进,已到沛县东南,扎下营寨。昼列旌旗,遮映山川;夜设火鼓,震明天地。玄德县中,止有五千余人,也只得勉强出县,布阵安营。忽报吕布引兵离县一里、西南上扎下营寨。纪灵知吕布领兵来救刘备,急令人致书于吕布,责其无信。布笑曰:“我有一计,使袁、刘两家都不怨我。”乃发使往纪灵、刘备寨中,请二人饮宴。玄德闻布相请,即便欲往。关、张曰:“兄长不可去。吕布必有异心。”玄德曰:“我待彼不薄,彼必不害我。”遂上马而行。关、张随往,到吕布寨中,入见。布曰:“吾今特解公之危。异日得志,不可相忘!”玄德称谢。布请玄德坐。关、张按剑立于背后。人报纪灵到,玄德大惊,欲避之。布曰:“吾特请你二人来会议,勿得生疑。”玄德未知其意,心下不安。 纪灵下马入寨,却见玄德在帐上坐,大惊,抽身便回。左右留之不住。吕布向前一把扯回,如提童稚。灵曰:“将军欲杀纪灵耶?”布曰:“非也。”灵曰:“莫非杀大耳儿乎?”布曰:“亦非也。”灵曰:“然则为何?”布曰:“玄德与布乃兄弟也,今为将军所困,故来救之。”灵曰:“若此则杀灵也?”布曰:“无有此理。布平生不好斗,惟好解斗。吾今为两家解之。”灵曰:“请问解之之法?”布曰:“我有一法,从天所决。”乃拉灵入帐与玄德相见。二人各怀疑忌。布乃居中坐,使灵居左,备居右,且教设宴行酒。酒行数巡,布曰:“你两家看我面上,俱各罢兵。”玄德无语。灵曰:“吾奉主公之命,提十万之兵,专捉刘备,如何罢得?”张飞大怒,拔剑在手。叱曰:“吾虽兵少,觑汝辈如儿戏耳!你比百万黄巾何如?你敢伤我哥哥!”关公急止之曰:“且看吕将军如何主意,那时各回营寨厮杀未迟。 @@ -313,7 +313,7 @@ 操知布绝婚袁术,大喜,遂斩韩胤于市曹。陈登密谏操曰:“吕布,豺狼也,勇而无谋,轻于去就,宜早图之。”操曰:“吾素知吕布狼子野心,诚难久养。非公父子莫能究其情,公当与吾谋之。”登曰:“丞相若有举动,某当为内应。”操喜,表赠陈珪秩中二千石,登为广陵太守。登辞回,操执登手曰:“东方之事,便以相付。”登点头允诺。回徐州见吕布,布问之,登言:“父赠禄,某为太守。”布大怒曰:“汝不为吾求徐州牧,而乃自求爵禄!汝父教我协同曹公,绝婚公路,今吾所求,终无一获;而汝父子俱各显贵,吾为汝父子所卖耳!”遂拔剑欲斩之。登大笑曰:“将军何其不明之甚也!”布曰:“吾何不明?”登曰:“吾见曹公,言养将军譬如养虎,当饱其肉,不饱则将噬人。曹公笑曰:“不如卿言。吾待温侯,如养鹰耳:狐兔未息,不敢先饱,饥则为用,饱则飏去。某问谁为狐兔,曹公曰:“淮南袁术;江东孙策、冀州袁绍、荆襄刘表、益州刘璋、汉中张鲁,皆狐兔也。布掷剑笑曰:“曹公知我也!”正说话间,忽报袁术军取徐州。吕布闻言失惊。正是:秦晋未谐吴越斗,婚姻惹出甲兵来。 毕竟后事如何,且听下文分解。 (本章完) -第17章 袁公路大起七军 曹孟德会合三将 +第17章 袁公路大起七军 曹孟德会合三将   却说袁术在淮南,地广粮多,又有孙策所质玉玺,遂思僭称帝号;大会群下议曰:“昔汉高祖不过泗上一亭长,而有天下;今历年四百,气数已尽,海内鼎沸。吾家四世三公,百姓所归;吾效应天顺人,正位九五。尔众人以为何如?”主簿阁象曰:“不可。昔周后稷积德累功,至于文王,三分天下有其二,犹以服事殷。明公家世虽贵,未若有周之盛;汉室虽微,未若殷纣之暴也。此事决不可行。”术怒曰:“吾袁姓出于陈。陈乃大舜之后。以土承火,正应其运。又谶云:代汉者,当涂高也。吾字公路,正应其谶。又有传国玉玺。若不为君,背天道也。吾意已决,多言者斩!”遂建号仲氏,立台省等官,乘龙凤辇,祀南北郊,立冯方女为后,立子为东宫。因命使催取吕布之女为东宫妃,却闻布已将韩胤解赴许都,为曹操所斩,乃大怒;遂拜张勋为大将军,统领大军二十余万,分七路征徐州:第一路大将张勋居中,第二路上将桥蕤居左,第三路上将陈纪居右,第四路副将雷薄居左,第五路副将陈兰居右,第六路降将韩暹居左,第七路降将杨奉居右。各领部下健将,克日起行。命兖州刺史金尚为太尉,监运七路钱粮。尚不从,术杀之。以纪灵为七路都救应使。术自引军三万,使李丰、梁刚、乐就为催进使,接应七路之兵。 吕布使人探听得张勋一军从大路径取徐州,桥蕤一军取小沛,陈纪一军取沂都,雷薄一军取琅琊,陈兰一军取碣石,韩暹一军取下邳,杨奉一军取浚山:七路军马,日行五十里,于路劫掠将来。乃急召众谋士商议,陈宫与陈珪父子俱至。陈宫曰:“徐州之祸,乃陈珪父子所招,媚朝廷以求爵禄,今日移祸于将军。可斩二人之头献袁术,其军自退。”布听其言,即命擒下陈珪、陈登。陈登大笑曰:“何如是之懦也?吾观七路之兵,如七堆腐草,何足介意!”布曰:“汝若有计破敌、免汝死罪。”陈登曰:“将军若用老夫之言,徐州可保无虞。”布曰:“试言之。”登曰:“术兵虽众,皆乌合之师,素不亲信;我以正兵守之,出奇兵胜之,无不成功。更有一计,不止保安徐州,并可生擒袁术。”布曰:“计将安出?”登曰:“韩暹、杨奉乃汉旧臣,因惧曹操而走,无家可依,暂归袁术;术必轻之,彼亦不乐为术用。若凭尺书结为内应,更连刘备为外合,必擒袁术矣。”布曰:“汝须亲到韩暹、杨奉处下书。”陈登允诺。布乃发表上许都,并致书与豫州,然后令陈登引数骑,先于下邳道上候韩暹。退引兵至,下寨毕,登入见。暹问曰:“汝乃吕布之人,来此何干?”登笑曰:“某为大汉公卿,何谓吕布之人?若将军者,向为汉臣,今乃为叛贼之臣,使昔日关中保驾之功,化为乌有,窃为将军不取也。且袁术性最多疑,将军后必为其所害。今不早图,悔之无及!”暹叹曰:“吾欲归汉,恨无门耳。”登乃出布书。暹览书毕曰:“吾已知之。公先回。吾与杨将军反戈击之。但看火起为号,温侯以兵相应可也。”登辞暹,急回报吕布。 布乃分兵五路,高顺引一军进小沛,敌桥蕤;陈宫引一军进沂都,敌陈纪;张辽、臧霸引一军出琅琊,敌雷薄;宋宪、魏续引一军出碣石,敌陈兰;吕布自引一军出大道,敌张勋。各领军一万,余者守城。吕布出城三十里下寨。张勋军到,料敌吕布不过,且退二十里屯住,待四下兵接应。 @@ -329,7 +329,7 @@ 却说张绣知操引兵来,急发书报刘表,使为后应;一面与雷叙、张先二将领兵出城迎敌。两阵对圆,张绣出马,指操骂曰:“汝乃假仁义无廉耻之人,与禽兽何异!”操大怒,令许褚出马。绣令张先接战。只三合,许褚斩张先于马下,绣军大败。操引军赶至南阳城下。绣入城,闭门不出。操围城攻打,见城壕甚阔,水势又深,急难近城。乃令军士运土填壕;又用土布袋并柴薪草把相杂,于城边作梯凳;又立云梯窥望城中;操自骑马绕城观之,如此三日。传令教军士于西门角上,堆积柴薪,会集诸将,就那里上城。城中贾诩见如此光景,便谓张绣曰:“某已知曹操之意矣。今可将计就计而行。”正是:强中自有强中手,用诈还逢识诈人。 不知其计若何,且听下文分解。 (本章完) -第18章 贾文和料敌决胜 夏侯惇拨矢啖睛 +第18章 贾文和料敌决胜 夏侯惇拨矢啖睛   却说贾诩料知曹操之意,便欲将计就计而行,乃谓张绣曰:“某在城上见曹操绕城而观者三日。他见城东南角砖土之色,新旧不等,鹿角多半毁坏,意将从此处攻进,却虚去西北上积草,诈为声势,欲哄我撤兵守西北,彼乘夜黑必爬东南角而进也。绣曰:“然则奈何?”诩曰:“此易事耳。来日可今精壮之兵,饱食轻装,尽蒙于东南房屋内,却教百姓假扮军士,虚守西北。夜间任他在东南角上爬城。俟其爬进城时,一声炮响,伏兵齐起,操可擒矣。”绣喜,从其计。 早有探马报曹操,说张绣尽撤兵在西北角上,呐喊守城,东南却甚空虚。操曰:“中吾计矣!”遂命军中密备锹钁爬城器具。日间只引军攻西北角。至二更时分,却领精兵于东南角上爬过壕去,砍开鹿角。城中全无动静,众军一齐拥入。只听得一声炮响,伏兵四起。曹军急退,背后张绣亲驱勇壮杀来。曹军大败,退出城外,奔走数十里。张绣直杀至天明方收军入城。曹操计点败军,折兵五万余人,失去辎重无数。吕虔、于禁俱各被伤。却说贾诩见操败走,急劝张绣遗书刘表,使起兵截其后路。表得书,即欲起兵。忽探马报孙策屯兵湖口。蒯良曰:“策屯兵湖口,乃曹操之计也。今操新败,若不乘势击之,后必有患。”表乃令黄祖坚守隘口,自己统兵至安众县截操后路;一面约会张绣。绣知表兵已起,即同贾诩引兵袭操。 且说操军缓缓而行,至襄城,到清水,操忽于马上放声大哭。众惊问其故,操曰:“吾思去年于此地折了吾大将典韦,不由不哭耳!”因即下令屯住军马,大设祭筵,吊奠典韦亡魂。操亲自拈香哭拜,三军无不感叹。祭典韦毕,方祭侄曹安民及长子曹昂,并祭阵亡军士;连那匹射死的大宛马,也都致祭。次日,忽荀彧差人报说:“刘表助张绣屯兵安众,截吾归路。”操答彧书曰:“吾日行数里,非不知贼来追我;然吾计划已定,若到安众,破绣必矣。君等勿疑。”便催军行至安众县界。刘表军已守险要,张绣随后引军赶来。操乃令众军黑夜凿险开道,暗伏奇兵。及天色微明,刘表、张绣军会合,见操兵少,疑操遁去,俱引兵入险击之。操纵奇兵出,大破两家之兵。曹兵出了安众隘口,于隘外下塞。刘表、张绣各整败兵相见。 @@ -344,7 +344,7 @@ 却说夏侯惇引军前进,正与高顺军相遇,便挺枪出马搦战。离顺迎敌。两马相交,战有四五十合,高顺抵敌不住,败下阵来。惇纵马追赶,顺绕阵而走。惇不舍,亦绕阵追之。阵上曹性看见,暗地拈弓搭箭,觑得亲切,一箭射去,正中夏侯惇左目。惇大叫一声,急用手拔箭,不想连眼珠拨出,乃大呼曰:“父精母血,不可弃也!”遂纳于口内啖之,仍复挺枪纵马,直取曹性。性不及提防,早被一枪搠透面门,死于马下。两边军士见者,无不骇然。夏侯惇既杀曹性,纵马便回。高顺从背后赶来,麾军齐上,曹兵大败。夏侯渊救护其兄而走。吕虔、李典将败军退去济北下寨。高顺得胜,引军回击玄德。恰好吕布大军亦至,布与张辽、高顺分兵三路,来攻玄德、关、张三寨,正是:啖睛猛将虽能战,中箭先锋难久持。 未知玄德胜负如何,且听下文分解。 (本章完) -第19章 下邳城曹操鏖兵 白门楼吕布殒命 +第19章 下邳城曹操鏖兵 白门楼吕布殒命   却说高顺引张辽击关公寨,吕布自击张飞寨,关、张各出迎战,玄德引兵两路接应。吕布分军从背后杀来,关、张两军皆溃,玄德引数十骑奔回沛城。吕布赶来,玄德急唤城上军士放下吊桥。吕布随后也到。城上欲待放箭,又恐射了玄德。被吕布乘势杀入城门,把门将士,抵敌不住,都四散奔避。吕布招军入城。玄德见势已急,到家不及,只得弃了妻小,穿城而过,走出西门,匹马逃难,吕布赶到玄德家中,糜竺出迎,告布曰:“吾闻大丈夫不废人之妻子。今与将军争天下者,曹公耳。玄德常念辕门射赖之恩,不敢背将军也。今不得已而投曹公,惟将军怜之。”布曰:“吾与玄德旧交,岂忍害他妻子。”便令糜竺引玄德妻小,去徐州安置。布自引军投山东兖州境上,留高顺、张辽守小沛。此时孙乾已逃出城外。关、张二人亦各自收得些人马,往山中住扎。 且说玄德匹马逃难,正行间,背后一人赶至,视之乃孙乾也。玄德曰:“吾今两弟不知存亡,妻小失散,为之奈何?”孙乾曰:“不若且投曹操,以图后计。”玄德依言,寻小路投许都。途次绝粮,尝往村中求食。但到处,闻刘豫州,皆争进饮食。一日,到一家投宿,其家一少年出拜,问其姓名,乃猎户刘安也。当下刘安闻豫州牧至,欲寻野味供食,一时不能得,乃杀其妻以食之。玄值曰:“此何肉也?”安曰:“乃狼肉也。”玄德不疑,乃饱食了一顿,天晚就宿。至晓将去,往后院取马,忽见一妇人杀于厨下,臂上肉已都割去。玄德惊问,方知昨夜食者,乃其妻之肉也。玄德不胜伤感,洒泪上马。刘安告玄德曰:“本欲相随使君,因老母在堂,未敢远行。”玄德称谢而别,取路出梁城。忽见尘头蔽日,一彪大军来到。玄德知是曹操之军,同孙乾径至中军旗下,与曹操相见,具说失沛城、散二弟、陷妻小之事。操亦为之下泪。又说刘安杀妻为食之事,操乃令孙乾以金百两往赐之。 军行至济北,夏侯渊等迎接入寨,备言兄夏侯惇损其一目,卧病未痊。操临卧处视之,令先回许都调理。一面使人打探吕布现在何处。探马回报云:“吕布与陈宫、臧霸结连泰山贼寇,共攻兖州诸郡。”操即令曹仁引三千兵打沛城;操亲提大军,与玄德来战吕布。前至山东,路近萧关,正遇泰山寇孙观、吴敦、尹礼、昌豨领兵三万余拦住去路。操令许褚迎战,四将一齐出马。许褚奋力死战,四将抵敌不住,各自败走。操乘势掩杀,追至萧关。探马飞报吕布。 @@ -363,7 +363,7 @@ 缚虎望宽今太懦,养鹰休饱昔无疑。恋妻不纳陈宫谏,枉骂无恩大耳儿。”又有诗论玄德曰:“伤人饿虎缚体宽,董卓丁原血未干。玄德既知能啖父,争如留取害曹瞒?”却说武士拥张辽至。操指辽曰:“这人好生面善。”辽曰:“濮阳城中曾相遇,如何忘却?”操笑曰:“你原来也记得!”辽曰:“只是可惜!”操曰:“可惜甚的?”辽曰:“可惜当日火不大,不曾烧死你这国贼!”操大怒曰:“败将安敢辱吾!”拔剑在手,亲自来杀张辽。辽全无惧色,引颈待杀。曹操背后一人攀住臂膊,一人跪于面前,说道:“丞相且莫动手!”正是:乞哀吕布无人救,骂贼张辽反得生。 毕竟救张辽的是谁,且听下文分解。 (本章完) -第20章 曹阿瞒许田打围 董国舅内阁受诏 +第20章 曹阿瞒许田打围 董国舅内阁受诏   话说曹操举剑欲杀张辽,玄德攀住臂膊,云长跪于面前。玄德曰,“此等赤心之人,正当留用。”云长曰:“关某素知文远忠义之士,愿以性命保之。”操掷剑笑曰:“我亦知文远忠义,故戏之耳。”乃亲释其缚,解衣衣之,延之上坐,辽感其意,遂降。操拜辽为中郎将,赐爵关内侯,使招安臧霸。霸闻吕布已死,张辽已降,遂亦引本部军投降。操厚赏之。臧霸又招安孙观、吴敦、尹礼来降;独昌豨未肯归顺。操封臧霸为琅琊相。孙观等亦各加官,令守青、徐沿海地面。将吕布妻女载回许都。大犒三军,拔寨班师。路过徐州,百姓焚香遮道,请留刘使君为牧。操曰:“刘使君功大,且待面君封爵,回来未迟。”百姓叩谢。操唤车骑将军车胄权领徐州。操军回许昌,封赏出征人员,留玄德在相府左近宅院歇定。 次日,献帝设朝,操表奏玄德军功,引玄德见帝。玄德具朝服拜于丹墀。帝宣上殿,问曰:“卿祖何人?”玄德奏曰:“臣乃中山靖王之后,孝景皇帝阁下玄孙,刘雄之孙,刘弘之子也。”帝教取宗族世谱检看,令宗正卿宣读曰:“孝景皇帝生十四子。第七子乃中山靖王刘胜。胜生陆城亭侯刘贞。贞生沛侯刘昂。昂生漳侯刘禄。禄生沂水侯刘恋。恋生钦阳侯刘英。英生安国侯刘建。建生广陵侯刘哀。哀生胶水侯刘宪。宪生祖邑侯刘舒。舒生祁阳侯刘谊。谊生原泽侯刘必。必生颍川侯刘达。达生丰灵侯刘不疑。不疑生济川侯刘惠。惠生东郡范令刘雄。雄生刘弘。弘不仕。刘备乃刘弘之子也。”帝排世谱,则玄德乃帝之叔也。帝大喜,请入偏殿叙叔侄之礼。帝暗思:“曹操弄权,国事都不由朕主,今得此英雄之叔,朕有助矣!”遂拜玄德为左将军、宜城亭侯。设宴款待毕,玄德谢恩出朝。自此人皆称为刘皇叔。 曹操回府,荀彧等一班谋士入见曰:“天子认刘备为叔,恐无益于明公。”操曰:“彼既认为皇叔,吾以天子之诏令之,彼愈不敢不服矣。况吾留彼在许都,名虽近君,实在吾掌握之内,吾何惧哉?吾所虑者,太尉杨彪系袁术亲戚,倘与二袁为内应,为害不浅。当即除之。”乃密使人诬告彪交通袁术,遂收彪下狱,命满宠按治之。时北海太守孔融在许都,因谏操曰:“杨公四世清德,岂可因袁氏而罪之乎?”操曰:“此朝廷意也。”融曰:“使成王杀召公,周公可得言不知耶?”操不得已,乃免彪官,放归田里。议郎赵彦愤操专横,上疏劾操不奉帝旨、擅收大臣之罪。操大怒,即收赵彦杀之。于是百官无不悚惧。谋士程昱说操曰:“今明公威名日盛,何不乘此时行王霸之事?”操曰:“朝廷股肱尚多,未可轻动。吾当请天子田猎,以观动静。”于是拣选良马、名鹰、俊犬、弓矢俱备,先聚兵城外,操入请天子田猎。帝曰:“田猎恐非正道。”操曰:“古之帝王,春搜夏苗,秋狝冬狩:四时出郊,以示武于天下。今四海扰攘之时,正当借田猎以讲武。”帝不敢不从,随即上逍遥马,带宝雕弓、金鈚箭,排銮驾出城。玄德与关、张各弯弓插箭,内穿掩心甲,手持兵器,引数十骑随驾出许昌。曹操骑爪黄飞电马,引十万之众,与天子猎于许田。军士排开围场,周广二百余里。操与天子并马而行,只争一马头。背后都是操之心腹将校。文武百官,远远侍从,谁敢近前。当日献帝驰马到许田,刘玄德起居道傍。帝曰:“朕今欲看皇叔射猎。”玄德领命上马,忽草中赶起一兔。玄德射之,一箭正中那兔。帝喝采。转过土坡,忽见荆棘中赶出一只大鹿。帝连射三箭不中,顾谓操曰:“卿射之。”操就讨天子宝雕弓、金鈚箭,扣满一射,正中鹿背,倒于草中。群臣将校,见了金鈚箭,只道天子射中,都踊跃向帝呼“万岁”。曹操纵马直出,遮于天子之前以迎受之。众皆失色。玄德背后云长大怒,剔起卧蚕眉,睁开丹凤眼,提刀拍马便出,要斩曹操。玄德见了,慌忙摇手送目。关公见兄如此,便不敢动。玄德欠身向操称贺曰:“丞相神射,世所罕及!”操笑曰:“此天子洪福耳。”乃回马向天子称贺,竟不献还宝雕弓,就自悬带。围场已罢,宴于许田。 @@ -378,7 +378,7 @@ 礼毕坐定,腾曰:“腾入觐将还,故来相辞,何见拒也?”承曰:“贱躯暴疾,有失迎候,罪甚!”腾曰:“面带春色,未见病容。”承无言可答。腾拂袖便起,嗟叹下阶曰:“皆非救国之人也!”承感其言,挽留之,问曰:“公谓何人非救国之人?”腾曰:“许田射猎之事,吾尚气满胸膛;公乃国之至戚,犹自殆于酒色,而不思讨贼,安得为皇家救难扶灾之人乎!”承恐其诈,佯惊曰:“曹丞相乃国之大臣,朝廷所倚赖,公何出此言?”腾大怒曰:“汝尚以曹贼为好人耶?”承曰:“耳目甚近,请公低声。”腾曰:“贪生怕死之徒,不足以论大事!”说罢又欲起身。承知腾忠义,乃曰:“公且息怒。某请公看一物。”遂邀腾入书院,取诏示之。腾读毕,毛发倒竖,咬齿嚼唇,满口流血,谓承曰:“公若有举动,吾即统西凉兵为外应。”承请腾与诸公相见,取出义状,教腾书名。腾乃取酒歃血为盟曰:“吾等誓死不负所约!”指坐上五人言曰:“若得十人,大事谐矣。”承曰:“忠义之士,不可多得。若所与非人,则反相害矣。”腾教取《鸳行鹭序簿》来检看。检到刘氏宗族,乃拍手言曰:“何不共此人商议?”众皆问何人。马腾不慌不忙,说出那人来。正是:本因国舅承明诏,又见宗潢佐汉朝。 毕竟马腾之言如何,且听下文分解。 (本章完) -第21章 曹操煮酒论英雄 关公赚城斩车胄 +第21章 曹操煮酒论英雄 关公赚城斩车胄   却说董承等问马腾曰:“公欲用何人?”马腾曰:“见有豫州牧刘玄德在此,何不求之?”承曰:“此人虽系皇叔,今正依附曹操,安肯行此事耶?”腾曰:“吾观前日围场之中,曹操迎受众贺之时,云长在玄德背后,挺刀欲杀操,玄德以目视之而止。玄德非不欲图操,恨操牙爪多,恐力不及耳。公试求之,当必应允。”吴硕曰:“此事不宜太速,当从容商议。”众皆散去。次日黑夜里,董承怀诏,径往玄德公馆中来。门吏入报,玄德迎出,请入小阁坐定。关、张侍立于侧。玄德曰:“国舅夤夜至此,必有事故。”承曰:“白日乘马相访,恐操见疑,故黑夜相见。”玄德命取酒相待。承曰:“前日围场之中,云长欲杀曹操,将军动目摆头而退之,何也?”玄德失惊曰:“公何以知之?”承曰:“人皆不见,某独见之。”玄德不能隐讳,遂曰:“舍弟见操僭越,故不觉发怒耳。”承掩面而哭曰:“朝廷臣子,若尽如云长,何忧不太平哉!”玄德恐是曹操使他来试探,乃佯言曰:“曹丞相治国,为何忧不太平?”承变色而起曰:“公乃汉朝皇叔,故剖肝沥胆以相告,公何诈也?”玄德曰:“恐国舅有诈,故相试耳。”于是董承取衣带诏令观之,玄德不胜悲愤。又将义状出示,上止有六位:一,车骑将军董承;二,工部侍郎王子服;三,长水校尉种辑;四,议郎吴硕;五,昭信将军吴子兰;六,西凉太守马腾。玄德曰:“公既奉诏讨贼,备敢不效犬马之劳。”承拜谢,便请书名。玄德亦书“左将军刘备”,押了字,付承收讫。承曰:“尚容再请三人,共聚十义,以图国贼,”玄德曰:“切宜缓缓施行,不可轻泄。”共议到五更,相别去了。 玄德也防曹操谋害,就下处后园种菜,亲自浇灌,以为韬晦之计。关、张二人曰:“兄不留心天下大事,而学小人之事,何也?”玄德曰:“此非二弟所知也。”二人乃不复言。 一日,关、张不在,玄德正在后园浇菜,许褚、张辽引数十人入园中曰:“丞相有命,请使君便行。”玄德惊问曰:“有甚紧事?”许褚曰:“不知。只教我来相请。”玄德只得随二人入府见操。操笑曰:“在家做得好大事!”?得玄德面如土色。操执玄德手,直至后园,曰:“玄德学圃不易!”玄德方才放心,答曰:“无事消遣耳。”操曰:“适见枝头梅子青青,忽感去年征张绣时,道上缺水,将士皆渴;吾心生一计,以鞭虚指曰:‘前面有梅林。’军士闻之,口皆生唾,由是不渴。今见此梅,不可不赏。又值煮酒正熟,故邀使君小亭一会。”玄德心神方定。随至小亭,已设樽俎:盘置青梅,一樽煮酒。二人对坐,开怀畅饮。酒至半酣,忽阴云漠漠,聚雨将至。从人遥指天外龙挂,操与玄德凭栏观之。操曰:“使君知龙之变化否?”玄德曰:“未知其详。”操曰:“龙能大能小,能升能隐;大则兴云吐雾,小则隐介藏形;升则飞腾于宇宙之间,隐则潜伏于波涛之内。方今春深,龙乘时变化,犹人得志而纵横四海。龙之为物,可比世之英雄。玄德久历四方,必知当世英雄。请试指言之。”玄德曰:“备肉眼安识英雄?”操曰:“休得过谦。”玄德曰:“备叨恩庇,得仕于朝。天下英雄,实有未知。”操曰:“既不识其面,亦闻其名。”玄德曰:“淮南袁术,兵粮足备,可为英雄?”操笑曰:“冢中枯骨,吾早晚必擒之!”玄德曰:“河北袁绍,四世三公,门多故吏;今虎踞冀州之地,部下能事者极多,可为英雄?“操笑曰:“袁绍色厉胆薄,好谋无断;干大事而惜身,见小利而忘命:非英雄也。玄德曰:“有一人名称八俊,威镇九州:刘景升可为英雄?”操曰:“刘表虚名无实,非英雄也。”玄德曰:“有一人血气方刚,江东领袖——孙伯符乃英雄也?”操曰:“孙策藉父之名,非英雄也。”玄德曰:“益州刘季玉,可为英雄乎?”操曰:“刘璋虽系宗室,乃守户之犬耳,何足为英雄!”玄德曰:“如张绣、张鲁、韩遂等辈皆何如?”操鼓掌大笑曰:“此等碌碌小人,何足挂齿!”玄德曰:“舍此之外,备实不知。”操曰:“夫英雄者,胸怀大志,腹有良谋,有包藏宇宙之机,吞吐天地之志者也。”玄德曰:“谁能当之?”操以手指玄德,后自指,曰:“今天下英雄,惟使君与操耳!”玄德闻言,吃了一惊,手中所执匙箸,不觉落于地下。时正值天雨将至,雷声大作。玄德乃从容俯首拾箸曰:“一震之威,乃至于此。”操笑曰:“丈夫亦畏雷乎?”玄德曰:“圣人迅雷风烈必变,安得不畏?”将闻言失箸缘故,轻轻掩饰过了。操遂不疑玄德。后人有诗赞曰:“勉从虎穴暂趋身,说破英雄惊杀人。巧借闻雷来掩饰,随机应变信如神。” @@ -395,7 +395,7 @@ 云长赶来,手起一刀,砍于马下,割下首级提回,望城上呼曰:“反贼车胄,吾已杀之;众等无罪,投降免死!”诸军倒戈投降,军民皆安。云长将胄头去迎玄德,具言车胄欲害之事,今已斩首。玄德大惊曰:“曹操若来。如之奈何?”云长曰:“弟与张飞迎之。”玄德懊悔不已,遂入徐州。百姓父老,伏道而接。玄德到府,寻张飞,飞已将车胄全家杀尽。玄德曰:“杀了曹操心腹之人,如何肯休?”陈登曰:“某有一计,可退曹操。”正是:既把孤身离虎穴,还将妙计息狼烟。 不知陈登说出甚计来,且听下文分解。 (本章完) -第22章 袁曹各起马步三军 关张共擒王刘二将 +第22章 袁曹各起马步三军 关张共擒王刘二将   却说陈登献计于玄德曰:“曹操所惧者袁绍。绍虎踞冀、青、幽、并诸郡,带甲百万,文官武将极多,今何不写书遣人到彼求救?”玄德曰:“绍向与我未通往来,今又新破其弟,安肯相助?”登曰:“此间有一人与袁绍三世通家,若得其一书致绍,绍必来相助。”玄德问何人。登曰:“此人乃公平日所折节敬礼者,何故忘之?”玄德猛省曰:“莫非郑康成先生乎?”登笑曰:“然也。”原来郑康成名玄,好学多才,尝受业于马融。融每当讲学,必设绛帐,前聚生徒,后陈声妓,侍女环列左右。玄听讲三年,目不邪视,融甚奇之。及学成而归。融叹曰:“得我学之秘者,惟郑玄一人耳!”玄家中侍婢俱通毛诗。一婢尝忤玄意,玄命长跪阶前。一婢戏谓之曰:“胡为乎泥中?”此婢应声曰:“薄言往愬,逢彼之怒。”其风雅如此。 桓帝朝,玄官至尚书;后因十常侍之乱,弃官归田,居于徐州。玄德在涿郡时,已曾师事之;及为徐州牧,时时造庐请教,敬礼特甚。当下玄德想出此人,大喜,便同陈登亲至郑玄家中,求其作书。玄慨然依允,写书一封,付与玄德。玄德便差孙乾星夜赍往袁绍处投递。绍览毕,自忖曰:“玄德攻灭吾弟,本不当相助;但重以郑尚书之命,不得不往救之。”遂聚文武官,商议兴兵伐曹操。谋士田丰曰:“兵起连年,百姓疲弊,仓廪无积,不可复兴大军。宜先遣人献捷天子,若不得通,乃表称曹操隔我王路,然后提兵屯黎阳;更于河内增益舟楫,缮置军器,分遣精兵,屯扎边鄙。三年之中,大事可定也。”谋士审配曰:“不然。以明公之神武,抚河朔之强盛,兴兵讨曹贼,易如反掌,何必迁延日月?”谋士沮授曰:“制胜之策,不在强盛。曹操法令既行,士卒精练,比公孙瓒坐受困者不同。今弃献捷良策,而兴无名之兵,窃为明公不取。”谋士郭图曰:“非也。 兵加曹操,岂曰无名?公正当及时早定大业。愿从郑尚书之言,与刘备共仗大义,剿灭曹贼,上合天意,下合民情,实为幸甚!”四人争论未定,绍躇踌不决。忽许攸、荀谌自外而入。绍曰:“二人多有见识,且看如何主张。”二人施礼毕,绍曰:“郑尚书有书来,令我起兵助刘备,攻曹操。起兵是乎?不起兵是乎?”二人齐声应曰:“明公以众克寡,以强攻弱,讨汉贼以扶王室:起兵是也。”绍曰:“二人所见,正合我心。”便商议兴兵。先令孙乾回授郑玄,并约玄德准备接应;一面令审配、逢纪为统军,田丰、荀谌、许攸为谋士,颜良、文丑为将军,起马军十五万,步兵十五万,共精兵三十万,望黎阳进发。分拨已定,郭图进曰:“以明公大义伐操,必须数操之恶,驰檄各郡,声罪致讨,然后名正言顺。”绍从之,遂令书记陈琳草檄。琳字孔璋,素有才名;灵帝时为主簿,因谏何进不听,复遭董卓之乱,避难冀州,绍用为记室。当下领命草檄,援笔立就。其文曰: @@ -428,7 +428,7 @@ 犬豕何堪共虎斗,鱼虾空自与龙争。 不知二人性命如何,且听下文分解。 (本章完) -第23章 祢正平裸衣骂贼 吉太医下毒遭刑 +第23章 祢正平裸衣骂贼 吉太医下毒遭刑   却说曹操欲斩刘岱、王忠。孔融谏曰:“二人本非刘备敌手,若斩之,恐失将士之心。”操乃免其死,黜罢爵禄。欲自起兵伐玄德。孔融曰:“方今隆冬盛寒,未可动兵,待来春未为晚也。可先使人招安张绣、刘表,然后再图徐州。”操然其言,先遣刘晔往说张绣。晔至襄城,先见贾诩,陈说曹公盛德。诩乃留晔于家中。次日来见张绣,说曹公遣刘晔招安之事。正议间,忽报袁绍有使至。绣命入。使者呈上书信。绣览之,亦是招安之意。诩问来使曰:“近日兴兵破曹操,胜负何如?”使曰:“隆冬寒月,权且罢兵。今以将军与荆州刘表俱有国士之风,故来相请耳。”诩大笑曰:“汝可便回见本初,道汝兄弟尚不能容,何能容天下国士乎!”当面扯碎书,叱退来使。 张绣曰:“方今袁强曹弱;今毁书叱使,袁绍若至,当如之何?”诩曰:“不如去从曹操。”绣曰:“吾先与操有仇,安得相容?”诩曰:“从操其便有三:夫曹公奉天子明诏,征伐天下,其宜从一也;绍强盛,我以少从之,必不以我为重,操虽弱,得我必喜,其宜从二也;曹公王霸之志,必释私怨,以明德于四海,其宜从三也。愿将军无疑焉。”绣从其言,请刘晔相见。晔盛称操德,且曰:“丞相若记旧怨,安肯使某来结好将军乎?”绣大喜,即同贾诩等赴许都投降。绣见操,拜于阶下。操忙扶起,执其手曰:“有小过失,勿记于心。”遂封绣为扬武将军,封贾诩为执金吾使。 操即命绣作书招安刘表。贾诩进曰:“刘景升好结纳名流,今必得一有文名之士往说之,方可降耳。”操问荀攸曰:“谁人可去?”攸曰:“孔文举可当其任。”操然之。攸出见孔融曰:“丞相欲得一有文名之士,以备行人之选。公可当此任否?”融曰:“吾友祢衡,字正平,其才十倍于我。此人宜在帝左右,不但可备行人而已。我当荐之天子。”于是遂上表奏帝。其文曰:“臣闻洪水横流,帝思俾乂;旁求四方,以招贤俊。昔世宗继统,将弘基业;畴咨熙载,群士响臻。陛下睿圣,纂承基绪,遭遇厄运,劳谦日昃;维岳降神,异人并出。窃见处士平原祢衡:年二十四,字正平,淑质贞亮,英才卓跞。初涉艺文,升堂睹奥;目所一见,辄诵之口,耳所暂闻,不忘于心;性与道合,思若有神;弘羊潜计,安世默识,以衡准之,诚不足怪。忠果正直,志怀霜雪;见善若惊,嫉恶若仇;任座抗行,史鱼厉节,殆无以过也。鸷鸟累百,不如一鹗;使衡立朝,必有可观。 @@ -451,7 +451,7 @@ 操见吉平已死,教左右牵过秦庆童至面前。操曰:“国舅认得此人否?”承大怒曰:“逃奴在此,即当诛之!”操曰:“他首告谋反,今来对证,谁敢诛之?”承曰:“丞相何故听逃奴一面之说?”操曰:“王子服等吾已擒下,皆招证明白,汝尚抵赖乎?”即唤左右拿下,命从人直入董承卧房内,搜出衣带诏并义状。操看了,笑曰:“鼠辈安敢如此!”遂命:“将董承全家良贱,尽皆监禁,休教走脱一个。”操回府以诏状示众谋士商议,要废献帝,更立新君。正是:数行丹诏成虚望,一纸盟书惹祸殃。 未知献帝性命如何,且听下文分解。 (本章完) -第24章 国贼行凶杀贵妃 皇叔败走投袁绍 +第24章 国贼行凶杀贵妃 皇叔败走投袁绍   却说曹操见了衣带诏,与众谋士商议,欲废却献帝,更择有德者立之。程昱谏曰:“明公所以能威震四方,号令天下者,以奉汉家名号故也,今诸侯未平,遽行废立之事,必起兵端矣。”操乃止。只将董承等五人,并其全家老小,押送各门处斩。死者共七百余人。城中官民见者,无不下泪。后人有诗叹董承曰:“密诏传衣带,天言出禁门。当年曾救驾,此日更承恩。忧国成心疾,除奸入梦魂。忠贞千古在,成败复谁论。”又有叹王子服等四人诗曰:“书名尺素矢忠谋,慷慨思将君父酬。赤胆可怜捐百口,丹心自是足千秋。” 且说曹操既杀了董承等众人,怒气未消,遂带剑入宫,来弑董贵妃。贵妃乃董承之妹,帝幸之,已怀孕五月。当日帝在后宫,正与伏皇后私论董承之事至今尚无音耗。忽见曹操带剑入宫,面有怒容,帝大惊失色。操曰:“董承谋反,陛下知否?”帝曰:“董卓已诛矣。”操大声曰:“不是董卓!是董承!”帝战栗曰:“朕实不知。”操曰:“忘了破指修诏耶?”帝不能答。操叱武士擒董妃至。帝告曰:“董妃有五月身孕,望丞相见怜。”操曰:“若非天败,吾已被害。岂得复留此女,为吾后患!”伏后告曰:“贬于冷宫,待分娩了,杀之未迟。”操曰:“欲留此逆种,为母报仇乎?”董妃泣告曰:“乞全尸而死,勿令彰露。”操令取白练至面前。帝泣谓妃曰:“卿于九泉之下,勿怨朕躬!”言讫,泪下如雨。伏后亦大哭。操怒曰:“犹作儿女态耶!”叱武士牵出,勒死于宫门之外。后人有诗叹董妃曰:“春殿承恩亦枉然,伤哉龙种并时捐。堂堂帝主难相救,掩面徒看泪涌泉。”操谕监宫官曰:“今后但有外戚宗族,不奉吾旨,辄入宫门者,斩,守御不严,与同罪。”又拨心腹人三千充御林军,令曹洪统领,以为防察。 操谓程昱曰:“今董承等虽诛,尚有马腾、刘备,亦在此数,不可不除。”昱曰:“马腾屯军西凉,未可轻取;但当以书慰劳,勿使生疑,诱入京师,图之可也。刘备现在徐州,分布掎角之势,亦不可轻敌。况今袁绍屯兵官渡,常有图许都之心。若我一旦东征,刘备势必求救于绍。绍乘虚来袭,何以当之?”操曰:“非也。备乃人杰也,今若不击,待其羽翼既成。急难图矣。袁绍虽强,事多怀疑不决,何足忧乎!”正议间,郭嘉自外而入。操问曰:“吾欲东征刘备,奈有袁绍之忧,如何?”嘉曰:“绍性迟而多疑,其谋士各相妒忌,不足忧也。刘备新整军兵,众心未服,丞相引兵东征,一战可定矣。”操大喜曰:“正合吾意。”遂起二十万大军,分兵五路下徐州。细作探知,报入徐州。 @@ -464,7 +464,7 @@ 整备窝弓射猛虎,安排香饵钓鳌鱼。 未知其计若何,且听下文分解。 (本章完) -第25章 屯土山关公约三事 救白马曹操解重围 +第25章 屯土山关公约三事 救白马曹操解重围   却说程昱献计曰:“云长有万人之敌,非智谋不能取之。今可即差刘备手下投降之兵,入下邳,见关公,只说是逃回的,伏于城中为内应;却引关公出战,诈败佯输,诱入他处,以精兵截其归路,然后说之可也。”操听其谋,即令徐州降兵数十,径投下邳来降关公。关公以为旧兵,留而不疑。 次日,夏侯惇为先锋,领兵五千来搦战。关公不出,惇即使人于城下辱骂。关公大怒,引三千人马出城,与夏侯惇交战。约战十馀合,惇拨回马走。关公赶来,惇且战且走。关公约赶二十里,恐下邳有失,提兵便回。只听得一声炮响,左有徐晃,右有许褚,两队军截住去路,关公夺路而走,两边伏兵排下硬弩百张,箭如飞蝗。关公不得过,勒兵再回,徐晃、许褚接住交战。关公奋力杀退二人,引军欲回下邳,夏侯惇又截住厮杀。公战至日晚,无路可归,只得到一座土山,引兵屯于山头,权且少歇。曹兵团团将土山围住。关公于山上遥望下邳城中火光冲天,却是那诈降兵卒偷开城门,曹操自提大军杀入城中,只教举火以惑关公之心。关公见下邳火起,心中惊惶,连夜几番冲下山来,皆被乱箭射回。 捱到天晓,再欲整顿下山冲突,忽见一人跑马上山来,视之乃张辽也。关公迎谓曰:“文远欲来相敌耶?”辽曰:“非也。想故人旧日之情,特来相见。”遂弃刀下马,与关公叙礼毕,坐于山顶。公曰:“文远莫非说关某乎?”辽曰:“不然。昔日蒙兄救弟,今日弟安得不救兄?”公曰:“然则文远将欲助我乎?”辽曰:“亦非也。”公曰:“既不助我,来此何干?”辽曰:“玄德不知存亡,翼德未知生死。昨夜曹公已破下邳,军民尽无伤害,差人护卫玄德家眷,不许惊忧。如此相待,弟特来报兄。”关公怒曰:“此言特说我也。吾今虽处绝地,视死如归。汝当速去,吾即下山迎战。”张辽大笑曰:“兄此言岂不为天下笑乎?”公曰:“吾仗忠义而死,安得为天下笑?”辽曰:“兄今即死,其罪有三。”公曰:“汝且说我那三罪?”辽曰:“当初刘使君与兄结义之时,誓同生死;今使君方败,而兄即战死,倘使君复出,欲求兄相助,而不可复得,岂不负当年之盟誓乎?其罪一也。刘使君以家眷付托于兄,兄今战死,二夫人无所依赖,负却使君依托之重。其罪二也。兄武艺超群,兼通经史,不思共使君匡扶汉室,徒欲赴汤蹈火,以成匹夫之勇,安得为义?其罪三也。兄有此三罪,弟不得不告。” @@ -481,7 +481,7 @@ 却说颜良败军奔回,半路迎见袁绍,报说被赤面长须使大刀一勇将,匹马入阵,斩颜良而去,因此大败。绍惊问曰:“此人是谁?”沮授曰:“此必是刘玄德之弟关云长也。”绍大怒,指玄德曰:“汝弟斩吾爱将,汝必通谋,留尔何用!”唤刀斧手推出玄德斩之。正是:初见方为座上客,此日几同阶下囚。 未知玄德性命如何,且听下文分解。 (本章完) -第26章 袁本初败兵折将 关云长挂印封金 +第26章 袁本初败兵折将 关云长挂印封金   却说袁绍欲斩玄德。玄德从容进曰:“明公只听一面之词,而绝向日之情耶?备自徐州失散,二弟云长未知存否;天下同貌者不少,岂赤面长须之人,即为关某也?明公何不察之?”袁绍是个没主张的人,闻玄德之言,责沮授曰:“误听汝言,险杀好人。”遂仍请玄德上帐坐,议报颜良之仇。帐下一人应声而进曰:“颜良与我如兄弟,今被曹贼所杀,我安得不雪其恨?”玄德视其人,身长八尺,面如獬豸,乃河北名将文丑也。袁绍大喜曰:“非汝不能报颜良之仇。吾与十万军兵,便渡黄河,追杀曹贼!”沮授曰:“不可。今宜留屯延津,分兵官渡,乃为上策。若轻举渡河,设或有变,众皆不能还矣。”绍怒曰:“皆是汝等迟缓军心,迁延日月,有妨大事!岂不闻兵贵神速乎?”沮授出,叹曰:“上盈其志,下务其功;悠悠黄河,吾其济乎!”遂托疾不出议事。玄德曰:“备蒙大恩,无可报效,意欲与文将军同行:一者报明公之德,二者就探云长的实信。”绍喜,唤文丑与玄德同领前部。文丑曰:“刘玄德屡败之将,于军不利。既主公要他去时,某分三万军,教他为后部。”于是文丑自领七万军先行,令玄德引三万军随后。 且说曹操见云长斩了颜良,倍加钦敬,表奏朝廷,封云长为汉寿亭侯,铸印送关公。忽报袁绍又使大将文丑渡黄河,已据延津之上。操乃先使人移徙居民于西河,然后自领兵迎之;传下将令:以后军为前军,以前军为后军;粮草先行,军兵在后。吕虔曰:“粮草在先,军兵在后,何意也?”操曰:“粮草在后,多被剽掠,故令在前。”虔曰:“倘遇敌军劫去,如之奈何?”操曰:“且待敌军到时,却又理会。”虚心疑未决。操令粮食辎重沿河堑至延津。操在后军,听得前军发喊,急教人看时,报说:“河北大将文丑兵至,我军皆弃粮草,四散奔走。后军又远,将如之何?”操以鞭指南阜曰:“此可暂避。”人马急奔土阜。操令军士皆解衣卸甲少歇,尽放其马。文丑军掩至。 众将曰:“贼至矣!可急收马匹,退回白马!”荀攸急止之曰:“此正可以饵敌,何故反退?”操急以目视荀攸而笑。攸知其意,不复言。文丑军既得粮草车仗,又来抢马。军士不依队伍,自相杂乱。曹操却令军将一齐下土阜击之,文丑军大乱。曹兵围裹将来,文丑挺身独战,军士自相践踏。文丑止遏不住,只得拨马回走。操在土阜上指曰:“文丑为河北名将、谁可擒之?”张辽、徐晃飞马齐出,大叫:“文丑休走!”文丑回头见二将赶上,遂按住铁枪,拈弓搭箭,正射张辽。徐晃大叫:“贼将休放箭!”张辽低头急躲,一箭射中头盔,将簪缨射去。辽奋力再赶,坐下战马,又被文丑一箭射中面颊。那马跪倒前蹄,张辽落地。文丑回马复来,徐晃急轮大斧,截住厮杀。只见文丑后面军马齐到,晃料敌不过,拨马而回。文丑沿河赶来。 @@ -496,7 +496,7 @@ 关公入内告知二嫂,随即至相府,拜辞曹操。操知来意,乃悬回避牌于门。关公怏怏而回,命旧日跟随人役,收拾车马,早晚伺候;分付宅中,所有原赐之物,尽皆留下,分毫不可带去。次日再往相府辞谢,门首又挂回避牌。关公一连去了数次,皆不得见。乃往张辽家相探,欲言其事。辽亦托疾不出。关公思曰:“此曹丞相不容我去之意。我去志已决,岂可复留!”即写书一封,辞谢曹操。书略曰:“羽少事皇叔,誓同生死;皇天后土,实闻斯言。前者下邳失守,所请三事,已蒙恩诺。今探知故主现在袁绍军中,回思昔日之盟,岂容违背?新恩虽厚,旧义难忘。兹特奉书告辞,伏惟照察。其有余恩未报,愿以俟之异日。”写毕封固,差人去相府投递;一面将累次所受金银,一一封置库中,悬汉寿亭侯印于堂上,请二夫人上车。关公上赤兔马,手提青龙刀,率领旧日跟随人役,护送车仗,径出北门。门吏挡之。关公怒目横刀,大喝一声,门吏皆退避。关公既出门,谓从者曰:“汝等护送车仗先行,但有追赶者,吾自当之,勿得惊动二位夫人。”从者推车,望官道进发。却说曹操正论关公之事未定,左右报关公呈书。操即看毕,大惊曰:“云长去矣!”忽北门守将飞报:“关公夺门而去,车仗鞍马二十余人,皆望北行。”又关公宅中人来报说:“关公尽封所赐金银等物。美女十人,另居内室。其汉寿亭侯印悬于堂上。丞相所拨人役,皆不带去,只带原跟从人,及随身行李,出北门去了。”众皆愕然。一将挺身出曰:“某愿将铁骑三千,去生擒关某,献与丞相!”众视之,乃将军蔡阳也。正是:欲离万丈蛟龙穴,又遇三千狼虎兵。 蔡阳要赶关公,毕竟如何,且听下文分解。 (本章完) -第27章 美髯公千里走单骑 汉寿侯五关斩六将 +第27章 美髯公千里走单骑 汉寿侯五关斩六将   却说曹操部下诸将中,自张辽而外,只有徐晃与云长交厚,其余亦皆敬服;独蔡阳不服关公,故今日闻其去,欲往追之。操曰:“不忘故主,来去明白,真丈夫也。汝等皆当效之。”遂叱退蔡阳,不令去赶。程昱曰:“丞相待关某甚厚,今彼不辞而去,乱言片楮,冒渎钧威,其罪大矣。若纵之使归袁绍,是与虎添翼也。不若追而杀了,以绝后患。”操曰:“吾昔已许之,岂可失信!彼各为其主,勿追也。”因谓张辽曰:“云长封金挂印,财贿不以动其心,爵禄不以移其志,此等人吾深敬之。想他去此不远,我一发结识他做个人情。汝可先去请住他,待我与他送行,更以路费征袍赠之,使为后日记念。”张辽领命,单骑先往。曹操引数十骑随后而来。 却说云长所骑赤兔马,日行千里,本是赶不上;因欲护送车仗,不敢纵马,按辔徐行。忽听背后有人大叫:“云长且慢行!”回头视之,见张辽拍马而至。关公教车仗从人,只管望大路紧行;自己勒住赤兔马,按定青龙刀,问曰:“文远莫非欲追我回乎?”辽曰:“非也。丞相知兄远行,欲来相送,特先使我请住台驾,别无他意。”关公曰:“便是丞相铁骑来,吾愿决一死战!”遂立马于桥上望之。见曹操引数十骑,飞奔前来,背后乃是许褚、徐晃、于禁、李典之辈。操见关公横刀立马于桥上,令诸将勒住马匹,左右排开。关公见众人手中皆无军器,方始放心。操曰:“云长行何太速?”关公于马上欠身答曰:“关某前曾禀过丞相。今故主在河北,不由某不急去。 累次造府,不得参见,故拜书告辞,封金挂印,纳还丞相。望丞相勿忘昔日之言。”操曰:“吾欲取信于天下,安肯有负前言。恐将军途中乏用,特具路资相送。”一将便从马上托过黄金一盘。关公曰:“累蒙恩赐,尚有余资。留此黄金以赏将士。”操曰:“特以少酬大功于万一,何必推辞?”关公曰:“区区微劳,何足挂齿。”操笑曰:“云长天下义士,恨吾福薄,不得相留。锦袍一领,略表寸心。”令一将下马,双手捧袍过来。云长恐有他变,不敢下马,用青龙刀尖挑锦袍披于身上,勒马回头称谢曰:“蒙丞相赐袍,异日更得相会。”遂下桥望北而去。许褚曰:“此人无礼太甚,何不擒之?”操曰:“彼一人一骑,吾数十余人,安得不疑?吾言既出,不可追也。”曹操自引众将回城,于路叹想云长不已。 @@ -515,7 +515,7 @@ 关公于马上自叹曰:“吾非欲沿途杀人,奈事不得已也。曹公知之,必以我为负恩之人矣。”正行间,忽见一骑自北而来,大叫:“云长少住!”关公勒马视之,乃孙乾也。关公曰:“自汝南相别,一向消息若何?”乾曰:“刘辟、龚都自将军回兵之后,复夺了汝南;遣某往河北结好袁绍,请玄德同谋破曹之计。不想河北将士,各相妒忌。田丰尚囚狱中;沮授黜退不用;审配、郭图各自争权;袁绍多疑,主持不定。某与刘皇叔商议,先求脱身之计。今皇叔已往汝南会合刘辟去了。恐将军不知,反到袁绍处,或为所害,特遣某于路迎接将来。幸于此得见。将军可速往汝南与皇叔相会。”关公教孙乾拜见夫人。夫人问其动静。孙乾备说袁绍二次欲斩皇叔,今幸脱身往汝南去了。夫人可与云长到此相会。二夫人皆掩面垂泪。关公依言,不投河北去,径取汝南来。正行之间,背后尘埃起处,一彪人马赶来,当先夏侯惇大叫:“关某休走!”正是:六将阻关徒受死,一军拦路复争锋。 毕竟关公怎生脱身,且听下文分解。 (本章完) -第28章 斩蔡阳兄弟释疑 会古城主臣聚义 +第28章 斩蔡阳兄弟释疑 会古城主臣聚义   却说关公同孙乾保二嫂向汝南进发,不想夏侯惇领三百余骑,从后追来。孙乾保车仗前行。关公回身勒马按刀问曰:“汝来赶我,有失丞相大度。”夏侯惇曰:“丞相无明文传报,汝于路杀人,又斩吾部将,无礼太甚!我特来擒你,献与丞相发落!”言讫,便拍马挺枪欲斗。 只见后面一骑飞来,大叫:“不可与云长交战!”关公按辔不动。来使于怀中取出公文,谓夏侯惇曰:“丞相敬爱关将军忠义,恐于路关隘拦截,故遣某特赍公文,遍行诸处。”惇曰:“关某于路杀把关将士,丞相知否?”来使曰:“此却未知。”惇曰:“我只活捉他去见丞相,待丞相自放他。”关公怒曰:“吾岂惧汝耶!”拍马持刀,直取夏侯惇。惇挺枪来迎。两马相交,战不十合,忽又一骑飞至,大叫:“二将军少歇!”惇停枪问来使曰:“丞相叫擒关某乎?”使者曰:“非也。丞相恐守关诸将阻挡关将军,故又差某驰公文来放行。”惇曰:“丞相知其于路杀人否?”使者曰:“未知。”惇曰:“既未知其杀人,不可放去。”指挥手下军士,将关公围住。 关公大怒,舞刀迎战。两个正欲交锋,阵后一人飞马而来,大叫:“云长、元让,休得争战!”众视之,乃张辽也。二人各勒住马。张辽近前言曰:“奉丞相钧旨:因闻知云长斩关杀将,恐于路有阻,特差我传谕各处关隘,任便放行。”惇曰:“秦琪是蔡阳之甥。他将秦琪托付我处,今被关某所杀,怎肯干休?”辽曰:“我见蔡将军,自有分解。既丞相大度,教放云长去,公等不可废丞相之意。”夏侯惇只得将军马约退。辽曰:“云长今欲何往?”关公曰:“闻兄长又不在袁绍处,吾今将遍天下寻之。”辽曰:“既未知玄德下落,且再回见丞相,若何?”关公笑曰:“安有是理!文远回见丞相,幸为我谢罪。”说毕,与张辽拱手而别。于是张辽与夏侯惇领军自回。 @@ -538,7 +538,7 @@ 只因河北英雄去,引出江东豪杰来。 未知其事如何,且听下文分解。 (本章完) -第29章 小霸王怒斩于吉 碧眼儿坐领江东 +第29章 小霸王怒斩于吉 碧眼儿坐领江东   却说孙策自霸江东,兵精粮足。建安四年,袭取庐江,败刘勋,使虞翻驰檄豫章,豫章太守华歆投降。自此声势大振,乃遣张纮往许昌上表献捷。曹操知孙策强盛,叹曰:“狮儿难与争锋也!”遂以曹仁之女许配孙策幼弟孙匡,两家结婚。留张纮在许昌。孙策求为大司马,曹操不许。策恨之,常有袭许都之心。于是吴郡太守许贡,乃暗遣使赴许都上书于曹操。其略曰:“孙策骁勇,与项籍相似。朝廷宜外示荣宠,召在京师;不可使居外镇,以为后患。”使者赍书渡江,被防江将士所获,解赴孙策处。策观书大怒,斩其使,遣人假意请许贡议事。贡至,策出书示之,叱曰:“汝欲送我于死地耶!”命武士绞杀之。贡家属皆逃散。有家客三人,欲为许贡报仇,恨无其便。一日,孙策引军会猎于丹徒之西山,赶起一大鹿,策纵马上山逐之。正赶之间,只见树林之内有三个人持枪带弓面立。策勒马问曰:“汝等何人?”答曰:“乃韩当军士也。在此射鹿。”策方举辔欲行,一人拈枪望策左腿便刺。 策大惊,急取佩剑从马上砍去,剑刃忽坠,止存剑靶在手。一人早拈弓搭箭射来,正中孙策面颊。策就拔面上箭,取弓回射放箭之人,应弦面倒。那二人举枪向孙策乱搠,大叫曰:“我等是许贡家客,特来为主人报仇!”策别无器械,只以弓拒之,且拒且走。二人死战不退。策身被数枪,马亦带伤。正危急之时,程普引数人至。孙策大叫:“杀贼!“程普引众齐上,将许贡家客砍为肉泥。看孙策时,血流满面,被伤至重,乃以刀割抱,裹其伤处,救回吴会养病。后人有诗赞许家三客曰:“孙郎智勇冠江湄,射猎山中受困危。许客三人能死义,杀身豫让未为奇。”却说孙策受伤而回,使人寻请华伦医治。不想华佗已往中原去了,止有徒弟在吴,命其治疗。其徒曰:“箭头有药,毒已入骨。须静养百日,方可无虞。若怒气冲激,其疮难治。”孙策为人最是性急,恨不得即日便愈。将息到二十余日,忽闻张纮有使者自许昌回,策唤问之。使者曰:“曹操甚惧主公;其帐下谋士,亦俱敬服;惟有郭嘉不服。” 策曰:“郭嘉曾有何说?”使者不敢言。策怒,固问之。使者只得从实告曰:“郭嘉曾对曹操言主公不足惧也:轻而无备,性急少谋,乃匹夫之勇耳,他日必死于小人之手。”策闻言,大怒曰:“匹夫安敢料吾!吾誓取许昌!”遂不待疮愈,便欲商议出兵。张昭谏曰:“医者戒主公百日休动,今何因一时之忿,自轻万金之躯?”正话间,忽报袁绍遣使陈震至。策唤入问之。震具言袁绍欲结东吴为外应,共攻曹操。策大喜,即日会诸将于城楼上,设宴款待陈震。饮酒之间,忽见诸将互相耳语,纷纷下楼。策怪问何故,左右曰:“有于神仙者,今从楼下过,诸将欲往拜之耳。”策起身凭栏观之,见一道人,身披鹤氅,手携藜杖,立于当道,百姓俱焚香伏道而拜。策怒曰:“是何妖人?快与我擒来!”左右告曰:“此人姓于,名吉,寓居东方,往来吴会,普施符水,救人万病,无有不验。当世呼为神仙,未可轻渎。”策愈怒,喝令:“速速擒来!违者斩!” @@ -557,7 +557,7 @@ 肃又荐一人见孙权:此人博学多才,事母至孝;覆姓诸葛,名瑾,字子瑜,琅琊南阳人也。权拜之为上宾。瑾劝权勿通袁绍,且顺曹操,然后乘便图之。权依言,乃遣陈震回,以书绝袁绍。却说曹操闻孙策已死,欲起兵下江南。侍御史张纮谏曰:“乘人之丧而伐之,既非义举;若其不克,弃好成仇:不如因而善遇之。”操然其说,乃即奏封孙权为将军,兼领会稽太守;即令张纮为会稽都尉,赍印往江东。孙权大喜,又得张纮回吴,即命与张昭同理政事。张纮又荐一人于孙权:此人姓顾,名雍,字元叹,乃中郎蔡邕之徒;其为人少言语,不饮酒,严厉正大。权以为丞,行太守事。自是孙权威震江东,深得民心。且说陈震回见袁绍,具说:“孙策已亡,孙权继立。曹操封之为将军,结为外应矣。”袁绍大怒,遂起冀、青、幽、并等处人马七十余万,复来攻取许昌。正是:江南兵革方休息,冀北干戈又复兴。 未知胜负若何,且听下文分解。 (本章完) -第30章 战官渡本初败绩 劫乌巢孟德烧粮 +第30章 战官渡本初败绩 劫乌巢孟德烧粮   却说袁绍兴兵,望官渡进发。夏侯惇发书告急。曹操起军七万,前往迎敌,留荀彧守许都。绍兵临发,田丰从狱中上书谏曰:“今且宜静守以待天时,不可妄兴大兵,恐有不利。”逢纪谮曰:“主公兴仁义之师,田丰何得出此不祥之语!”绍因怒,欲斩田丰。众官告免。绍恨曰:“待吾破了曹操,明正其罪!”遂催军进发,旌旗遍野,刀剑如林。行至阳武,下定寨栅。沮授曰:“我军虽众,而勇猛不及彼军;彼军虽精,而粮草不如我军。彼军无粮,利在急战;我军有粮,宜且缓守。若能旷以日月,则彼军不战自败矣。”绍怒曰:“田丰慢我军心,吾回日必斩之。汝安敢又如此!”叱左右:“将沮授锁禁军中,待我破曹之后,与田丰一体治罪!”于是下令,将大军七十万,东西南北,周围安营,连络九十余里。 细作探知虚实,报至官渡。曹军新到,闻之皆惧。曹操与众谋士商议。荀攸曰:“绍军虽多,不足惧也。我军俱精锐之士,无不一以当十。但利在急战。若迁延日月,粮草不敷,事可忧矣。”操曰:“所言正合吾意。”遂传令军将鼓噪而进。绍军来迎,两边排成阵势。审配拨弩手一万,伏于两翼;弓箭手五千,伏于门旗内:约炮响齐发。三通鼓罢,袁绍金盔金甲,锦袍玉带,立马阵前。左右排列着张郃、高览、韩猛、淳于琼等诸将。旌旗节钺,甚是严整。曹阵上门旗开处,曹操出马。许诸、张辽、徐晃、李典等,各持兵器,前后拥卫。曹操以鞭指袁绍曰:“吾于天子之前,保奏你为大将军,今何故谋反?”绍怒曰:“汝托名汉相,实为汉贼!罪恶弥天,甚于莽、卓,乃反诬人造反耶!”操曰:“吾今奉诏讨汝!”绍曰:“吾奉衣带诏讨贼!”操怒,使张辽出战。张邰跃马来迎。 二将斗了四五十合,不分胜负。曹操见了,暗暗称奇。许褚挥刀纵马,直出助战。高览挺枪接住。四员将捉对儿厮杀。曹操令夏侯惇、曹洪,各引三千军,齐冲彼阵。审配见曹军来冲阵,便令放起号炮:两下万弩并发,中军内弓箭手一齐拥出阵前乱射。曹军如何抵敌,望南急走。袁绍驱兵掩杀,曹军大败,尽退至官渡。袁绍移军逼近官渡下寨。审配曰:“今可拨兵十万守官渡,就曹操寨前筑起土山,令军人下视寨中放箭。操若弃此而去,吾得此隘口,许昌可破矣。”绍从之,于各寨内选精壮军人,用铁锹土担,齐来曹操寨边,垒土成山。曹营内见袁军堆筑土山,欲待出去冲突,被审配弓弩手当住咽喉要路,不能前进。十日之内,筑成土山五十余座,上立高橹,分拨弓弩手于其上射箭。曹军大惧,皆顶着遮箭牌守御。土山上一声梆子响处,箭下如雨。曹军皆蒙楯伏地,袁军呐喊而笑。 @@ -578,7 +578,7 @@ 势弱只因多算胜,兵强却为寡谋亡。 未知胜负如何,且看下文分解。 (本章完) -第31章 曹操仓亭破本初 玄德荆州依刘表 +第31章 曹操仓亭破本初 玄德荆州依刘表   却说曹操乘袁绍之败,整顿军马,迤逦追袭。袁绍幅巾单衣,引八百余骑,奔至黎阳北岸,大将蒋义渠出寨迎接。绍以前事诉与义渠。义渠乃招谕离散之众,众闻绍在,又皆蚁聚。军势复振,议还冀州。军行之次,夜宿荒山。绍于帐中闻远远有哭声,遂私往听之。却是败军相聚,诉说丧兄失弟,弃伴亡亲之苦,各各捶胸大哭,皆曰:“若听田丰之言,我等怎遭此祸!”绍大悔曰:“吾不听田丰之言,兵败将亡;今回去,有何面目见之耶!”次日,上马正行间,逢纪引军来接。绍对逢纪曰:“吾不听田丰之言,致有此败。吾今归去,羞见此人。”逢纪因谮曰:“丰在狱中闻主公兵败,抚掌大笑曰:果不出吾之料!”袁绍大怒曰:“竖儒怎敢笑我!我必杀之!”遂命使者赍宝剑先往冀州狱中杀田丰。 却说田丰在狱中。一日,狱吏来见丰曰:“与别驾贺喜!”丰曰:“何喜可贺?”狱吏曰:“袁将军大败而回,君必见重矣。”丰笑曰:“吾今死矣!”狱吏问曰:“人皆为君喜,君何言死也?”丰曰:“袁将军外宽而内忌,不念忠诚。若胜而喜,犹能赦我;今战败则羞,吾不望生矣。”狱吏未信。忽使者赍剑至,传袁绍命,欲取田丰之首,狱吏方惊。丰曰:“吾固知必死也。”狱吏皆流泪。丰曰:“大丈夫生于天地间,不识其主而事之,是无智也!今日受死,夫何足惜!”乃自刎于狱中。后人有诗曰:“昨朝沮授军中失,今日田丰狱内亡。河北栋梁皆折断,本初焉不丧家邦!”田丰既死,闻者皆为叹惜。 袁绍回冀州,心烦意乱,不理政事。其妻刘氏劝立后嗣。绍所生三子长子袁谭字显思,出守青州;次子袁熙字显奕,出守幽州;三子袁尚字显甫,是绍后妻刘氏所出,生得形貌俊伟,绍至爱之,因此留在身边。自官渡兵败之后,刘氏劝立尚为后嗣,绍乃与审配、逢纪、辛评、郭图四人商议、原来审、逢二人,向辅袁尚;辛、郭二人,向辅袁谭;四人各为其主。当下袁绍谓四人曰:“今外患未息,内事不可不早定,吾将议立后嗣:长子谭,为人性刚好杀;次子熙,为人柔懦难成;三子尚,有英雄之表,礼贤敬士,吾欲立之。公等之意若何?”郭图曰:“三子之中,谭为长,今又居外;主公若废长立幼,此乱萌也。今军威稍挫,敌兵压境,岂可复使父子兄弟自相争乱耶?主公且理会拒敌之策,立嗣之事,毋容多议。”袁绍踌躇未决。忽报袁熙引兵六万,自幽州来;袁谭引兵五万,自青州来;外甥高干亦引兵五万,自并州来:各至冀州助战。绍喜,再整人马来战曹操。时操引得胜之兵,陈列于河上,有土人箪食壶浆以迎之。操见父老数人,须发尽白,乃命入帐中赐坐,问之曰:“老丈多少年纪?”答曰:“欲近百岁矣。”操曰:“吾军士惊扰汝乡,吾甚不安。”父老曰:“桓帝时,有黄星见于楚、宋之分,辽东人殷馗善晓天文,夜宿于此,对老汉等言:黄星见于乾象,正照此间。后五十年,当有真人起于梁沛之间。今以年计之,整整五十年。袁本初重敛于民,民皆怨之。丞相兴仁义之兵,吊民伐罪,官渡一战,破袁绍百万之众,正应当时殷馗之言,兆民可望太平矣。”操笑曰:“何敢当老丈所言?”遂取酒食绢帛赐老人而遣之。号令三军:“如有下乡杀人家鸡犬者,如杀人之罪!”于是军民震服。操亦心中暗喜。人报袁绍聚四州之兵,得二三十万,前至仓亭下寨。操提兵前进,下寨已定。次日,两军相对,各布成阵势。操引诸将出阵,绍亦引三子一甥及文官武将出到阵前。操曰:“本初计穷力尽,何尚不思投降?直待刀临项上,悔无及矣!”绍大怒,回顾众将曰:“谁敢出马?”袁尚欲于父前逞能,便舞双刀,飞马出阵,来往奔驰。操指问众将曰:“此何人?”有识者答曰:“此袁绍三子袁尚也。”言未毕,一将挺枪早出。操视之,乃徐晃部将史涣也。两骑相交,不三合,尚拨马刺斜而走。史涣赶来,袁尚拈弓搭箭,翻身背射,正中史涣左目,坠马而死。袁绍见子得胜,挥鞭一指,大队人马拥将过来,混战大杀一场,各鸣金收军还寨。 @@ -593,7 +593,7 @@ 玄德见表,执礼甚恭。表亦相待甚厚。玄德引关、张等拜见刘表,表遂与玄德等同入荆州,分拨院宅居住。却说曹操探知玄德已往荆州投奔刘表,便欲引兵攻之。程昱曰:“袁绍未除,而遽攻荆襄,倘袁绍从北而起,胜负未可知矣。不如还兵许都,养军蓄锐,待来年春暖,然后引兵先破袁绍,后取荆襄:南北之利,一举可收也。”操然其言,遂提兵回许都。至建安七年,春正月,操复商议兴兵。先差夏侯惇、满宠镇守汝南,以拒刘表;留曹仁、荀彧守许都:亲统大军前赴官渡屯扎。且说袁绍自旧岁感冒吐血症候,今方稍愈,商议欲攻许都。审配谏曰:“旧岁官渡,仓亭之败,军心未振;尚当深沟高垒,以养军民之力。”正议间,忽报曹操进兵官渡,来攻冀州。绍曰:“若候兵临城下,将至壕边,然后拒敌,事已迟矣。吾当自领大军出迎。”袁尚曰:“父亲病体未痊,不可远征。儿愿提兵前去迎敌。”绍许之,遂使人往青州取袁谭,幽州取袁熙,并州取高干:四路同破曹操。正是:才向汝南鸣战鼓,又从冀北动征鼙。 未知胜负如何,且听下文分解。 (本章完) -第32章 夺冀州袁尚争锋 决漳河许攸献计 +第32章 夺冀州袁尚争锋 决漳河许攸献计   却说袁尚自斩史涣之后,自负其勇,不待袁谭等兵至,自引兵数万出黎阳,与曹军前队相迎。张辽当先出马,袁尚挺枪来战,不三合,架隔遮拦不住,大败而走。张辽乘势掩杀,袁尚不能主张,急急引军奔回冀州。 袁绍闻袁尚败回,又受了一惊,旧病复发,吐血数斗,昏倒在地。刘夫人慌救入卧内,病势渐危。刘夫人急请审配、逢纪,直至袁绍榻前,商议后事。绍但以手指而不能言。刘夫人曰:“尚可继后嗣否?”绍点头。审配便就榻前写了遗嘱。绍翻身大叫一声,又吐血斗余而死。后人有诗曰:“累世公卿立大名,少年意气自纵横。空招俊杰三千客,漫有英雄百万兵。羊质虎皮功不就,凤毛鸡胆事难成。更怜一种伤心处,家难徒延两弟兄。”袁绍既死,审配等主持丧事。刘夫人便将袁绍所爱宠妾五人尽行杀害;又恐其阴魂于九泉之下再与绍相见,乃髡其发,刺其面,毁其尸:其妒恶如此。袁尚恐宠妾家属为害,并收而杀之。审配、逢纪立袁尚为大司马将军,领冀、青、幽、并四州牧,遣使报丧。此时袁谭已发兵离青州,知父死,便与郭图、辛评商议。 图曰:“主公不在冀州,审配、逢纪必立显甫为主矣。当速行。”辛评曰:“审、逢二人,必预定机谋。今若速往,必遭其祸。”袁谭曰:“若此当何如?”郭图曰:“可屯兵城外,观其动静。某当亲往察之。”谭依言。郭图遂入冀州,见袁尚。礼毕,尚问:“兄何不至?”图曰:“因抱病在军中,不能相见。”尚曰:“吾受父亲遗命,立我为主,加兄为车骑将军。目下曹军压境,请兄为前部,吾随后便调兵接应也。”图曰:“军中无人商议良策,愿乞审正南、逢元图二人为辅。”尚曰:“吾亦欲仗此二人早晚画策,如何离得!”图曰:“然则于二人内遣一人去,何如?”尚不得已,乃令二人拈阄,拈着者便去。逢纪拈着,尚即命逢纪赍印绶,同郭图赴袁谭军中。纪随图至谭军,见谭无病,心中不安,献上印绶。谭大怒,欲斩逢纪。郭图密谏曰:“今曹军压境,且只款留逢纪在此,以安尚心。待破曹之后,却来争冀州不迟。” @@ -615,7 +615,7 @@ 却说操长子曹丕,字子桓,时年十八岁。丕初生时,有云气一片,其色青紫,圆如车盖,覆于其室,终日不散。有望气者,密谓操曰:“此天子气也。令嗣贵不可言!”丕八岁能属文,有逸才,博古通今,善骑射,好击剑。时操破冀州,不随父在军中,先领随身军,径投袁绍家,下马拔剑而入。有一将当之曰:“丞相有命,诸人不许入绍府。”不叱退,提剑入后堂。见两个妇人相抱而哭,不向前欲杀之。正是:四世公侯已成梦,一家骨肉又遭殃。 未知性命如何,且听下文分解。 (本章完) -第33章 曹丕乘乱纳甄氏 郭嘉遗计定辽东 +第33章 曹丕乘乱纳甄氏 郭嘉遗计定辽东   却说曹丕见二妇人啼哭,拔剑欲斩之。忽见红光满目,遂按剑而问曰:“汝何人也?”一妇人告曰:“妾乃袁将军之妻刘氏也。”丕曰:“此女何人?”刘氏曰:“此次男袁熙之妻甄氏也。因熙出镇幽州,甄氏不肯远行,故留于此。”丕拖此女近前,见披发垢而。不以衫袖拭其面而观之,见甄氏玉肌花貌,有倾国之色。遂对刘氏曰:“吾乃曹丞相之子也。愿保汝家。汝勿忧虑。”道按剑坐于堂上。 却说曹操统领众将入冀州城,将入城门,许攸纵马近前,以鞭指城门而呼操曰:“阿瞒,汝不得我,安得入此门?”操大笑。众将闻言,俱怀不平。操至绍府门下,问曰:“谁曾入此门来?”守将对曰:“世子在内。”操唤出责之。刘氏出拜曰:“非世子不能保全妾家,愿就甄氏为世子执箕帚。”操教唤出甄氏拜于前。操视之曰:“真吾儿妇也?”遂令曹不纳之。 操既定冀州,亲往袁绍墓下设祭,再拜而哭甚哀,顾谓众官曰:“昔日吾与本初共起兵时,本初问吾曰:‘若事不辑,方面何所可据?’吾问之曰:‘足下意欲若何?’本初曰:‘吾南据河,北阻燕代,兼沙漠之众,南向以争天下,庶可以济乎?’吾答曰:‘吾任天下之智力,以道御之,无所不可。’此言如昨,而今本初已丧,吾不能不为流涕也!”众皆叹息。操以金帛粮米赐绍妻刘氏。乃下令曰:“河北居民遭兵革之难,尽免今年租赋。”一面写表申朝;操自领冀州牧。 @@ -635,7 +635,7 @@ 星文方向南中指,金宝旋从北地生。 不知所得何物,且听下文分解。 (本章完) -第34章 蔡夫人隔屏听密语 刘皇叔跃马过檀溪 +第34章 蔡夫人隔屏听密语 刘皇叔跃马过檀溪   却说曹操于金光处,掘出一铜雀,间荀攸曰:“此何兆也?”攸曰:“昔舜母梦玉雀入怀而生舜。今得铜雀,亦吉祥之兆也。”操大喜,遂命作高台以庆之。乃即日破土断木,烧瓦磨砖,筑铜雀台于漳河之上。约计一年而工毕。少子曹植进曰:“若建层台,必立三座:中间高者,名为铜雀;左边一座,名为玉龙;右边一座,名为金凤。更作两条飞桥,横空而上,乃为壮观。”操曰:“吾儿所言甚善。他日台成,足可娱吾者矣!”原来曹操有五子,惟植性敏慧,善文章,曹操平日最爱之。于是留曹植与曹丕在邺郡造台,使张燕守北寨。操将所得袁绍之兵,共五六十万,班师回许都。大封功臣;又表赠郭嘉为贞侯,养其子奕于府中。复聚众谋士商议,欲南征刘表。荀彧曰:“大军方北征而回,未可复动。且待半年,养精蓄锐,刘表、孙权可一鼓而下也。”操从之,遂分兵屯田,以候调用。 却说玄德自到荆州,刘表待之甚厚。一日,正相聚饮酒,忽报降将张武、陈孙在江夏掳掠人民,共谋造反。表惊曰:“二贼又反,为祸不小!”玄德曰:“不须兄长忧虑,备请往讨之。”表大喜,即点三万军,与玄德前去。玄德领命即行,不一日,来到江夏。张武、陈孙引兵来迎。玄德与关、张、赵云出马在门旗下,望见张武所骑之马,极其雄骏。玄德曰:“此必千里马也。”言未毕,赵云挺枪而出,径冲彼阵。张武纵马来迎,不三合,被赵云一枪刺落马下,随手扯住辔头,牵马回阵。陈孙见了,随赶来夺。张飞大喝一声,挺矛直出,将陈孙刺死。众皆溃散。玄德招安余党,平复江夏诸县,班师而回。表出郭迎接入城,设宴庆功。酒至半酣,表曰:“吾弟如此雄才,荆州有倚赖也。但忧南越不时来寇,张鲁、孙权皆足为虑。”玄德曰:“弟有三将,足可委用:使张飞巡南越之境;云长拒固子城,以镇张鲁;赵云拒三江,以当孙权。何足虑哉?”表喜,欲从其言。 蔡瑁告其姊蔡夫人曰:“刘备遣三将居外,而自居荆州,久必为患。”蔡夫人乃夜对刘表曰:“我闻荆州人多与刘备往来,不可不防之。今容其居住城中,无益,不若遣使他往。”表曰:“玄德仁人也。”蔡氏曰:“只恐他人不似汝心。”表沉吟不答。次日出城,见玄德所乘之马极骏,问之,知是张武之马,表称赞不已。玄德遂将此马送与刘表。表大喜,骑回城中。蒯越见而问之。表曰:“此玄德所送也。”越曰:“昔先兄蒯良,最善相马;越亦颇晓。此马眼下有泪槽,额边生白点,名为的卢,骑则妨主。张武为此马而亡。主公不可乘之。”表听其言。次日请玄德饮宴,因言曰:“昨承惠良马,深感厚意。但贤弟不时征进,可以用之。敬当送还。”玄德起谢。表又曰:“贤弟久居此间,恐废武事。襄阳属邑新野县,颇有钱粮。弟可引本部军马于本县屯扎,何如?”玄德领诺。次日,谢别刘表,引本部军马径往新野。 @@ -652,7 +652,7 @@ 逃生独出西门道,背后追兵复将到。一川烟水涨檀溪,急叱征骑往前跳。马蹄蹄碎青玻璃,天风响处金鞭挥。耳畔但闻千骑走,波中忽见双龙飞。西川独霸真英主,坐下龙驹两相遇。檀溪溪水自东流,龙驹英主今何处!临流三叹心欲酸,斜阳寂寂照空山;三分鼎足浑如梦,踪迹空留在世间。”玄德跃过溪西,顾望东岸。蔡瑁已引军赶到溪边,大叫:“使君何故逃席而去?”玄德曰:“吾与汝无仇,何故欲相害?”瑚曰:“吾并无此心。使君休听人言。”玄德见瑁手将拈弓取箭,乃急拨马望西南而去。瑁谓左右曰:“是何神助也?”方欲收军回城,只见西门内赵云引三百军赶来。正是:跃去龙驹能救主,追来虎将欲诛仇。 未知蔡瑁性命如何,且听下文分解。 (本章完) -第35章 玄德南漳逢隐沧 单福新野遇英主 +第35章 玄德南漳逢隐沧 单福新野遇英主   却说蔡瑁方欲回城,赵云引军赶出城来。原来赵云正饮酒间,忽见人马动,急入内观之,席上不见了玄德。云大惊,出投馆舍,听得人说:“蔡瑁引军望西赶去了。”云火急绰枪上马,引着原带来三百军,奔出西门,正迎着蔡瑁,急问曰:“吾主何在?”瑁曰:“使君逃席而去,不知何往。”赵云是谨细之人,不肯造次,即策马前行。遥望大溪,别无去路,乃复回马,喝问蔡瑁曰:“汝请吾主赴宴,何故引着军马追来?”瑁曰:“九郡四十二州县官僚俱在此,吾为上将,岂可不防护?”云曰:“汝逼吾主何去了?”瑁曰:“闻使君匹马出西门,到此却又不见。”云惊疑不定,直来溪边看时,只见隔岸一带水迹。云暗忖曰:“难道连马跳过了溪去?”令三百军四散观望,并不见踪迹。云再回马时,蔡瑁已入城去了。云乃拿守门军士追问,皆说:“刘使君飞马出西门而去。”云再欲入城?又恐有埋伏,遂急引军归新野。 却说玄德跃马过溪,似醉如痴,想:“此阔涧一跃而过,岂非天意!”迤逦望南漳策马而行,日将沉西。正行之间,见一牧童跨于牛背上,口吹短笛而来。玄德叹曰:“吾不如也!”遂立马观之。牧童亦停牛罢笛,熟视玄德,曰:“将军莫非破黄巾刘玄德否?”玄德惊问曰:“汝乃村僻小童,何以知吾姓字!”牧童曰:“我本不知,因常侍师父,有客到日,多曾说有一刘玄德,身长七尺五寸,垂手过膝,目能自顾其耳,乃当世之英雌,今观将军如此模样,想必是也。”玄德曰:“汝师何人也?”牧童曰:“吾师覆姓司马,名徽,字德操,颍川人也。道号水镜先生。”玄德曰:“汝师与谁为友?”小童曰:“与襄阳庞德公、庞统为友。”玄德曰:“庞德公乃庞统何人?”童子曰:“叔侄也。庞德公字山民,长俺师父十岁;庞统字士元,少俺师父五岁。一日,我师父在树上采桑,适庞统来相访,坐于树下,共相议论,终日不倦。吾师甚爱庞统,呼之为弟。”玄德曰:“汝师今居何处?”牧童遥指曰:“前面林中,便是庄院。”玄德曰:“吾正是刘玄德。汝可引我去拜见你师父。”童子便引玄德,行二里余,到庄前下马,入至中门,忽闻琴声甚美。玄德教童子且休通报,侧耳听之。琴声忽住而不弹。 一人笑而出曰:“琴韵清幽,音中忽起高抗之调。必有英雄窃听。”童子指谓玄德曰:“此即吾师水镜先生也。”玄德视其人,松形鹤骨,器宇不凡。慌忙进前施礼,衣襟尚湿。水镜曰:“公今日幸免大难!”玄德惊讶不已。小童曰:“此刘玄德也。”水镜请入草堂,分宾主坐定。玄德见架上满堆书卷,窗外盛栽松竹,横琴于石床之上,清气飘然。水镜问曰:“明公何来?”玄德曰:“偶尔经由此地,因小童相指,得拜尊颜,不胜万幸!”水镜笑曰:“公不必隐讳。公今必逃难至此。”玄德遂以襄阳一事告之。水镜曰:“吾观公气色,已知之矣。”因问玄德曰:“吾久闻明公大名,何故至今犹落魄不偶耶?”玄德曰:“命途多蹇,所以至此。”水镜曰:“不然。盖因将军左右不得其人耳。”玄德曰:“备虽不才,文有孙乾、糜竺、简雍之辈,武有关、张、赵云之流,竭忠辅相,颇赖其力。”水镜曰:“关、张、赵云,皆万人敌,惜无善用之之人。若孙乾、糜竺辈,乃白面书生,非经纶济世之才也。”玄德曰:“备亦尝侧身以求山谷之遗贤,奈未遇其人何!”水镜曰:“岂不闻孔子云十室之邑必有忠信,何谓无人?”玄德曰:“备愚昧不识,愿赐指教。”水镜曰:“公闻荆襄诸郡小儿谣言乎?其谣曰:八九年间始欲衰,至十三年无孑遗。到头天命有所归,泥中蟠龙向天飞。此谣始于建安初:建安八年,刘景升丧却前妻,便生家乱,此所谓始欲衰也;无孑遗者,不久则景升将逝,文武零落无孑遗矣;天命有归,龙向天飞,盖应在将军也。”玄德闻言惊谢曰:“备安敢当此!”水镜曰:“今天下之奇才,尽在于此,公当往求之。”玄德急问曰:“奇才安在?果系何人?”水镜曰:“伏龙、凤雏,两人得一,可安天下。”玄德曰:“伏龙、凤雏何人也?”水镜抚掌大笑曰:“好!好!”玄德再问时,水镜曰:“天色已晚,将军可于此暂宿一宵,明日当言之。”即命小童具饮馔相待,马牵入后院喂养。玄德饮膳毕,即宿于草堂之侧。玄德因思水镜之言,寝不成寐。 @@ -666,7 +666,7 @@ 却说败军回见曹仁,报说:“二吕被杀,军士多被活捉。”曹仁大惊,与李典商议。典曰:“二将欺敌而亡,今只宜按兵不动,申报丞相,起大兵来征剿,乃为上策。”仁曰:“不然。今二将阵亡,死折许多军马,此仇不可不急报。量新野弹丸之地,何劳丞相大军?”典曰:“刘备人杰也,不可轻视。”仁曰:“公何怯也!”典曰:“兵法云知彼知己,百战百胜。某非怯战,但恐不能必胜耳。”仁怒曰:“公怀二心耶?吾必欲生擒刘备!”典曰:“将军若去,某守樊城。”仁曰:“汝若不同去,真怀二心矣!”典不得已,只得与曹仁点起二万五千军马,渡河投新野而来。正是:偏裨既有舆尸辱,主将重兴雪耻兵。 未知胜负何如,且听下文分解。 (本章完) -第36章 玄德用计袭樊城 元直走马荐诸葛 +第36章 玄德用计袭樊城 元直走马荐诸葛   却说曹仁忿怒,遂大起本部之兵,星夜渡河,意欲踏平新野。且说单福得胜回县,谓玄德曰:“曹仁屯兵樊城,今知二将被诛,必起大军来战。”玄德曰:“当何以迎之?”福曰:“彼若尽提兵而来,樊城空虚,可乘间夺之。”玄德问计。福附耳低言如此如此。玄德大喜,预先准备已定。忽报马报说:“曹仁引大军渡河来了。”单福曰:“果不出吾之料。”遂请玄德出军迎敌。两阵对圆,赵云出马唤彼将答话。曹仁命李典出阵,与赵云交锋。约战十数合,李典料敌不过,拨马回阵。云纵马追赶,两翼军射住,遂各罢兵归寨。李典回见曹仁,言:“彼军精锐,不可轻敌,不如回樊城。”曹仁大怒曰:“汝未出军时,已慢吾军心;今又卖阵,罪当斩首!”便喝刀斧手推出李典要斩;众将苦告方免。乃调李典领后军,仁自引兵为前部。 次日鸣鼓进军,布成一个阵势,使人问玄德曰:“识吾阵势?”单福便上高处观看毕,谓玄德曰:“此八门金锁阵也。八门者:休、生、伤、杜、景、死、惊、开。如从生门、景门、开门而入则吉;从伤门、惊门、休门而入则伤;从杜门、死们而人则亡。今八门虽布得整齐,只是中间通欠主持。如从东南角上生门击人,往正西景门而出,其阵必乱。”玄德传令,教军士把住阵角,命赵云引五百军从东南而入,径往西出。云得令,挺枪跃马,引兵径投东南角上,呐喊杀入中军。曹仁便投北走。云不追赶,却突出西门,又从西杀转东南角上来。曹仁军大乱。玄德麾军冲击,曹兵大败而退。单福命休追赶,收军自回。却说曹仁输了一阵,方信李典之言;因复请典商议,言:“刘备军中必有能者,吾阵竟为所破。”李典曰:“吾虽在此,甚忧樊城。”曹仁曰:“今晚去劫寨。如得胜,再作计议;如不胜,便退军回樊城。”李典曰:“不可。刘备必有准备。”仁曰:“若如此多疑,何以用兵!”遂不听李典之言。自引军为前队,使李典为后应,当夜二更劫寨。 却说单福正与玄德在寨中议事,忽信风骤起。福曰:“今夜曹仁必来劫寨。”玄德曰:“何以敌之?”福笑曰:“吾已预算定了。”遂密密分拨已毕。至二更,曹仁兵将近寨,只见寨中四围火起,烧着寨栅。曹仁知有准备,急令退军。赵云掩杀将来。仁不及收兵回寨,急望北河而走。将到河边,才欲寻船渡河,岸上一彪军杀到:为首大将,乃张飞也。曹仁死战,李典保护曹仁下船渡河。曹军大半淹死水中。曹仁渡过河面,上岸奔至樊城,令人叫门。只见城上一声鼓响,一将引军而出,大喝曰:“吾已取樊城多时矣!”众惊视之,乃关云长也。仁大惊,拨马便走。云长追杀过来。曹仁又折了好些军马,星夜投许昌。 @@ -682,7 +682,7 @@ 且说徐庶既别玄德,感其留恋之情,恐孔明不肯出山辅之,遂乘马直至卧龙冈下,入草庐见孔明。孔明问其来意。庶曰:“庶本欲事刘豫州,奈老母为曹操所囚,驰书来召,只得舍之而往。临行时,将公荐与玄德。玄德即日将来奉谒,望公勿推阻,即展平生之大才以辅之,幸甚!”孔明闻言作色曰:“君以我为享祭之牺牲乎!”说罢,拂袖而入。庶羞惭而退,上马趱程,赴许昌见母。正是:嘱友一言因爱主,赴家千里为思亲。 未知后事若何,下文便见。 (本章完) -第37章 司马徽再荐名士 刘玄德三顾草庐 +第37章 司马徽再荐名士 刘玄德三顾草庐   却说徐庶趱程赴许昌。曹操知徐庶已到,遂命荀彧、程昱等一班谋士往迎之。庶入相府拜见曹操。操曰:“公乃高明之士,何故屈身而事刘备乎?”庶曰:“某幼逃难,流落江湖,偶至新野,遂与玄德交厚,老母在此,幸蒙慈念,不胜愧感。”操曰:“公今至此,正可晨昏侍奉令堂,吾亦得听清诲矣。”庶拜谢而出。急往见其母,泣拜于堂下。母大惊曰:“汝何故至此?”庶曰:“近于新野事刘豫州;因得母书,故星夜至此。”徐母勃然大怒,拍案骂曰:“辱子飘荡江湖数年,吾以为汝学业有进,何其反不如初也!汝既读书,须知忠孝不能两全。 岂不识曹操欺君罔上之贼?刘玄德仁义布于四海,况又汉室之胄,汝既事之,得其主矣,今凭一纸伪书,更不详察,遂弃明投暗,自取恶名,真愚夫也!吾有何面目与汝相见!汝玷辱祖宗,空生于天地间耳!”骂得徐庶拜伏于地,不敢仰视,母自转入屏风后去了。少顷,家人出报曰:“老夫人自缢于梁间。”徐庶慌入救时,母气已绝。后人有《徐母赞》曰:“贤哉徐母,流芳千古:守节无亏,于家有补;教子多方,处身自苦;气若丘山,义出肺腑;赞美豫州,毁触魏武;不畏鼎镬,不惧刀斧;唯恐后嗣,玷辱先祖。伏剑同流,断机堪伍;生得其名,死得其所:贤哉徐母,流芳千古!”徐虑见母已死,哭绝于地,良久方苏。曹操使人赍礼吊问,又亲往祭奠。徐庶葬母柩于许昌之南原,居丧守墓。凡曹操所赐,庶俱不受。 时操欲商议南征。荀彧谏曰:“天寒未可用兵;姑待春暖,方可长驱大进。”操从之,乃引漳河之水作一池,名玄武池,于内教练水军,准备南征。 @@ -699,7 +699,7 @@ 玄德回新野之后,光阴荏苒,又早新春。乃令卜者揲蓍,选择吉期,斋戒三日,薰沐更衣,再往卧龙冈谒孔明。关、张闻之不悦,遂一齐入谏玄德。正是:高贤未服英雄志,屈节偏生杰士疑。 不知其言若何,下文便晓。 (本章完) -第38章 定三分隆中决策 战长江孙氏报仇 +第38章 定三分隆中决策 战长江孙氏报仇   却说玄德访孔明两次不遇,欲再往访之。关公曰:“兄长两次亲往拜谒,其礼太过矣。想诸葛亮有虚名而无实学,故避而不敢见。兄何惑于斯人之甚也!”玄德曰:“不然,昔齐桓公欲见东郭野人,五反而方得一面。况吾欲见大贤耶?”张飞曰:“哥哥差矣。量此村夫,何足为大贤;今番不须哥哥去;他如不来,我只用一条麻绳缚将来!”玄德叱曰:“汝岂不闻周文王谒姜子牙之事乎?文王且如此敬贤,汝何太无礼!今番汝休去,我自与云长去。”飞曰:“既两位哥哥都去,小弟如何落后!”玄德曰:“汝若同往,不可失礼。”飞应诺。 于是三人乘马引从者往隆中。离草庐半里之外,玄德便下马步行,正遇诸葛均。玄德忙施礼,问曰:“令兄在庄否?”均曰:“昨暮方归。将军今日可与相见。”言罢,飘然自去。玄德曰:“今番侥幸得见先生矣!”张飞曰:“此人无礼!便引我等到庄也不妨,何故竟自去了!”玄德曰:“彼各有事,岂可相强。”三人来到庄前叩门,童子开门出问。玄德曰:“有劳仙童转报:刘备专来拜见先生。”童子曰:“今日先生虽在家,但今在草堂上昼寝未醒。”玄德曰:“既如此,且休通报。”分付关、张二人,只在门首等着。玄德徐步而入,见先生仰卧于草堂几席之上。 玄德拱立阶下。半晌,先生未醒。关、张在外立久,不见动静,入见玄德犹然侍立。张飞大怒,谓云长曰:“这先生如何傲慢!见我哥哥侍立阶下,他竟高卧,推睡不起!等我去屋后放一把火,看他起不起!”云长再三劝住。玄德仍命二人出门外等候。望堂上时,见先生翻身将起,忽又朝里壁睡着。童子欲报。玄德曰:“且勿惊动。”又立了一个时辰,孔明才醒,口吟诗曰:“大梦谁先觉?平生我自知,草堂春睡足,窗外日迟迟。”孔明吟罢,翻身问童子曰:“有俗客来否?”童子曰:“刘皇叔在此,立候多时。”孔明乃起身曰:“何不早报!尚容更衣。”遂转入后堂。又半晌,方整衣冠出迎。 @@ -719,7 +719,7 @@ 细作探知,报至江夏。黄祖急聚众商议,令苏飞为大将,陈就、邓龙为先锋,尽起江夏之兵迎敌。陈就、邓龙各引一队艨艟截住沔口,艨艟上各设强弓硬弩千余张,将大索系定艨艟于水面上。东吴兵至,艨艟上鼓响,弓弩齐发,兵不敢进,约退数里水面。甘宁谓董袭曰:“事已至此,不得不进。”乃选小船百余只,每船用精兵五十人:二十人撑船,三十人各披衣甲,手执铜刀,不避矢石,直至艨艟傍边,砍断大索,艨艟遂横。甘宁飞上艨艟,将邓龙砍死。陈就弃船而走。吕蒙见了,跳下小船,自举橹棹,直入船队,放火烧船。陈就急待上岸,吕蒙舍命赶到跟前,当胸一刀砍翻。比及苏飞引军于岸上接应时,东吴诸将一齐上岸,势不可当。祖军大败。苏飞落荒而走,正遇东吴大将潘璋,两马相交,战不数合,被璋生擒过去,径至船中来见孙权。权命左右以槛车囚之,待活捉黄祖,一并诛戮。催动三军,不分昼夜,攻打夏口。正是:只因不用锦帆贼,至令冲开大索船。 不知黄祖胜负如何,且看下文分解。 (本章完) -第39章 荆州城公子三求计 博望坡军师初用兵 +第39章 荆州城公子三求计 博望坡军师初用兵   却说孙权督众攻打夏口,黄祖兵败将亡,情知守把不住,遂弃江夏,望荆州而走。甘宁料得黄祖必走荆州,乃于东门外伏兵等候。祖带数十骑突出东门,正走之间,一声喊起,甘宁拦住。祖于马上谓宁曰:“我向日不曾轻待汝,今何相逼耶?”宁叱曰:“吾昔在江夏,多立功绩,汝乃以劫江贼待我,今日尚有何说!”黄祖自知难免,拨马而走。甘宁冲开士卒,直赶将来,只听得后面喊声起处,又有数骑赶来。宁视之,乃程普也。宁恐普来争功,慌忙拈弓搭箭,背射黄祖,祖中箭翻身落马;宁枭其首级,回马与程普合兵一处,回见孙权,献黄祖首级。权命以木匣盛贮,待回江东祭献于亡父灵前。重赏三军,升甘宁为都尉。商议欲分兵守江夏。张昭曰:“孤城不可守,不如且回江东。刘表知我破黄祖,必来报仇;我以逸待劳,必败刘表;表败而后乘势攻之,荆襄可得也。”权从其言,遂弃江夏,班师回江东。 苏飞在槛车内,密使人告甘宁求救。宁曰:“飞即不言,吾岂忘之?”大军既至吴会,权命将苏飞袅首,与黄祖首级一同祭献。甘宁乃入见权,顿首哭告曰:“某向日若不得苏飞,则骨填沟壑矣,安能效命将军麾下哉?今飞罪当诛,某念其昔日之恩情,愿纳还官爵,以赎飞罪。”权曰:“彼既有恩于君,吾为君赦之。但彼若逃去奈何?宁曰:“飞得免诛戮,感恩无地,岂肯走乎!若飞去,宁愿将首级献于阶下。”权乃赦苏飞,止将黄祖首级祭献。祭毕设宴,大会文武庆功。 正饮酒间,忽见座上一人大哭而起,拔剑在手,直取甘宁。宁忙举坐椅以迎之。权惊视其人,乃凌统也,因甘宁在江夏时,射死他父亲凌操,今日相见,故欲报仇。权连忙劝住,谓统曰:“兴霸射死卿父,彼时各为其主,不容不尽力。今既为一家人,岂可复理旧仇?万事皆看吾面。”凌统即头大哭曰:“不共戴天之仇,岂容不报!”权与众官再三劝之,凌统只是怒目而视甘宁。权即日命甘宁领兵五千、战船一百只,往夏口镇守,以避凌统。宁拜谢,领兵自往夏口去了。权又加封凌统为承烈都尉。统只得含恨而止。东吴自此广造战船,分兵守把江岸;又命孙静引一枝军守吴会;孙权自领大军,屯柴桑;周瑜日于鄱阳湖教练水军,以备攻战。 @@ -736,7 +736,7 @@ 且说李典见势头不好,急奔回博望城时,火光中一军拦住。当先大将,乃关云长也。李典纵马混战,夺路而走。于禁见粮草车辆,都被火烧,便投小路奔逃去了。夏侯兰、韩浩来救粮草,正遇张飞。战不数合,张飞一枪刺夏侯兰于马下。韩浩夺路走脱。直杀到天明,却才收军。杀得尸横遍野,血流成河。后人有诗曰:“博望相持用火攻,指挥如意笑谈中。直须惊破曹公胆,初出茅庐第一功!”夏侯惇收拾残军,自回许昌。却说孔明收军。关、张二人相谓曰:“孔明真英杰也!”行不数里,见糜竺、糜芳引军簇拥着一辆小车。车中端坐一人,乃孔明也。关、张下马拜伏于车前。须臾,玄德、赵云、刘封、关平等皆至,收聚众军,把所获粮草辎重,分赏将士,班师回新野,新野百姓望尘遮道而拜,曰:“吾属生全,皆使君得贤人之力也!”孔明回至县中,谓玄德曰:“夏侯惇虽败去,曹操必自引大军来。”玄德曰:“似此如之奈何?”孔明曰:“亮有一计,可敌曹军。”正是:破敌未堪息战马,避兵又必赖良谋。 未知其计若何,且看下回分解。 (本章完) -第40章 蔡夫人议献荆州 诸葛亮火烧新野 +第40章 蔡夫人议献荆州 诸葛亮火烧新野   却说玄德问孔明求拒曹兵之计。孔明曰:“新野小县,不可久居,近闻刘景升病在危笃,可乘此机会,取彼荆州为安身之地,庶可拒曹操也。”玄德曰:“公言甚善;但备受景升之恩,安忍图之!”孔明曰:“今若不取,后悔何及!”玄德曰:“吾宁死,不忍作负义之事。”孔明曰:“且再作商议。” 却说夏侯惇败回许昌,自缚见曹操,伏地请死。操释之。惇曰:“惇遭诸葛亮诡计,用火攻破我军。”操曰:“汝自幼用兵,岂不知狭处须防火攻?”惇曰:“李典、于禁曾言及此,悔之不及!”操乃赏二人。惇曰:“刘备如此猖狂,真腹心之患也,不可不急除。”操曰:“吾所虑者,刘备、孙权耳;余皆不足介意,今当乘此时扫平江南。”便传令起大兵五十万,令曹仁、曹洪为第一队,张辽、张郃为第二队。夏侯渊、夏侯惇为第三队,于禁、李典为第四队,操自领诸将为第五队:每队各引兵十万。又令许褚为折冲将军,引兵三千为先锋。选定建安十三年秋七月丙午日出师。 太中大夫孔融谏曰:“刘备,刘表皆汉室宗亲,不可轻伐;孙权虎踞六郡,且有大江之险,亦不易取,今丞相兴此无义之师,恐失天下之望。”操怒曰:“刘备、刘表、孙权皆逆命之臣,岂容不讨!”遂叱退孔融,下令:“如有再谏者,必斩。”孔融出府,仰天叹曰:“以至不仁伐至仁,安得不败乎!”时御史大夫郗虑家客闻此言,报知郗虑,虑常被孔融侮慢,心正恨之,乃以此言入告曹操,且曰:“融平日每每狎侮丞相,又与祢衡相善,衡赞融曰仲尼不死,融赞衡曰颜回复生。向者祢衡之辱丞相,乃融使之也。”操大怒,遂命廷尉捕捉孔融。融有二子,年尚少,时方在家,对坐弈棋。左右急报曰:“尊君被廷尉执去,将斩矣!二公子何不急避?”二子曰:“破巢之下,安有完卵乎?”言未已,廷尉又至,尽收融家小并二子,皆斩之,号令融尸于市。京兆脂习伏尸而哭。操闻之,大怒,欲杀之。荀彧曰:“彧闻脂习常谏融曰:公刚直太过,乃取祸之道,今融死而来哭,乃义人也,不可杀。”操乃止,习收融父子尸首,皆葬之。后人有诗赞孔融曰:“孔融居北海,豪气贯长虹:坐上客长满,樽中酒不空;文章惊世俗,谈笑侮王公。史笔褒忠直,存官纪太中。”曹操既杀孔融,传令五队军马次第起行,只留荀彧等守许昌。 @@ -752,7 +752,7 @@ 却说云长在上流用布袋遏住河水,黄昏时分,望见新野火起;至四更,忽听得下流头人喊马嘶,急令军士一齐掣起布袋,水势滔天,望下流冲去,曹军人马俱溺于水中,死者极多。曹仁引众将望水势慢处夺路而走。行到博陵渡口,只听喊声大起,一军拦路,当先大将,乃张飞也,大叫:“曹贼快来纳命!”曹军大惊。正是:城内才看红焰吐,水边又遇黑风来。 未知曹仁性命如何,且看下文分解。 (本章完) -第41章 刘玄德携民渡江 赵子龙单骑救主 +第41章 刘玄德携民渡江 赵子龙单骑救主   却说张飞因关公放了上流水,遂引军从下流杀将来,截住曹仁混杀。忽遇许褚,便与交锋;许褚不敢恋战,夺路走脱。张飞赶来,接着玄德、孔明,一同沿河到上流。刘封、糜芳已安排船只等候,遂一齐渡河,尽望樊城而去,孔明教将船筏放火烧毁。却说曹仁收拾残军,就新野屯住,使曹洪去见曹操,具言失利之事。操大怒曰:“诸葛村夫,安敢如此;”催动三军,漫山塞野,尽至新野下寨。传令军士一面搜山,一面填塞白河。令大军分作八路,一齐去取樊城。刘晔曰:“丞相初至襄阳,必须先买民心,今刘备尽迁新野百姓入樊城,若我兵径进,二县为齑粉矣;不如先使人招降刘备。备即不降,亦可见我爱民之心;若其来降,则荆州之地,可不战而定也。”操从其言,便问:“谁可为使?”刘晔曰:“徐庶与刘备至厚,今现在军中,何不命他一往?”操曰:“他去恐不复来。”晔曰:“他若不来,贻笑于人矣。丞相勿疑。”操乃召徐庶至,谓曰:“我本欲踏平樊城,奈怜众百姓之命。公可往说刘备:如肯来降,免罪赐爵;若更执迷,军民共戮,玉石俱焚。吾知公忠义,故特使公往。愿勿相负。” 徐庶受命而行。至樊城,玄德、孔明接见,共诉旧日之情。庶曰:“曹操使庶来招降使君,乃假买民心也,今彼分兵八路,填白河而进。樊城恐不可守,宜速作行计。”玄德欲留徐庶。庶谢曰:“某若不还,恐惹人笑。今老母已丧,抱恨终天。身虽在彼,誓不为设一谋,公有卧龙辅佐,何愁大业不成。庶请辞。”玄德不敢强留。 徐庶辞回,见了曹操,言玄德并无降意。操大怒,即日进兵。玄德问计于孔明。孔明曰:“可速弃樊城,取襄阳暂歇。”玄德曰:“奈百姓相随许久,安忍弃之?”孔明曰:“可令人遍告百姓:有愿随者同去,不愿者留下。”先使云长往江岸整顿船只,令孙乾、简雍在城中声扬曰:“今曹兵将至,孤城不可久守,百姓愿随者,便同过江。”两县之民,齐声大呼曰:“我等虽死,亦愿随使君!”即日号泣而行。扶老携幼,将男带女,滚滚渡河,两岸哭声不绝。玄德于船上望见,大恸曰:“为吾一人而使百姓遭此大难,吾何生哉!”欲投江而死,左右急救止。闻者莫不痛哭。船到南岸,回顾百姓,有未渡者,望南而哭。玄德急令云长催船渡之,方才上马。 @@ -773,7 +773,7 @@ 四十二年真命主,将军因得显神威。”张郃见了,大惊而退。赵云纵马正走,背后忽有二将大叫:“赵云休走!”前面又有二将,使两般军器,截住去路:后面赶的是马延、张顗,前面阻的是焦触、张南,都是袁绍手下降将。赵云力战四将,曹军一齐拥至。云乃拔青釭剑乱砍,手起处,衣甲平过,血如涌泉。杀退众军将,直透重围。却说曹操在景山顶上,望见一将,所到之处,威不可当,急问左右是谁。曹洪飞马下山大叫曰:“军中战将可留姓名!”云应声曰:“吾乃常山赵子龙也!”曹洪回报曹操。操曰:“真虎将也!吾当生致之。”遂令飞马传报各处:“如赵云到,不许放冷箭,只要捉活的。”因此赵云得脱此难;此亦阿斗之福所致也。这一场杀:赵云怀抱后主,直透重围,砍倒大旗两面,夺槊三条;前后枪刺剑砍,杀死曹营名将五十余员。后人有诗曰:“血染征袍透甲红,当阳谁敢与争锋!古来冲阵扶危主,只有常山赵子龙。” 赵云当下杀透重围,已离大阵,血满征袍。正行间,山坡下又撞出两枝军,乃夏侯惇部将钟缙、钟绅兄弟二人,一个使大斧,一个使画戟,大喝:“赵云快下马受缚!”正是:“才离虎窟愈生去,又遇龙潭鼓浪来。毕竟子龙怎地脱身,且听下回分解。 (本章完) -第42章 张翼德大闹长坂桥 刘豫州败走汉津口 +第42章 张翼德大闹长坂桥 刘豫州败走汉津口   却说钟缙、钟绅二人拦住赵云厮杀。赵云挺枪便刺,钟缙当先挥大斧来迎。两马相交,战不三合。被云一枪刺落马下,夺路便走。背后钟绅持戟赶来,马尾相衔,那枝戟只在赵云后心内弄影。云急拨转马头,恰好两胸相拍。云左手持枪隔过画戟,右手拔出青釭宝剑砍去,带盔连脑,砍去一半,绅落马而死,余众奔散。赵云得脱,望长坂桥而走,只闻后面喊声大震,原来文聘引军赶来。赵云到得桥边,人困马乏。见张飞挺矛立马于桥上,云大呼曰:“翼德援我!”飞曰:“子龙速行,追兵我自当之。” 云纵马过桥,行二十余里,见玄德与众人憩于树下。云下马伏地而泣。玄德亦泣。云喘息而言曰:“赵云之罪,万死犹轻!糜夫人身带重伤,不肯上马,投井而死,云只得推土墙掩之。怀抱公子,身突重围;赖主公洪福,幸而得脱。适来公子尚在怀中啼哭,此一会不见动静,多是不能保也。”遂解视之,原来阿斗正睡着未醒。云喜曰:“幸得公子无恙!”双手递与玄德。玄德接过,掷之于地曰:“为汝这孺子,几损我一员大将!”赵云忙向地下抱起阿斗,泣拜曰:“云虽肝脑涂地,不能报也!”后人有诗曰:“曹操军中飞虎出,赵云怀内小龙眠。无由抚慰忠臣意,故把亲儿掷马前。” 却说文聘引军追赵云至长坂桥,只见张飞倒竖虎须,圆睁环眼,手绰蛇矛,立马桥上,又见桥东树林之后,尘头大起,疑有伏后,便勒住马,不敢近前。俄而曹仁、李典、夏侯惇、夏侯渊、乐进、张辽、张郃、许褚等都至。见飞怒目横矛,立马于桥上,又恐是诸葛孔明之计,都不敢近前。扎住阵脚,一字儿摆在桥西,使人飞报曹操。操闻知,急上马,从阵后来。张飞睁圆环眼,隐隐见后军青罗伞盖、旄钺旌旗来到,料得是曹操心疑,亲自来看。飞乃厉声大喝曰:“我乃燕人张翼德也!谁敢与我决一死战?”声如巨雷。曹军闻之,尽皆股栗。 @@ -788,7 +788,7 @@ 肃见孔明礼毕,问曰:“向慕先生才德,未得拜晤;今幸相遇,愿闻目今安危之事。”孔明曰:“曹操奸计,亮已尽知;但恨力未及,故且避之。”肃曰:“皇叔今将止于此乎?”孔明曰:“使君与苍梧太守吴臣有旧,将往投之。”肃曰:“吴臣粮少兵微,自不能保,焉能容人?”孔明曰:“吴臣处虽不足久居,今且暂依之,别有良图。”肃曰:“孙将军虎踞六郡,兵精粮足,又极敬贤礼士,江表英雄,多归附之。今为君计。莫若遣心腹往结东吴,以共图大事。”孔明曰:“刘使君与孙将军自来无旧,恐虚费词说。且别无心腹之人可使。”肃曰:“先生之兄,现为江东参谋,日望与先生相见。肃不才,愿与公同见孙将军,共议大事。”玄德曰:“孔明是吾之师,顷刻不可相离,安可去也?”肃坚请孔明同去。玄德佯不许。孔明曰:“事急矣,请奉命一行。玄德方才许诺。鲁肃遂别了玄德、刘琦,与孔明登舟,望柴桑郡来。正是:只因诸葛扁舟去,致使曹兵一旦休。 不知孔明此去毕竟如何,且看下文分解。 (本章完) -第43章 诸葛亮舌战群儒 鲁子敬力排众议 +第43章 诸葛亮舌战群儒 鲁子敬力排众议   却说鲁肃、孔明辞了玄德、刘琦,登舟望柴桑郡来。二人在舟中共议、鲁肃谓孔明曰:“先生见孙将军,切不可实言曹操兵多将广。”孔明曰:“不须子敬叮咛,亮自有对答之语。”及船到岸,肃请孔明于馆驿中暂歇,先自往见孙权。权正聚文武于堂上议事,闻鲁肃回,急召入问曰:“子敬往江夏,体探虚实若何?”肃曰:“已知其略,尚容徐禀。”权将曹操檄文示肃曰:“操昨遣使赍文至此,孤先发遣来使,现今会众商议未定。”肃接檄文观看。其略曰:“孤近承帝命,奉词伐罪。旄麾南指,刘琮束手;荆襄之民,望风归顺。今统雄兵百万,上将千员,欲与将军会猎于江夏,共伐刘备,同分土地,永结盟好。幸勿观望,速赐回音。”鲁肃看毕曰:“主公尊意若何?”权曰:“未有定论。”张昭曰:“曹操拥百万之众,借天子之名,以征四方,拒之不顺。且主公大势可以拒操者,长江也。今操既得荆州,长江之险,已与我共之矣,势不可敌。以愚之计,不如纳降,为万安之策。众谋士皆曰:“子布之言,正合天意。”孙权沉吟不语。张昭又曰:“主公不必多疑。如降操,则东吴民安,江南六郡可保矣。”孙权低头不语。 须臾,权起更衣,鲁肃随于权后。权知肃意,乃执肃手而言曰:“卿欲如何?”肃曰:“恰才众人所言,深误将军。众人皆可降曹操,惟将军不可降曹操。”权曰:“何以言之?”肃曰:“如肃等降操,当以肃还乡党,累官故不失州郡也;将军降操,欲安所归乎?位不过封侯,车不过一乘,骑不过一匹,从不过数人,岂得南面称孤哉!众人之意,各自为己,不可听也。将军宜早定大计。”权叹曰:“诸人议论,大失孤望。子敬开说大计,正与吾见相同。此天以子敬赐我也!但操新得袁绍之众,近又得荆州之兵,恐势大难以抵敌。”肃曰:“肃至江夏,引诸葛瑾之弟诸葛亮在此,主公可问之,便知虚实。”权曰:“卧龙先生在此乎?”肃曰:“现在馆驿中安歇。”权曰:“今日天晚,且未相见。来日聚文武于帐下,先教见我江东英俊,然后升堂议事。”肃领命而去。次日至馆驿中见孔明,又嘱曰:“今见我主,切不可言曹操兵多。”孔明笑曰:“亮自见机而变,决不有误。”肃乃引孔明至幕下。早见张昭、顾雍等一班文武二十余人,峨冠博带,整衣端坐。孔明逐一相见,各问姓名。施礼已毕,坐于客位。张昭等见孔明丰神飘洒,器宇轩昂,料道此人必来游说。张昭先以言挑之曰:“昭乃江东微末之士,久闻先生高卧隆中,自比管;乐。此语果有之乎?”孔明曰:“此亮平生小可之比也。”昭曰:“近闻刘豫州三顾先生于草庐之中,幸得先生,以为如鱼得水,思欲席卷荆襄。今一旦以属曹操,未审是何主见?”孔明自思张昭乃孙权手下第一个谋士,若不先难倒他,如何说得孙权,遂答曰:“吾观取汉上之地,易如反掌。我主刘豫州躬行仁义,不忍夺同宗之基业,故力辞之。刘琮孺子,听信佞言,暗自投降,致使曹操得以猖獗。今我主屯兵江夏,别有良图,非等闲可知也。”昭曰:“若此,是先生言行相违也。 先生自比管、乐,管仲相桓公,霸诸侯,一国天下;乐毅扶持微弱之燕,下齐七十余城:此二人者,真济世之才也。先生在草庐之中,但笑傲风月,抱膝危坐。今既从事刘豫州,当为生灵兴利除害,剿灭乱贼。且刘豫州未得先生之前,尚且纵横寰宇,割据城池;今得先生,人皆仰望。虽三尺童蒙,亦谓彪虎生翼,将见汉室复兴,曹氏即灭矣。朝廷旧臣,山林隐士,无不拭目而待:以为拂高天之云翳,仰日月之光辉,拯民于水火之中,措天下于衽席之上,在此时也。何先生自归豫州,曹兵一出,弃甲抛戈,望风而窜;上不能报刘表以安庶民,下不能辅孤子而据疆土;乃弃新野,走樊城,败当阳,奔夏口,无容身之地:是豫州既得先生之后,反不如其初也。 @@ -805,7 +805,7 @@ 主公自思比袁绍若何?曹操向日兵微将寡,尚能一鼓克袁绍;何况今日拥百万之众南征,岂可轻敌?若听诸葛亮之言,妄动甲兵,此所谓负薪救火也。”孙权只低头不语。顾雍曰:“刘备因为曹操所败,故欲借我江东之兵以拒之,主公奈何为其所用乎;愿听子布之言。”孙权沉吟未决。张昭等出,鲁肃入见曰:“适张子布等,又劝主公休动兵,力主降议,此皆全躯保妻子之臣,为自谋之计耳。原主公勿听也。”孙权尚在沉吟。肃曰:“主公若迟疑,必为众人误矣。”权曰:“卿且暂退,容我三思。”肃乃退出。时武将或有要战的,文官都是要降的,议论纷纷不一。且说孙权退入内宅,寝食不安,犹豫不决。吴国太见权如此,问曰:“何事在心,寝食俱废?”权曰:“今曹操屯兵于江汉,有下江南之意。问诸文武,或欲降者,或欲战者。欲待战来,恐寡不敌众;欲待降来,又恐曹操不容:因此犹豫不决。”吴国太曰:“汝何不记吾姐临终之语乎?”孙权如醉方醒,似梦初觉,想出这句话来。正是:追思国母临终语,引得周郎立战功。 毕竟说着甚的,且看下文分解。 (本章完) -第44章 孔明用智激周瑜 孙权决计破曹操 +第44章 孔明用智激周瑜 孙权决计破曹操   却说吴国太见孙权疑惑不决,乃谓之曰:“先姊遗言云:‘伯符临终有言:内事不决问张昭,外事不决问周瑜。’今何不请公瑾问之?”权大喜,即遣使往鄱阳请周瑜议事。原来周瑜在鄱阳湖训练水师,闻曹操大军至汉上,便星夜回柴桑郡议军机事。使者未发,周瑜已先到。鲁肃与瑜最厚,先来接着,将前项事细述一番。周瑜曰:“子敬休忧,瑜自有主张。今可速请孔明来相见。”鲁肃上马去了。 周瑜方才歇息,忽报张昭、顾雍、张纮、步骘四人来相探。瑜接入堂中坐定,叙寒温毕。张昭曰:“都督知江东之利害否?”瑜曰:“未知也。”昭曰:“曹操拥众百万,屯于汉上,昨传檄文至此,欲请主公会猎于江夏。虽有相吞之意,尚未露其形。昭等劝主公且降之,庶免江东之祸。不想鲁子敬从江夏带刘备军师诸葛亮至此,彼因自欲雪愤,特下说词以激主公。子敬却执迷不悟。正欲待都督一决。”瑜曰:“公等之见皆同否?”顾雍等曰:“所议皆同。”瑜曰:“吾亦欲降久矣。公等请回,明早见主公,自有定议。”昭等辞去。 少顷,又报程普、黄盖、韩当等一班战将来见。瑜迎入,各问慰讫。程普曰:“都督知江东早晚属他人否?”瑜曰:“未知也。”普曰:“吾等自随孙将军开基创业,大小数百战,方才战得六郡城池。今主公听谋士之言,欲降曹操,此真可耻可惜之事!吾等宁死不辱。望都督劝主公决计兴兵,吾等愿效死战。”瑜曰:“将军等所见皆同否?”黄盖忿然而起,以手拍额曰:“吾头可断,誓不降曹!”众人皆曰:“吾等都不愿降!”瑜曰:“吾正欲与曹操决战,安肯投降!将军等请回。瑜见主公,自有定议。”程普等别去。 @@ -819,7 +819,7 @@ 次日,瑜请诸葛瑾,谓曰:“令弟孔明有王佐之才,如何屈身事刘备?今幸至江东,欲烦先生不惜齿牙余论,使令弟弃刘备而事东吴,则主公既得良辅,而先生兄弟又得相见,岂不美哉?先生幸即一行。”瑾曰:“瑾自至江东,愧无寸功。今都督有命,敢不效力。”即时上马,径投驿亭来见孔明。孔明接入,哭拜,各诉阔情。瑾泣曰:“弟知伯夷、叔齐乎?”孔明暗思:“此必周郎教来说我也。”遂答曰:“夷、齐古之圣贤也。”瑾曰:“夷、齐虽至饿死首阳山下,兄弟二人亦在一处。我今与你同胞共乳,乃各事其主,不能旦暮相聚。视夷、齐之为人,能无愧乎?”孔明曰:“兄所言者,情也;弟所守者,义也。弟与兄皆汉人。今刘皇叔乃汉室之胄,兄若能去东吴,而与弟同事刘皇叔,则上不愧为汉臣,而骨肉又得相聚,此情义两全之策也。不识兄意以为何如?”瑾思曰:“我来说他,反被他说了我也。”遂无言回答,起身辞去。回见周瑜,细述孔明之言。瑜曰:“公意若何?”瑾曰:“吾受孙将军厚恩,安肯相背!”瑜曰:“公既忠心事主,不必多言。吾自有伏孔明之计。”正是:智与智逢宜必合,才和才角又难容。 毕竟周瑜定何计伏孔明,且看下回分解。 (本章完) -第45章 三江口曹操折兵 群英会蒋干中计 +第45章 三江口曹操折兵 群英会蒋干中计   却说周瑜闻诸葛瑾之言,转恨孔明,存心欲谋杀之。次日,点齐军将,入辞孙权。权曰:“卿先行,孤即起兵继后。”瑜辞出,与程普、鲁肃领兵起行,便邀孔明同住。孔明欣然从之。一同登舟,驾起帆樯,迤逦望夏口而进。离三江口五六十里,船依次第歇定。周瑜在中央下寨,岸上依西山结营,周围屯住。孔明只在一叶小舟内安身。 周瑜分拨已定,使人请孔明议事。孔明至中军帐,叙礼毕,瑜曰:“昔曹操兵少,袁绍兵多,而操反胜绍者,因用许攸之谋,先断乌巢之粮也。今操兵八十三万,我兵只五六万,安能拒之?亦必须先断操之粮,然后可破。我已探知操军粮草,俱屯于聚铁山。先生久居汉上,熟知地理。敢烦先生与关、张、子龙辈——吾亦助兵千人——星夜往聚铁山断操粮道。彼此各为主人之事,幸勿推调。”孔明暗思:“此因说我不动,设计害我。我若推调,必为所笑。不如应之,别有计议。”乃欣然领诺。瑜大喜。孔明辞出。鲁肃密谓瑜曰:“公使孔明劫粮,是何意见?”瑜曰:“吾欲杀孔明,恐惹人笑,故借曹操之手杀之,以绝后患耳。”肃闻言,乃往见孔明,看他知也不知。只见孔明略无难色,整点军马要行。肃不忍,以言挑之曰:“先生此去可成功否?”孔明笑曰:“吾水战、步战、马战、车战,各尽其妙,何愁功绩不成,非比江东公与周郎辈止一能也。”肃曰:“吾与公瑾何谓一能?”孔明曰:“吾闻江南小儿谣言云:‘伏路把关饶子敬,临江水战有周郎。’公等于陆地但能伏路把关;周公瑾但堪水战,不能陆战耳。” 肃乃以此言告知周瑜。瑜怒曰:“何欺我不能陆战耶!不用他去!我自引一万马军,往聚铁山断操粮道:”肃又将此言告孔明。孔明笑曰:“公瑾令吾断粮者,实欲使曹操杀吾耳。吾故以片言戏之,公瑾便容纳不下。目今用人之际,只愿吴侯与刘使君同心,则功可成;如各相谋害,大事休矣。操贼多谋,他平生惯断人粮道,今如何不以重兵提备?公瑾若去,必为所擒。今只当先决水战,挫动北军锐气,别寻妙计破之。望子敬善言以告公瑾为幸。”鲁肃遂连夜回见周瑜,备述孔明之言。瑜摇首顿足曰:“此人见识胜吾十倍,今不除之,后必为我国之祸!”肃曰:“今用人之际,望以国家为重。且待破曹之后,图之未晚。”瑜然其说。 @@ -841,7 +841,7 @@ 操于众将内选毛玠、于禁为水军都督,以代蔡、张二人之职。细作探知,报过江东。周瑜大喜曰:“吾所患者,此二人耳。今既剿除,吾无忧矣。”肃曰:“都督用兵如此,何愁曹贼不破乎!”瑜曰:“吾料诸将不知此计,独有诸葛亮识见胜我,想此谋亦不能瞒也。子敬试以言挑之,看他知也不知,便当回报。”正是:还将反间成功事,去试从旁冷眼人。 未知肃去问孔明还是如何,且看下文分解。 (本章完) -第46章 用奇谋孔明借箭 献密计黄盖受刑 +第46章 用奇谋孔明借箭 献密计黄盖受刑   却说鲁肃领了周瑜言语,径来舟中相探孔明。孔明接入小舟对坐。肃曰:“连日措办军务,有失听教。”孔明曰:“便是亮亦未与都督贺喜。”肃曰:“何喜?”孔明曰:“公瑾使先生来探亮知也不知,便是这件事可贺喜耳。”谈得鲁肃失色问曰:“先生何由知之?”孔明曰:“这条计只好弄蒋干。曹操、虽被一时瞒过,必然便省悟,只是不肯认错耳。今蔡、张两人既死,江东无患矣,如何不贺喜!吾闻曹操换毛玠、于禁为水军都督,则这两个手里,好歹送了水军性命。”鲁肃听了,开口不得,把些言语支吾了半晌,别孔明而回。孔明嘱曰:“望子敬在公瑾面前勿言亮先知此事。恐公瑾心怀妒忌,又要寻事害亮。”鲁肃应诺而去,回见周瑜,把上项事只得实说了。瑜大惊曰:“此人决不可留!吾决意斩之!”肃劝曰:“若杀孔明,却被曹操笑也。”瑜曰:“吾自有公道斩之,教他死而无怨。”肃曰:“何以公道斩之?”瑜曰:“子敬休问,来日便见。”次日,聚众将于帐下,教请孔明议事。孔明欣然而至。 坐定,瑜问孔明曰:“即日将与曹军交战,水路交兵,当以何兵器为先?”孔明曰:“大江之上,以弓箭为先。”瑜曰:“先生之言,甚合愚意。但今军中正缺箭用,敢烦先生监造十万枝箭,以为应敌之具。此系公事,先生幸勿推却。”孔明曰:“都督见委,自当效劳。敢问十万枝箭,何时要用?”瑜曰:“十日之内,可完办否?”孔明曰:“操军即日将至,若候十日,必误大事。”瑜曰:“先生料几日可完办?”孔明曰:“只消三日,便可拜纳十万枝箭。”瑜曰:“军中无戏言。”孔明曰:“怎敢戏都督!愿纳军令状:三日不办,甘当重罚。”瑜大喜,唤军政司当面取了文书,置酒相待曰:“待军事毕后,自有酬劳。”孔明曰:“今日已不及,来日造起。至第三日,可差五百小军到江边搬箭。”饮了数杯,辞去。鲁肃曰:“此人莫非诈乎?”瑜曰:“他自送死,非我逼他。今明白对众要了文书,他便两胁生翅,也飞不去。我只分付军匠人等,教他故意迟延,凡应用物件,都不与齐备。如此,必然误了日期。那时定罪,有何理说?公今可去探他虚实,却来回报。 肃领命来见孔明。孔明曰:“吾曾告子敬,休对公瑾说,他必要害我。不想子敬不肯为我隐讳,今日果然又弄出事来。三日内如何造得十万箭?子敬只得救我!”肃曰:“公自取其祸,我如何救得你?”孔明曰:“望子敬借我二十只船,每船要军士三十人,船上皆用青布为幔,各束草千余个,分布两边。吾别有妙用。第三日包管有十万枝箭。只不可又教公瑾得知,若彼知之,吾计败矣。”肃允诺,却不解其意,回报周瑜,果然不提起借船之事,只言:“孔明并不用箭竹、翎毛、胶漆等物,自有道理。”瑜大疑曰:“且看他三日后如何回覆我!”却说鲁肃私自拨轻快船二十只,各船三十余人,并布幔束草等物,尽皆齐备,候孔明调用。第一日却不见孔明动静;第二日亦只不动。至第三日四更时分,孔明密请鲁肃到船中。肃问曰:“公召我来何意?”孔明曰:“特请子敬同往取箭。”肃曰:“何处去取?”孔明曰:“子敬休问,前去便见。”遂命将二十只船,用长索相连,径望北岸进发。是夜大雾漫天,长江之中,雾气更甚,对面不相见。 @@ -858,7 +858,7 @@ 且说黄盖卧于帐中,诸将皆来动问。盖不言语,但长吁而已。忽报参谋阚泽来问。盖令请入卧内,叱退左右。阚泽曰:“将军莫非与都督有仇?”盖曰:“非也。”泽曰:“然则公之受责,莫非苦肉计乎?”盖曰:“何以知之?”泽曰:“某观公瑾举动,已料着八九分。”盖曰:“某受吴侯三世厚恩,无以为报,故献此计,以破曹操。吾虽受苦,亦无所恨。吾遍观军中,无一人可为心腹者。惟公素有忠义之心,敢以心腹相告。”泽曰:“公之告我,无非要我献诈降书耳。”盖曰:“实有此意。未知肯否?”阚泽欣然领诺。正是:勇将轻身思报主,谋臣为国有同心。 未知阚泽所言若何,且看下文分解。 (本章完) -第47章 阚泽密献诈降书 庞统巧授连环计 +第47章 阚泽密献诈降书 庞统巧授连环计   却说阚泽字德润,会稽山阴人也;家贫好学,与人佣工,尝借人书来看,看过一遍,更不遗忘;口才辨给,少有胆气。孙权召为参谋,与黄盖最相善。盖知其能言有胆,故欲使献诈降书。泽欣然应诺曰:“大丈夫处世,不能立功建业,不几与草木同腐乎!公既捐躯报主,泽又何惜微生!”黄盖滚下床来,拜而谢之。泽曰:“事不可缓,即今便行。”盖曰:“书已修下了。”泽领了书,只就当夜扮作渔翁,驾小舟,望北岸而行。 是夜寒星满天。三更时候,早到曹军水寨。巡江军士拿住,连夜报知曹操。操曰:“莫非是奸细么?”军士曰:“只一渔翁,自称是东吴参谋阚泽,有机密事来见。”操便教引将入来。军士引阚泽至,只见帐上灯烛辉煌,曹操凭几危坐,问曰:“汝既是东吴参谋,来此何干?”泽曰:“人言曹丞相求贤若渴,今观此问,甚不相合。黄公覆,汝又错寻思了也!”操曰:“吾与东吴旦夕交兵,汝私行到此,如何不问?”泽曰:“黄公覆乃东吴三世旧臣,今被周瑜于众将之前,无端毒打,不胜忿恨。因欲投降丞相,为报仇之计,特谋之于我。我与公覆,情同骨肉,径来为献密书。未知丞相肯容纳否?”操曰:“书在何处?”阚泽取书呈上。 操拆书,就灯下观看。书略曰:“盖受孙氏厚恩,本不当怀二心。然以今日事势论之:用江东六郡之卒,当中国百万之师,众寡不敌,海内所共见也。东吴将吏,无有智愚,皆知其不可。周瑜小子,偏怀浅戆,自负其能,辄欲以卵敌石;兼之擅作威福,无罪受刑,有功不赏。盖系旧臣,无端为所摧辱,心实恨之!伏闻丞相诚心待物,虚怀纳士,盖愿率众归降,以图建功雪耻。粮草军仗,随船献纳。泣血拜白,万勿见疑。”曹操于几案上翻覆将书看了十余次,忽然拍案张目大怒曰:“黄盖用苦肉计,令汝下诈降书,就中取事,却敢来戏侮我耶!”便教左右推出斩之。左右将阚泽簇下。泽面不改容,仰天大笑。操教牵回,叱曰:“吾已识破奸计,汝何故哂笑?”泽曰:“吾不笑你。吾笑黄公覆不识人耳。”操曰:“何不识人?”泽曰:“杀便杀,何必多问!”操曰:“吾自幼熟读兵书,深知奸伪之道。 @@ -874,7 +874,7 @@ 莫道东南能制胜,谁云西北独无人? 毕竟此人是谁,且看下文分解。 (本章完) -第48章 宴长江曹操赋诗 锁战船北军用武 +第48章 宴长江曹操赋诗 锁战船北军用武   却说庞统闻言,吃了一惊,急回视其人,原来却是徐庶。统见是故人,心下方定。回顾左右无人,乃曰:“你若说破我计,可惜江南八十一州百姓,皆是你送了也!”庶笑曰:“此间八十三万人马,性命如何?”统曰:“元直真欲破我计耶?”庶曰:“吾感刘皇叔厚恩,未尝忘报。曹操送死吾母,吾已说过终身不设一谋,今安肯破兄良策?只是我亦随军在此,兵败之后,玉石不分,岂能免难?君当教我脱身之术,我即缄口远避矣。”统笑曰:“元直如此高见远识,谅此有何难哉!”庶曰:“愿先生赐教。”统去徐庶耳边略说数句。庶大喜,拜谢。庞统别却徐庶,下船自回江东。 且说徐庶当晚密使近人去各寨中暗布谣言。次日,寨中三三五五,交头接耳而说。早有探事人报知曹操,说:“军中传言西凉州韩遂、马腾谋反,杀奔许都来。”操大惊,急聚众谋士商议曰:“吾引兵南征,心中所忧者,韩遂、马腾耳。军中谣言,虽未辨虚实,然不可不防。”言未毕,徐庶进曰:“庶蒙丞相收录,恨无寸功报效。请得三千人马,星夜往散关把住隘口;如有紧急,再行告报。”操喜曰:“若得元直去,吾无忧矣!散关之上,亦有军兵,公统领之。目下拨三千马步军,命臧霸为先锋,星夜前去,不可稽迟。”徐庶辞了曹操,与臧霸便行。此便是庞统救徐庶之计。后人有诗曰:“曹操征南日日忧,马腾韩遂起戈矛。凤雏一语教徐庶,正似游鱼脱钓钩。”曹操自遣徐庶去后,心中稍安,遂上马先看沿江旱寨,次看水寨。乘大船一只于中央,上建帅字旗号,两傍皆列水寨,船上埋伏弓弩千张。操居于上。 时建安十三年冬十一月十五日,天气晴明,平风静浪。操令:“置酒设乐于大船之上,吾今夕欲会诸将。”天色向晚,东山月上,皎皎如同白日。长江一带,如横素练。操坐大船之上,左右侍御者数百人,皆锦衣绣袄,荷戈执戟。文武众官,各依次而坐。操见南屏山色如画,东视柴桑之境,西观夏口之江,南望樊山,北觑乌林,四顾空阔,心中欢喜,谓众官曰:“吾自起义兵以来,与国家除凶去害,誓愿扫清四海,削平天下;所未得者江南也。今吾有百万雄师,更赖诸公用命,何患不成功耶!收服江南之后,天下无事,与诸公共享富贵,以乐太平。”文武皆起谢曰:“愿得早奏凯歌!我等终身皆赖丞相福荫。”操大喜,命左右行酒。饮至半夜,操酒酣,遥指南岸曰:“周瑜、鲁肃,不识天时!今幸有投降之人,为彼心腹之患,此天助吾也。”荀攸曰:“丞相勿言,恐有泄漏。”操大笑曰:“座上诸公,与近侍左右,皆吾心腹之人也,言之何碍!”又指夏口曰:“刘备、诸葛亮,汝不料蝼蚁之力,欲撼泰山,何其愚耶!”顾谓诸将曰:“吾今年五十四岁矣,如得江南,窃有所喜。昔日乔公与吾至契,吾知其二女皆有国色。后不料为孙策、周瑜所娶。吾今新构铜雀台于漳水之上,如得江南,当娶二乔,置之台上,以娱暮年,吾愿足矣!”言罢大笑。唐人杜牧之有诗曰:“折戟沉沙铁未消,自将磨洗认前朝。东风不与周郎便,铜雀春深锁二乔。”曹操正笑谈间,忽闻鸦声望南飞鸣而去。操问曰;“此鸦缘何夜鸣?”左右答曰:“鸦见月明,疑是天晓,故离树而鸣也。”操又大笑。时操已醉,乃取槊立于船头上,以酒奠于江中,满饮三爵,横槊谓诸将曰:“我持此槊,破黄巾、擒吕布、灭袁术、收袁绍,深入塞北,直抵辽东,纵横天下:颇不负大丈夫之志也。今对此景,甚有慷慨。吾当作歌,汝等和之。”歌曰:“对酒当歌,人生几何:譬如朝露,去日苦多。 @@ -886,7 +886,7 @@ 周泰一臂挽牌,一手提刀,两船相离七八尺,泰即飞身一跃,直跃过张南船上,手起刀落,砍张南于水中,乱杀驾舟军士。众船飞棹急回。韩当、周泰催船追赶,到半江中,恰与文聘船相迎。两边便摆定船厮杀。却说周瑜引众将立于山顶,遥望江北水面艨艟战船,排合江上,旗帜号带,皆有次序。回看文聘与韩当、周泰相持,韩当、周泰奋力攻击,文聘抵敌不住,回船而走,韩、周二人,急催船追赶。周瑜恐二人深入重地,便将白旗招飐,令众鸣金。二人乃挥棹而回。周瑜于山顶看隔江战船,尽入水寨。瑜顾谓众将曰:“江北战船如芦苇之密,操又多谋,当用何计以破之?”众未及对,忽见曹军寨中,被风吹折中央黄旗,飘入江中。瑜大笑曰:“此不祥之兆也!”正观之际,忽狂风大作,江中波涛拍岸。一阵风过,刮起旗角于周瑜脸上拂过。瑜猛然想起一事在心,大叫一声,往后便倒,口吐鲜血。诸将急救起时,却早不省人事。正是:一时忽笑又忽叫,难使南军破北军。 毕竟周瑜性命如何,且看下文分解。 (本章完) -第49章 七星坛诸葛祭风 三江口周瑜纵火 +第49章 七星坛诸葛祭风 三江口周瑜纵火   却说周瑜立于山顶,观望良久,忽然望后而倒,口吐鲜血,不省人事。左右救回帐中。诸将皆来动问,尽皆愕然相顾曰:“江北百万之众,虎踞鲸吞。不争都督如此,倘曹兵一至,如之奈何?”慌忙差人申报吴侯,一面求医调治。 却说鲁肃见周瑜卧病,心中忧闷,来见孔明,言周瑜卒病之事。孔明曰:“公以为何如?”肃曰:“此乃曹操之福,江东之祸也。”孔明笑曰:“公瑾之病,亮亦能医。”肃曰:“诚如此,则国家万幸!”即请孔明同去看病。肃先入见周瑜。瑜以被蒙头而卧。肃曰:“都督病势若何?”周瑜曰:“心腹搅痛,时复昏迷。”肃曰:“曾服何药饵?”瑜曰:“心中呕逆,药不能下。”肃曰:“适来去望孔明,言能医都督之病。现在帐外,烦来医治,何如?”瑜命请入,教左右扶起,坐于床上。孔明曰:“连日不晤君颜,何期贵体不安!”瑜曰:“人有旦夕祸福,岂能自保?”孔明笑曰:“天有不测风云,人又岂能料乎?”瑜闻失色,乃作呻吟之声。孔明曰:“都督心中似觉烦积否?”瑜曰:“然,”孔明曰:“必须用凉药以解之。”瑜曰:“已服凉药,全然无效。”孔明曰:“须先理其气;气若顺,则呼吸之间,自然痊可。”瑜料孔明必知其意,乃以言挑之曰:“欲得顺气,当服何药?”孔明笑曰:“亮有一方,便教都督气顺。”瑜曰:“愿先生赐教。”孔明索纸笔,屏退左右,密书十六字曰:“欲破曹公,宜用火攻;万事俱备,只欠东风。”写毕,递与周瑜曰:“此都督病源也。”瑜见了大惊,暗思:“孔明真神人也!早已知我心事!只索以实情告之。”乃笑曰:“先生已知我病源,将用何药治之?事在危急,望即赐教。”孔明曰:“亮虽不才,曾遇异人,传授奇门遁甲天书,可以呼风唤雨。都督若要东南风时,可于南屏山建一台,名曰七星坛:高九尺,作三层,用一百二十人,手执旗幡围绕。亮于台上作法,借三日三夜东南大风,助都督用兵,何如?”瑜曰:“休道三日三夜,只一夜大风,大事可成矣。只是事在目前,不可迟缓。”孔明曰:“十一月二十日甲子祭风,至二十二日丙寅风息,如何?”瑜闻言大喜,矍然而起。便传令差五百精壮军士,往南屏山筑坛;拨一百二十人,执旗守坛,听候使令。 孔明辞别出帐,与鲁肃上马,来南屏山相度地势,令军士取东南方赤土筑坛。方圆二十四丈,每一层高三尺,共是九尺。下一层插二十八宿旗:东方七面青旗,按角、亢、氏、房、心、尾、箕,布苍龙之形;北方七面皂旗,按斗、牛、女、虚、危、室、壁,作玄武之势;西方七面白旗,按奎、娄、胃、昴、毕、觜、参,踞白虎之威;南方七面红旗,按井、鬼、柳、星、张、翼、轸,成朱雀之状。第二层周围黄旗六十四面,按六十四卦,分八位而立。上一层用四人,各人戴束发冠,穿皂罗袍,凤衣博带,朱履方裾。前左立一人,手执长竿,竿尖上用鸡羽为葆。以招风信;前右立一人,手执长竿,竿上系七星号带,以表风色;后左立一人,捧宝剑;后右立一人,捧香炉。坛下二十四人,各持旌旗、宝盖、大戟、长戈、黄钺、白旄、朱幡、皂纛,环绕四面。 @@ -904,7 +904,7 @@ 火厄盛时遭水厄,棒疮愈后患金疮。 未知黄盖性命如何,且看下文分解。 (本章完) -第50章 诸葛亮智算华容 关云长义释曹操 +第50章 诸葛亮智算华容 关云长义释曹操   却说当夜张辽一箭射黄盖下水,救得曹操登岸,寻着马匹走时,军已大乱。韩当冒烟突火来攻水寨,忽听得士卒报道:“后梢舵上一人,高叫将军表字。”韩当细听,但闻高叫“义公救我?”当曰:“此黄公覆也!”急教救起。见黄盖负箭着伤,咬出箭杆,箭头陷在肉内。韩当急为脱去湿衣,用刀剜出箭头,扯旗束之,脱自己战袍与黄盖穿了,先令别船送回大寨医治。原来黄盖深知水性,故大寒之时,和甲堕江,也逃得性命。却说当日满江火滚,喊声震地。左边是韩当、蒋钦两军从赤壁西边杀来;右边是周泰、陈武两军从赤壁东边杀来;正中是周瑜、程普、徐盛、丁奉大队船只都到。火须兵应,兵仗火威。此正是:三江水战,赤壁鏖兵。曹军着枪中箭、火焚水溺者,不计其数。后人有诗曰:“魏吴争斗决雌雄,赤壁楼船一扫空。烈火初张照云海,周郎曾此破曹公。”又有一绝云:“山高月小水茫茫,追叹前朝割据忙。南士无心迎魏武,东风有意便周郎。”不说江中鏖兵。 且说甘宁令蔡中引入曹寨深处,宁将蔡中一刀砍于马下,就草上放起火来。吕蒙遥望中军火起,也放十数处火,接应甘宁。潘璋、董袭分头放火呐喊,四下里鼓声大震。曹操与张辽引百余骑,在火林内走,看前面无一处不着。正走之间,毛玠救得文聘,引十数骑到。操令军寻路。张辽指道:“只有乌林地面,空阔可走。”操径奔乌林。正走间,背后一军赶到,大叫:“曹贼休走!”火光中现出吕蒙旗号。操催军马向前,留张辽断后,抵敌吕蒙。却见前面火把又起,从山谷中拥出一军,大叫:“凌统在此!”曹操肝胆皆裂。忽刺斜里一彪军到,大叫:“丞相休慌!徐晃在此!”彼此混战一场,夺路望北而走。忽见一队军马,屯在山坡前。徐晃出问,乃是袁绍手下降将马延、张顗,有三千北地军马,列寨在彼;当夜见满天火起,未敢转动,恰好接着曹操。操教二将引一千军马开路,其余留着护身。操得这枝生力军马,心中稍安。马延、张顗二将飞骑前行。不到十里,喊声起处,一彪军出。 为首一将,大呼曰:“吾乃东吴甘兴霸也!”马延正欲交锋,早被甘宁一刀斩于马下;张顗挺枪来迎,宁大喝一声,顗措手不及,被宁手起一刀,翻身落马。后军飞报曹操。操此时指望合淝有兵救应;不想孙权在合淝路口,望见江中火光,知是我军得胜,便教陆逊举火为号,太史慈见了,与陆逊合兵一处,冲杀将来。操只得望彝陵而走。路上撞见张郃,操令断后。纵马加鞭,走至五更,回望火光渐远,操心方定,问曰:“此是何处?”左右曰:“此是乌林之西,宜都之北。”操见树木丛杂,山川险峻,乃于马上仰面大笑不止。诸将问曰:“丞相何故大笑?”操曰:“吾不笑别人,单笑周瑜无谋,诸葛亮少智。若是吾用兵之时,预先在这里伏下一军,如之奈何?”说犹未了,两边鼓声震响,火光竟天而起,惊得曹操几乎坠马。刺斜里一彪军杀出,大叫:“我赵子龙奉军师将令,在此等候多时了!”操教徐晃、张郃双敌赵云,自己冒烟突火而去。子龙不来追赶,只顾抢夺旗帜。曹操得脱。 @@ -919,7 +919,7 @@ 却说关云长放了曹操,引军自回。此时诸路军马,皆得马匹、器械、钱粮,已回夏口;独云长不获一人一骑,空身回见玄德。孔明正与玄德作贺,忽报云长至。孔明忙离坐席,执杯相迎曰:“且喜将军立此盖世之功,与普天下除大害。合宜远接庆贺!”云长默然。孔明曰:“将军莫非因吾等不曾远接,故尔不乐?”回顾左右曰:“汝等缘何不先报?”云长曰:“关某特来请死。”孔明曰:“莫非曹操不曾投华容道上来?”云长曰:“是从那里来。关某无能,因此被他走脱。”孔明曰:“拿得甚将士来?”云长曰:“皆不曾拿。”孔明曰:“此是云长想曹操昔日之恩,故意放了。但既有军令状在此,不得不按军法。”遂叱武士推出斩之。正是:拚将一死酬知己,致令千秋仰义名。 未知云长性命如何,且看下文分解。 (本章完) -第51章 曹仁大战东吴兵 孔明一气周公瑾 +第51章 曹仁大战东吴兵 孔明一气周公瑾   却说孔明欲斩云长,玄德曰:“昔吾三人结义时,誓同生死。今云长虽犯法,不忍违却前盟。望权记过,容将功赎罪。”孔明方才饶了。且说周瑜收军点将,各各叙功,申报吴侯。所得降卒,尽行发付渡江,大犒三军,遂进兵攻取南郡。前队临江下寨,前后分五营。周瑜居中。瑜正与众商议征进之策,忽报:“刘玄德使孙乾来与都督作贺。”瑜命请入。乾施礼毕,言:“主公特命乾拜谢都督大德,有薄礼上献。”瑜问曰:“玄德在何处?”乾答曰:“现移兵屯油江口。”瑜惊曰:“孔明亦在油江否?”乾曰;“孔明与主公同在油江。”瑜曰:“足下先回,某亲来相谢也。”瑜收了礼物,发付孙乾先回。肃曰:“却才都督为何失惊?”瑜曰:“刘备屯兵油江,必有取南郡之意。我等费了许多军马,用了许多钱粮,目下南郡反手可得;彼等心怀不仁,要就现成,须放着周瑜不死!”肃曰:“当用何策退之?”瑜曰:“吾自去和他说话。 好便好;不好时,不等他取南郡,先结果了刘备!”肃曰:“某愿同往。”于是瑜与鲁肃引三千轻骑,径投油江口来。先说孙乾回见玄德,言周瑜将亲来相谢。玄德乃问孔明曰:“来意若何?”孔明笑曰:“那里为这些薄礼肯来相谢。止为南郡而来。”玄德曰:“他若提兵来,何以待之?”孔明曰:“他来便可如此如此应答。”遂于油江口摆开战船,岸上列着军马。人报:“周瑜、鲁肃引兵到来。”孔明使赵云领数骑来接。瑜见军势雄壮,心甚不安。行至营门外,玄德、孔明迎入帐中。各叙礼毕,设宴相待。玄德举酒致谢鏖兵之事。酒至数巡,瑜曰:“豫州移兵在此,莫非有取南郡之意否?”玄德曰:“闻都督欲取南郡,故来相助。若都督不取,备必取之”。瑜笑曰:“吾东吴久欲吞并汉江,今南郡已在掌中,如何不取?”玄德曰:“胜负不可预定。曹操临归,令曹仁守南郡等处,必有奇计;更兼曹仁勇不可当:但恐都督不能取耳。”瑜曰:“吾若取不得,那时任从公取。”玄德曰:“子敬、孔明在此为证,都督休悔。”鲁肃踌躇未对。瑜曰:“大丈夫一言既出,何悔之有!”孔明曰:“都督此言,甚是公论。先让东吴去取;若不下,主公取之,有何不可!”瑜与肃辞别玄德、孔明,上马而去。玄德问孔明曰:“却才先生教备如此回答,虽一时说了,展转寻思,于理未然。我今孤穷一身,无置足之地,欲得南郡,权且容身;若先教周瑜取了,城池已属东吴矣,却如何得住?”孔明大笑曰:“当初亮劝主公取荆州,主公不听,今日却想耶?”玄德曰:“前为景升之地,故不忍取;今为曹操之地,理合取之。”孔明曰:“不须主公忧虑。尽着周瑜去厮杀,早晚教主公在南郡城中高坐。”玄德曰:“计将安出?”孔明曰:“只须如此如此。”玄德大喜,只在江口屯扎,按兵不动。却说周瑜、鲁肃回寨。肃曰:“都督如何亦许玄德取南郡?”瑜曰:“吾弹指可得南郡,落得虚做人情。”随问帐下将士:“谁敢先取南郡?”一人应声而出,乃蒋钦也。 瑜曰:“汝为先锋,徐盛、丁奉为副将,拨五千精锐军马,先渡江。吾随后引兵接应。”且说曹仁在南郡,分付曹洪守彝陵,以为掎角之势。人报:“吴兵已渡汉江。”仁曰:“坚守勿战为上。”骁将牛金奋然进曰:“兵临城下而不出战,是怯也。况吾兵新败,正当重振锐气。某愿借精兵五百,决一死战。”仁从之,令牛金引五百军出战。丁奉纵马来迎。约战四五合,奉诈败,牛金引军追赶入阵。奉指挥众军一裹围牛金于阵中。金左右冲突,不能得出。曹仁在城上望见牛金困在垓心,遂披甲上马,引麾下壮士数百骑出城,奋力挥刀,杀入吴阵。徐盛迎战,不能抵挡。曹仁杀到垓心,救出牛金。回顾尚有数十骑在阵,不能得出,遂复翻身杀入,救出重围。正遇蒋钦拦路,曹仁与牛金奋力冲散。仁弟曹纯,亦引兵接应,混杀一阵。吴军败走,曹仁得胜而回。蒋钦兵败,回见周瑜,瑜怒欲斩之,众将告免。瑜即点兵,要亲与曹仁决战。甘宁曰:“都督未可造次。今曹仁令曹洪据守彝陵,为掎角之势;某愿以精兵三千,径取彝陵,都督然后可取南郡。”瑜服其论,先教甘宁领三千兵攻打彝陵,早有细作报知曹仁,仁与陈矫商议。矫曰:“彝陵有失,南郡亦不可守矣。宜速救之。”仁遂令曹纯与牛金暗地引兵救曹洪。曹纯先使人报知曹洪,令洪出城诱敌。甘宁引兵至彝陵,洪出与甘宁交锋。战有二十余合,洪败走。宁夺了彝陵。至黄昏时,曹纯、牛金兵到,两下相合,围了彝陵。探马飞报周瑜,说甘宁困于彝陵城中,瑜大惊。程普曰:“可急分兵救之。”瑜曰:“此地正当冲要之处,若分兵去救,倘曹仁引兵来袭,奈何?”吕蒙曰:“甘兴霸乃江东大将,岂可不救?”瑜曰:“吾欲自往救之;但留何人在此,代当吾任?”蒙曰:“留凌公绩当之。蒙为前驱,都督断后;不须十日,必奏凯歌。”瑜曰:“未知凌公绩肯暂代吾任否?”凌统曰:“若十日为期,可当之;十日之外,不胜其任矣。”瑜大喜,遂留兵万余,付与凌统;即日起大兵投彝陵来。蒙谓瑜曰:“彝陵南僻小路,取南郡极便。可差五百军去砍倒树木,以断其路。彼军若败,必走此路;马不能行,必弃马而走,吾可得其马也。”瑜从之,差军去讫。 @@ -932,7 +932,7 @@ 周瑜、程普收住众军,径到南郡城下,见旌旗布满,敌楼上一将叫曰:“都督少罪!吾奉军师将令,已取城了。吾乃常山赵子龙也。”周瑜大怒,便命攻城。城上乱箭射下。瑜命且回军商议,使甘宁引数千军马,径取荆州;凌统引数千军马,径取襄阳;然后却再取南郡未迟。正分拨间,忽然探马急来报说:“诸葛亮自得了南郡,遂用兵符,星夜诈调荆州守城军马来救,却教张飞袭了荆州。”又一探马飞来报说:“夏侯惇在襄阳,被诸葛亮差人赍兵符,诈称曹仁求救,诱惇引兵出,却教云长袭取了襄阳。二处城池,全不费力,皆属刘玄德矣。”周瑜曰:“诸葛亮怎得兵符?”程普曰:“他拿住陈矫,兵符自然尽属之矣。”周瑜大叫一声,金疮迸裂。正是:几郡城池无我分,一场辛苦为谁忙! 未知性命如何,且看下文分解。 (本章完) -第52章 诸葛亮智辞鲁肃 赵子龙计取桂阳 +第52章 诸葛亮智辞鲁肃 赵子龙计取桂阳   却说周瑜见孔明袭了南郡,又闻他袭了荆襄,如何不气?气伤箭疮,半晌方苏,众将再三劝解。瑜曰:“若不杀诸葛村夫,怎息我心中怨气!程德谋可助我攻打南郡,定要夺还东吴。”正议间,鲁肃至。瑜谓之曰:“吾欲起兵与刘备、诸葛亮共决雌雄,复夺城池。子敬幸助我。”鲁肃曰:“不可。方今与曹操相持,尚未分成败;主公现攻合淝不下。不争自家互相吞并,倘曹兵乘虚而来,其势危矣。况刘玄德旧曾与曹操相厚,若逼得紧急,献了城池,一同攻打东吴,如之奈何?”瑜曰:“吾等用计策,损兵马,费钱粮,他去图现成,岂不可恨!”肃曰:“公瑾且耐。容某亲见玄德,将理来说他。若说不通,那时动兵未迟。”诸将曰:“子敬之言甚善。” 于是鲁肃引从者径投南郡来,到城下叫门。赵云出问,肃曰:“我要见刘玄德有话说。”云答曰:“吾主与军师在荆州城中。”肃遂不入南郡,径奔荆州。见旌旗整列,军容甚盛,肃暗羡曰:“孔明真非常人也!”军士报入城中,说鲁子敬要见。孔明令大开城门,接肃入衙。讲礼毕,分宾主而坐。茶罢,肃曰:“吾主吴侯,与都督公瑾,教某再三申意皇叔,前者,操引百万之众,名下江南,实欲来图皇叔;幸得东吴杀退曹兵,救了皇叔。所有荆州九郡,合当归于东吴。今皇叔用诡计,夺占荆襄,使江东空费钱粮军马,而皇叔安受其利,恐于理未顺。”孔明曰:“子敬乃高明之士,何故亦出此言?常言道:物必归主。荆襄九郡,非东吴之地,乃刘景升之基业。吾主固景升之弟也。景升虽亡,其子尚在;以叔辅侄,而取荆州,有何不可?”肃曰:“若果系公子刘琦占据,尚有可解;今公子在江夏,须不在这里!”孔明曰:“子敬欲见公子乎?”便命左右:“请公子出来。”只见两从者从屏风后扶出刘琦。琦谓肃曰:“病躯不能施礼,子敬勿罪。”鲁肃吃了一惊,默然无语,良久,言曰:“公子若不在,便如何?”孔明曰:“公子在一日,守一日;若不在,别有商议。”肃曰:“若公子不在,须将城池还我东吴。”孔明曰:“子敬之言是也。”遂设宴相待。 宴罢,肃辞出城,连夜归寨,具言前事。瑜曰:“刘琦正青春年少,如何便得他死?这荆州何日得还?”肃曰:“都督放心。只在鲁肃身上,务要讨荆襄还东吴。”瑜曰:“子敬有何高见?”肃曰:“吾观刘琦过于酒色,病入膏肓,现今面色羸瘦,气喘呕血,不过半年,其人必死。那时往取荆州,刘备须无得推故。”周瑜犹自忿气未消,忽孙权遣使至。瑜令请入。使曰:“主公围合淝,累战不捷。特令都督收回大军,且拨兵赴合淝相助。”周瑜只得班师回柴桑养病,令程普部领战船士卒,来合淝听孙权调用。 @@ -947,7 +947,7 @@ 玄德与孔明亲赴桂阳。云迎接入城,推赵范于阶下。孔明问之,范备言以嫂许嫁之事。孔明谓云曰:“此亦美事,公何如此?”云曰:“赵范既与某结为兄弟,今若娶其嫂,惹人唾骂,一也;其妇再嫁,使失大节,二也;赵范初降,其心难测,三也。主公新定江汉,枕席未安,云安敢以一妇人而废主公之大事?”玄德曰:“今日大事已定,与汝娶之,若何?”云吾:“天下女子不少,但恐名誉不立,何患无妻子乎?”玄德曰:“子龙真丈夫也!”遂释赵范,仍令为桂阳太守,重赏赵云。张飞大叫曰:“偏子龙干得功!偏我是无用之人!只拨三千军与我去取武陵郡,活捉太守金旋来献!”孔明大喜曰:“翼德要去不妨,但要依一件事。”正是:军师决胜多奇策,将士争先立战功。 未知孔明说出那一件事来,且看下文分解。 (本章完) -第53章 关云长义释黄汉升 孙仲谋大战张文远 +第53章 关云长义释黄汉升 孙仲谋大战张文远   却说孔明谓张飞曰:“前者子龙取桂阳郡时,责下军令状而去。今日翼德要取武陵,必须也责下军令状,方可领兵去。”张飞遂立军令状,欣然领三千军,星夜投武陵界上来。金旋听得张飞引兵到,乃集将校,整点精兵器械,出城迎敌。从事巩志谏曰:“刘玄德乃大汉皇叔,仁义布于天下;加之张翼德骁勇非常。不可迎敌,不如纳降为上。”金旋大怒曰:“汝欲与贼通连为内变耶?”喝令武士推出斩之。众官皆告曰:“先斩家人,于军不利。”金旋乃喝退巩志,自率兵出。离城二十里,正迎张飞。飞挺矛立马,大喝金旋。旋问部将:“谁敢出战?”众皆畏惧,莫敢向前。旋自骤马舞刀迎之。张飞大喝一声,浑如巨雷,金旋失色,不敢交锋,拨马便走。飞引众军随后掩杀。金旋走至城边,城上乱箭射下。旋惊视之,见巩志立于城上曰:“汝不顺天时,自取败亡,吾与百姓自降刘矣。”言未毕,一箭射中金旋面门,坠于马下,军士割头献张飞。巩志出城纳降,飞就令巩志赍印绶,往桂阳见玄德。玄德大喜,遂令巩志代金旋之职。 玄德亲至武陵,安民毕,驰书报云长,言翼德、子龙各得一郡。云长乃回书上请曰:“闻长沙尚未取,如兄长不以弟为不才,教关某干这件功劳甚好。”玄德大喜,遂教张飞星夜去替云长守荆州,令云长来取长沙。 云长既至,入见玄德、孔明。孔明曰:“子龙取桂阳,翼德取武陵,都是三千军去。今长沙太守韩玄,固不足道。只是他有一员大将,乃南阳人,姓黄,名忠,字汉升;是刘表帐下中郎将,与刘表之侄刘磐共守长沙,后事韩玄;虽今年近六旬却有万夫不当之勇,不可轻敌。云长去,必须多带军马。”云长曰:“军师何故长别人锐气,灭自己威风?量一老卒,何足道哉!关某不须用三千军,只消本部下五百名校刀手,决定斩黄忠、韩玄之首,献来麾下。”玄德苦挡。云长不依,只领五百校刀手而去。孔明谓玄德曰:“云长轻敌黄忠,只恐有失。主公当往接应。”玄德从之,随后引兵望长沙进发。 @@ -965,7 +965,7 @@ 先将计策安排定,只等东吴使命来。 未知孔明如何对答,且看下文分解。 (本章完) -第54章 吴国太佛寺看新郎 刘皇叔洞房续佳偶 +第54章 吴国太佛寺看新郎 刘皇叔洞房续佳偶   却说孔明闻鲁肃到,与玄德出城迎接,接到公廨,相见毕。肃曰:“主公闻令侄弃世,特具薄礼,遣某前来致祭。周都督再三致意刘皇叔、诸葛先生。”玄德、孔明起身称谢,收了礼物,置酒相待。肃曰:“前者皇叔有言:公子不在,即还荆州。今公子已去世,必然见还。不识几时可以交割?”玄德曰:“公且饮酒,有一个商议。”肃强饮数杯,又开言相问。玄德未及回答,孔明变色曰:“子敬好不通理,直须待人开口!自我高皇帝斩蛇起义,开基立业,传至于今;不幸奸雄并起,各据一方;少不得天道好还,复归正统。我主人乃中山靖王之后,孝景皇帝玄孙,今皇上之叔,岂不可分茅裂土?况刘景升乃我主之兄也,弟承兄业,有何不顺?汝主乃钱塘小吏之子,素无功德于朝廷;今倚势力,占据六郡八十一州,尚自贪心不足,而欲并吞汉土。刘氏天下,我主姓刘倒无分,汝主姓孙反要强争?且赤壁之战,我主多负勤劳,众将并皆用命,岂独是汝东吴之为?若非我借东南风,周郎安能展半筹之功?江南一破,休说二乔置于铜雀宫,虽公等家小,亦不能保。适来我主人不即答应者,以子敬乃高明之士,不待细说。 何公不察之甚也!”一席话,说得鲁子敬缄口无言;半晌乃曰:“孔明之言,怕不有理;争奈鲁肃身上甚是不便。”孔明曰:“有何不便处?”肃曰:“昔日皇叔当阳受难时,是肃引孔明渡江,见我主公;后来周公瑾要兴兵取荆州,又是肃挡住;至说待公子去世还荆州,又是肃担承:今却不应前言,教鲁肃如何回覆?我主与周公瑾必然见罪。肃死不恨,只恐惹恼东吴,兴动干戈,皇叔亦不能安坐荆州,空为天下耻笑耳。”孔明曰:“曹操统百万之众,动以天子为名,吾亦不以为意,岂惧周郎一小儿乎!若恐先生面上不好看,我劝主人立纸文书,暂借荆州为本;待我主别图得城池之时,便交付还东吴。此论如何?”肃曰:“孔明待夺得何处,还我荆州?”孔明曰:“中原急未可图;西川刘璋闇弱,我主将图之。若图得西川,那时便还。”肃无奈,只得听从。玄德亲笔写成文书一纸,押了字。保人诸葛孔明也押了字。孔明曰:“亮是皇叔这里人,难道自家作保?烦子敬先生也押个字,回见吴侯也好看。”肃曰:“某知皇叔乃仁义之人,必不相负。”遂押了字,收了文书。宴罢辞回。玄德与孔明,送到船边。孔明嘱曰:“子敬回见吴侯,善言伸意,休生妄想。若不准我文书,我翻了面皮,连八十一州都夺了。今只要两家和气,休教曹贼笑话。” 肃作别下船而回,先到柴桑郡见周瑜。瑜问曰:“子敬讨荆州如何?”肃曰:“有文书在此。”呈与周瑜,瑜顿足曰:“子敬中诸葛之谋也!名为借地,实是混赖。他说取了西川便还,知他几时取西川?假如十年不得西川,十年不还?这等文书,如何中用,你却与他做保!他若不还时,必须连累足下,主公见罪奈何?”肃闻言,呆了半晌,曰:“恐玄德不负我。”瑜曰:“子敬乃诚实人也。刘备枭雄之辈,诸葛亮奸猾之徒,恐不似先生心地。”肃曰:“若此,如之奈何?”瑜曰:“子敬是我恩人,想昔日指囷相赠之情,如何不救你?你且宽心住数日,待江北探细的回,别有区处。”鲁肃跼蹐不安。 @@ -987,7 +987,7 @@ 惊看侍女横刀立,疑是东吴设伏兵。 毕竟是何缘故,且看下文分解。 (本章完) -第55章 玄德智激孙夫人 孔明二气周公瑾 +第55章 玄德智激孙夫人 孔明二气周公瑾   却说玄德见孙夫人房中两边枪刀森列,侍婢皆佩剑,不觉失色。管家婆进曰:“贵人休得惊惧:夫人自幼好观武事,居常令侍婢击剑为乐,故尔如此。”玄德曰:“非夫人所观之事,吾甚心寒,可命暂去。”管家婆禀覆孙夫人曰:“房中摆列兵器,娇客不安,今且去之。”孙夫人笑曰:“厮杀半生,尚惧兵器乎!”命尽撤去,令侍婢解剑伏侍。当夜玄德与孙夫人成亲,两情欢洽。玄德又将金帛散给侍婢,以买其心,先教孙乾回荆州报喜。自此连日饮酒。国太十分爱敬。 却说孙权差人来柴桑郡报周瑜,说:“我母亲力主,已将吾妹嫁刘备。不想弄假成真。此事还复如何?”瑜闻大惊,行坐不安,乃思一计,修密书付来人持回见孙权。权拆书视之。书略曰:“瑜所谋之事,不想反覆如此。既已弄假成真,又当就此用计。刘备以枭雄之姿,有关、张、赵云之将,更兼诸葛用谋,必非久屈人下者。愚意莫如软困之于吴中:盛为筑宫室,以丧其心志;多送美色玩好,以娱其耳目;使分开关、张之情,隔远诸葛之契,各置一方,然后以兵击之,大事可定矣。今若纵之,恐蛟龙得云雨,终非池中物也。愿明公熟思之。”孙权看毕,以书示张昭。昭曰:“公瑾之谋,正合愚意。刘备起身微末,奔走天下,未尝受享富贵。今若以华堂大厦,子女金帛,令彼享用,自然疏远孔明、关、张等,使彼各生怨望,然后荆州可图也。主公可依公瑾之计而速行之。”权大喜,即日修整东府,广栽花木,盛设器用,请玄德与妹居住;又增女乐数十余人,并金玉锦绮玩好之物。国太只道孙权好意,喜不自胜。玄德果然被声色所迷,全不想回荆州。 却说赵云与五百军在东府前住,终日无事,只去城外射箭走马。看看年终。云猛省:“孔明分付三个锦囊与我,教我一到南徐,开第一个;住到年终,开第二个;临到危急无路之时,开第三个:于内有神出鬼没之计,可保主公回家。此时岁已将终,主公贪恋女色,并不见面,何不拆开第二个锦囊,看计而行?”遂拆开视之。原来如此神策。即日径到府堂,要见玄德。侍婢报曰:“赵子龙有紧急事来报贵人。”玄德唤入问之。云佯作失惊之状曰:“主公深居画堂,不想荆州耶?”玄德曰:“有甚事如此惊怪?”云曰:“今早孔明使人来报,说曹操要报赤壁鏖兵之恨,起精兵五十万,杀奔荆州,甚是危急,请主公便回。”玄德曰:“必须与夫人商议。”云曰:“若和夫人商议,必不肯教主公回。不如休说,今晚便好起程。迟则误事!”玄德曰:“你且暂退,我自有道理。”云故意催逼数番而出。玄德入见孙夫人,暗暗垂泪。 @@ -1004,7 +1004,7 @@ 帅字旗下,周瑜自领惯战水军,左有黄盖,右有韩当,势如飞马,疾似流星。看看赶上。孔明教棹船投北岸,弃了船,尽皆上岸而走,车马登程。周瑜赶到江边,亦皆上岸追袭。大小水军,尽是步行;止有为首官军骑马。周瑜当先,黄盖、韩当、徐盛、丁奉紧随。周瑜曰:“此处是那里?军士答曰:“前面是黄州界首。”望见玄德车马不远,瑜令并力追袭。正赶之间,一声鼓响,山崦内一彪刀手拥出,为首一员大将,乃关云长也。周瑜举止失措,急拨马便走;云长赶来,周瑜纵马逃命。正奔走间,左边黄忠,右边魏延,两军杀出。吴兵大败。周瑜急急下得船时,岸上军士齐声大叫曰:“周郎妙计安天下,陪了夫人又折兵!”瑜怒曰:“可再登岸决一死战!”黄盖、韩当力阻。瑜自思曰:“吾计不成,有何面目去见吴侯!”大叫一声,金疮迸裂,倒于船上。众将急救,却早不省人事。正是:两番弄巧翻成拙,此日含嗔却带羞。 未知周郎性命如何,且看下文分解。 (本章完) -第56章 曹操大宴铜雀台 孔明三气周公瑾 +第56章 曹操大宴铜雀台 孔明三气周公瑾   却说周瑜被诸葛亮预先埋伏关公、黄忠、魏延三枝军马,一击大败。黄盖、韩当急救下船,折却水军无数。遥观玄德、孙夫人车马仆从,都停住于山顶之上,瑜如何不气?箭疮未愈,因怒气冲激,疮口迸裂,昏绝于地。众将救醒,开船逃去。孔明教休追赶,自和玄德归荆州庆喜,赏赐众将。 周瑜自回柴桑。蒋钦等一行人马自归南徐报孙权。权不胜忿怒,欲拜程普为都督,起兵取荆州。周瑜又上书,请兴兵雪恨。张昭谏曰:“不可。曹操日夜思报赤壁之恨,因恐孙、刘同心,故未敢兴兵。今主公若以一时之忿,自相吞并,操必乘虚来攻,国势危矣。”顾雍曰:“许都岂无细作在此?若知孙、刘不睦,操必使人勾结刘备。备惧东吴,必投曹操。若是,则江南何日得安?为今之计,莫若使人赴许都,表刘备为荆州牧。曹操知之,则惧而不敢加兵于东南。且使刘备不恨于主公。然后使心腹用反间之计,令曹、刘相攻,吾乘隙而图之,斯为得耳。”权曰:“元叹之言甚善。但谁可为使?”雍曰:“此间有一人,乃曹操敬慕者,可以为使。”权问何人。雍曰:“华歆在此,何不遣之?”权大喜。即遣歆赍表赴许都。歆领命起程,径到许都来见曹操。闻操会群臣于邺郡,庆赏铜雀台,歆乃赴邺郡候见。 操自赤壁败后,常思报仇;只疑孙、刘并力,因此不敢轻进,时建安十五年春,造铜雀台成,操乃大会文武于邺郡,设宴庆贺。其台正临漳河,中央乃铜雀台,左边一座名玉龙台,右边一座名金凤台,各高十丈,上横二桥相通,千门万户,金碧交辉。是日,曹操头戴嵌宝金冠,身穿绿锦罗袍,玉带珠履,凭高而坐。文武侍立台下。 @@ -1023,7 +1023,7 @@ 战船密密排在江上,依次而进,看看至公安,并无一只军船,又无一人远接。周瑜催船速行。离荆州十余里,只见江面上静荡荡的。哨探的回报:“荆州城上,插两面白旗,并不见一人之影。”瑜心疑,教把船傍岸,亲自上岸乘马,带了甘宁、徐盛、丁奉一班军官,引亲随精军三千人,径望荆州来。既至城下,并不见动静。瑜勒住马,令军士叫门。城上问是谁人。吴军答曰:“是东吴周都督亲自在此。”言未毕,忽一声梆子响,城上军一齐都竖起枪刀。敌楼上赵云出曰:“都督此行,端的为何?”瑜曰:“吾替汝主取西川,汝岂犹未知耶?”云曰:“孔明军师已知都督假途灭虢之计,故留赵云在此。吾主公有言:孤与刘璋,皆汉室宗亲,安忍背义而取西川?若汝东吴端的取蜀,吾当披发入山,不失信于天下也。”周瑜闻之,勒马便回。只见一人打着令字旗,于马前报说:“探得四路军马,一齐杀到:关某从江陵杀来,张飞从姊归杀来,黄忠从公安杀来,魏延从孱陵小路杀来,四路正不知多少军马。喊声远近震动百余里,皆言要捉周瑜。”瑜马上大叫一声,箭疮复裂,坠于马下。正是:一着棋高难对敌,几番算定总成空。 未知性命如何,且看下文分解。 (本章完) -第57章 柴桑口卧龙吊丧 耒阳县凤雏理事 +第57章 柴桑口卧龙吊丧 耒阳县凤雏理事   却说周瑜怒气填胸,坠于马下,左右急救归船。军士传说:“玄德、孔明在前山顶上饮酒取乐。”瑜大怒,咬牙切齿曰:“你道我取不得西川,吾誓取之!”正恨间,人报吴侯遣弟孙瑜到。周瑜接入。具言其事。孙瑜曰:“吾奉兄命来助都督。”遂令催军前行。行至巴丘,人报上流有刘封、关平二人领军截住水路。周瑜愈怒。忽又报孔明遣人送书至。周瑜拆封视之。书曰:“汉军师中郎将诸葛亮,致书于东吴大都督公瑾先生麾下:亮自柴桑一别,至今恋恋不忘。闻足下欲取西川,亮窃以为不可。益州民强地险,刘璋虽暗弱,足以自守。今劳师远征,转运万里,欲收全功,虽吴起不能定其规,孙武不能善其后也。曹操失利于赤壁,志岂须臾忘报仇哉?今足下兴兵远征,倘操乘虚而至,江南齑粉矣!亮不忍坐视,特此告知。幸垂照鉴。”周瑜览毕,长叹一声,唤左右取纸笔作书上吴侯。乃聚众将曰:“吾非不欲尽忠报国,奈天命已绝矣。汝等善事吴侯,共成大业。”言讫,昏绝。徐徐又醒,仰天长叹曰:“既生瑜,何生亮!”连叫数声而亡。寿三十六岁。后人有诗叹曰:“赤壁遗雄烈,青年有俊声。弦歌知雅意,杯酒谢良朋,曾谒三千斛,常驱十万兵。巴丘终命处,凭吊欲伤情。”周瑜停丧于巴丘。众将将所遗书缄,遣人飞报孙权。权闻瑜死,放声大哭。拆视其书,乃荐鲁肃以自代也。书略曰:“瑜以凡才,荷蒙殊遇,委任腹心,统御兵马,敢不竭股肱之力,以图报效。奈死生不测,修短有命;愚志未展,微躯已殒,遗恨何极!方今曹操在北,疆场未静;刘备寄寓,有似养虎;天下之事,尚未可知。此正朝士旰食之秋,至尊垂虑之日也。鲁肃忠烈,临事不苟,可以代瑜之任。人之将死,其言也善。倘蒙垂鉴,瑜死不朽矣。”孙权览毕,哭曰:“公瑾有王佐之才,今忽短命而死,孤何赖哉?既遗书特荐子敬,孤敢不从之。”即日便命鲁肃为都督,总统兵马;一面教发周瑜灵柩回葬。却说孔明在荆州,夜观天文,见将星坠地,乃笑曰:“周瑜死矣。”至晓,告于玄德。玄德使人探之,果然死了。玄德问孔明曰:“周瑜既死,还当如何?”孔明曰:“代瑜领兵者,必鲁肃也。亮观天象,将星聚于东方。亮当以吊丧为由。往江东走一遭,就寻贤士佐助主公。”玄德曰:“只恐吴中将士加害于先生。”孔明曰:“瑜在之日,亮犹不惧;今瑜已死,又何患乎?”乃与赵云引五百军,具祭礼,下船赴巴丘吊丧。于路探听得孙权已令鲁肃为都督,周瑜灵柩已回柴桑。 孔明径至柴桑,鲁肃以礼迎接。周瑜部将皆欲杀孔明,因见赵云带剑相随,不敢下手。孔明教设祭物于灵前,亲自奠酒,跪于地下,读祭文曰:“呜呼公瑾,不幸夭亡!修短故天,人岂不伤?我心实痛,酹酒一觞;君其有灵,享我烝尝!吊君幼学,以交伯符;仗义疏财,让舍以民。吊君弱冠,万里鹏抟;定建霸业,割据江南。吊君壮力,远镇巴丘;景升怀虑,讨逆无忧。吊君丰度,佳配小乔;汉臣之婿,不愧当朝,吊君气概,谏阻纳质;始不垂翅,终能奋翼。吊君鄱阳,蒋干来说;挥洒自如,雅量高志。吊君弘才,文武筹略;火攻破敌,挽强为弱。想君当年,雄姿英发;哭君早逝,俯地流血。 忠义之心,英灵之气;命终三纪,名垂百世,哀君情切,愁肠千结;惟我肝胆,悲无断绝。昊天昏暗,三军怆然;主为哀泣;友为泪涟。亮也不才,丐计求谋;助吴拒曹,辅汉安刘;掎角之援,首尾相俦,若存若亡,何虑何忧?呜呼公瑾!生死永别!朴守其贞,冥冥灭灭,魂如有灵,以鉴我心:从此天下,更无知音!呜呼痛哉!伏惟尚飨。”孔明祭毕,伏地大哭,泪如涌泉,哀恸不已。众将相谓曰:“人尽道公瑾与孔明不睦,今观其祭奠之情,人皆虚言也。”鲁肃见孔明如此悲切,亦为感伤,自思曰:“孔明自是多情,乃公瑾量窄,自取死耳。”后人有诗叹曰:“卧龙南阳睡未醒,又添列曜下舒城。苍天既已生公瑾,尘世何须出孔明!” @@ -1043,7 +1043,7 @@ 曹操教招安西凉兵马,谕之曰:“马腾父子谋反,不干众人之事。”一面使人分付把住关隘,休教走了马岱。且说马岱自引一千兵在后。早有许昌城外逃回军士,报知马岱。岱大惊,只得弃了兵马,扮作客商,连夜逃遁去了。曹操杀了马腾等,便决意南征。忽人报曰:“刘备调练军马,收拾器械,将欲取川。”操惊曰:“若刘备收川,则羽翼成矣。将何以图之?”言未毕,阶下一人进言曰:“某有一计,使刘备、孙权不能相顾,江南、西川皆归丞相。”正是:西州豪杰方遭戮,南国英雄又受殃。 未知献计者是谁,且看下文分解。 (本章完) -第58章 马孟起兴兵雪恨 曹阿瞒割须弃袍 +第58章 马孟起兴兵雪恨 曹阿瞒割须弃袍   却说献策之人,乃治书侍御史陈群,字长文。操问曰:“陈长文有何良策?”群曰:“今刘备、孙权结为唇齿,若刘备欲取西川,丞相可命上将提兵,会合淝之众,径取江南,则孙权必求救于刘备;备意在西川,必无心救权;权无救则力乏兵衰,江东之地,必为丞相所得。若得江东,则荆州一鼓可平也;荆州既平,然后徐图西川:天下定矣。”操曰:“长文之言,正合吾意。”即时起大兵三十万,径下江南;令合淝张辽,准备粮草,以为供给。 早有细作报知孙权。权聚众将商议。张昭曰:“可差人往鲁子敬处,教急发书到荆州,使玄德同力拒曹。子敬有恩于玄德,其言必从;且玄德既为东吴之婿,亦义不容辞。若玄德来相助。江南可无患矣。”权从其言,即遣人谕鲁肃,使求救于玄德。肃领命,随即修书使人送玄德,玄德看了书中之意,留使者于馆舍,差人往南郡请孔明。孔明到荆州,玄德将鲁肃书与孔明看毕,孔明曰:“也不消动江南之兵,也不必动荆州之兵,自使曹操不敢正觑东南。”便回书与鲁肃,教高枕无忧,若但有北兵侵犯,皇叔自有退兵之策。使者去了。玄德问曰:“今操起三十万大军,会合淝之众,一拥而来,先生有何妙计,可以退之?”孔明曰:“操平生所虑者,乃西凉之兵也。今操杀马腾,其子马超现统西凉之众,必切齿操贼。主公可作一书,往结马超,使超兴兵入关,则操又何暇下江南乎?”玄德大喜,即时作书,遣一心腹人,径往西凉州投下。 却说马超在西凉州,夜感一梦:梦见身卧雪地,群虎来咬。惊惧而觉,心中疑惑,聚帐下将佐,告说梦中之事。帐下一人应声曰:“此梦乃不祥之兆也。”众视其人,乃帐前心腹校尉,姓庞,名德,字令明。超问:“令明所见若何?”德曰:“雪地遇虎,梦兆殊恶。莫非老将军在许昌有事否?”言未毕,一人踉跄而入,哭拜于地曰:“叔父与弟皆死矣!”超视之,乃马岱也。超惊问何为。岱曰:“叔父与侍郎黄奎同谋杀操,不幸事泄,皆被斩于市,二弟亦遇害。惟岱扮作客商,星夜走脱。超闻言,哭倒于地。众将救起。超咬牙切齿,痛恨操贼。忽报荆州刘皇叔遣人赍书至。超拆视之。书略曰:“伏念汉室不幸,操贼专权,欺君罔上,黎民凋残。备昔与令先君同受密诏,誓诛此贼。今令先君被操所害,此将军不共天地、不同日月之仇也。若能率西凉之兵,以攻操之右,备当举荆襄之众,以遏操之前:则逆操可擒,奸党可灭,仇辱可报,汉室可兴矣。书不尽言,立待回音。” @@ -1065,7 +1065,7 @@ 却说曹操收兵屯渭北,唤诸将曰:“贼欺我未立寨棚,必来劫野营。可四散伏兵,虚其中军。号炮响时,伏兵尽起,一鼓可擒也。”众将依令,伏兵已毕。当夜,马超却先使成宜引三十骑往前哨探,成宜见无人马,径入中军。操军见西凉兵到,遂放号炮。四面伏兵皆出,只围得三十骑。成宜被夏侯渊所杀。马超却自从背后与庞德、马岱兵分三路蜂拥杀来。正是:纵有伏兵能候敌,怎当键将共争先? 未知胜负若何,且看下文分解。 (本章完) -第59章 许诸裸衣斗马超 曹操抹书问韩遂 +第59章 许诸裸衣斗马超 曹操抹书问韩遂   却说当夜两兵混战,直到天明,各自收兵。马超屯兵渭口,日夜分兵,前后攻击。曹操在渭河内将船筏锁链作浮桥三条,接连南岸。曹仁引军夹河立寨,将粮草车辆穿连,以为屏障。马超闻之,教军士各挟草一束,带着火种,与韩遂引军并力杀到寨前,堆积草把,放起烈火。操兵抵敌不住,弃寨而走。车乘、浮桥,尽被烧毁。西凉兵大胜,截住渭河。曹操立不起营寨,心中忧惧。荀攸曰:“可取渭河沙土筑起土城,可以坚守。”操拨三万军担土筑城。马超又差庞德、马岱各引五百马军,往来冲突;更兼沙土不实,筑起便倒,操无计可施。时当九月尽,天气暴冷,彤云密布,连日不开。曹操在寨中纳闷。忽人报曰:“有一老人来见丞相,欲陈说方略。”操请入。见其人鹤骨松姿,形貌苍古。问之,乃京兆人也,隐居终南山,姓娄,名子伯,道号梦梅居士。操以客礼待之。子伯曰:“丞相欲跨渭安营久矣,今何不乘时筑之?”操曰:“沙土之地,筑垒不成。隐士有何良策赐教?”子伯曰:“丞相用兵如神,岂不知天时乎?连日阴云布合,朔风一起,必大冻矣。风起之后,驱兵士运土泼水,比及天明,土城已就。”操大悟,厚赏子伯。子伯不受而去。 是夜北风大作。操尽驱兵士担土泼水;为无盛水之具,作缣囊盛水浇之,随筑随冻。比及天明,沙水冻紧,土城已筑完。细作报知马超。超领兵观之,大惊,疑有神助。次日,集大军呜鼓而进。操自乘马出营,止有许褚一人随后。操扬鞭大呼曰:“孟德单骑至此,请马超出来答话。”超乘马挺枪而出。操曰:“汝欺我营寨不成,今一夜天已筑就,汝何不早降!”马超大怒,意欲突前擒之,见操背后一人,睁圆怪眼,手提钢刀,勒马而立。超疑是许褚,乃扬鞭问曰:“闻汝军中有虎侯,安在哉?”许褚提刀大叫曰:“吾即谯郡许褚也!”目射神光,威风抖擞。超不敢动,乃勒马回。操亦引许褚回寨。两军观之,无不骇然。操谓诸将曰:“贼亦知仲康乃虎侯也!”自此军中皆称褚为虎侯,许褚曰:“某来日必擒马超。”操曰:“马超英勇,不可轻敌。”褚曰:“某誓与死战!”即使人下战书,说虎侯单搦马超来日决战。超接书大怒曰:“何敢如此相欺耶!”即批次日誓杀虎痴。 次日,两军出营布成阵势。超分庞德为左翼,马岱为右翼,韩遂押中军。超挺枪纵马,立于阵前,高叫:“虎痴快出!”曹操在门旗下回顾众将曰:“马超不减吕布之勇!”言未绝,许褚拍马舞刀而出。马超挺枪接战。斗了一百余合,胜负不分。马匹困乏,各回军中,换了马匹,又出阵前。又斗一百余合,不分胜负。许褚性起,飞回阵中,卸了盔甲,浑身筋突,赤体提刀,翻身上马,来与马超决战。两军大骇。两个又斗到三十余合,褚奋威举刀便砍马超。超闪过,一枪望褚心窝刺来。褚弃刀将枪挟住。两个在马上夺枪。许诸力大,一声响,拗断枪杆,各拿半节在马上乱打。操恐褚有失,遂令夏侯渊、曹洪两将齐出夹攻。庞德、马岱见操将齐出,麾两翼铁骑,横冲直撞,混杀将来。操兵大乱。许褚臂中两箭。诸将慌退入寨。马超直杀到壕边,操兵折伤大半。操令坚闭休出。马超回至渭口,谓韩遂曰:“吾见恶战者莫如许褚,真虎痴也!” @@ -1083,7 +1083,7 @@ 却说益州刘璋,字季玉,即刘焉之子,汉鲁恭王之后。章帝元和中,徙封竟陵,支庶因居于此。后焉官至益州牧,兴平元年患病疽而死,州大吏赵韪等,共保璋为益州牧。璋曾杀张鲁母及弟,因此有仇。璋使庞羲为巴西太守,以拒张鲁。时笼羲探知张鲁欲兴兵取川,急报知刘璋。璋平生懦弱,闻得此信,心中大忧,急聚众官商议。忽一人昂然而出曰:“主公放心。某虽不才,凭三寸不烂之舌,使张鲁不敢正眼来觑西川。”正是:只因蜀地谋臣进,致引荆州豪杰来。 未知此人是谁,且看下文分解。 (本章完) -第60章 张永年反难杨修 庞士元议取西蜀 +第60章 张永年反难杨修 庞士元议取西蜀   却说那进计于刘璋者,乃益州别驾,姓张,名松,字永年。其人生得额钁头尖,鼻僵齿露,身短不满五尺,言语有若铜钟。刘璋问曰:“别驾有何高见,可解张鲁之危?”松曰:“某闻许都曹操,扫荡中原,吕布、二袁皆为所灭,近又破马超,天下无敌矣。主公可备进献之物,松亲往许都,说曹操兴兵取汉中,以图张鲁。则鲁拒敌不暇,何敢复窥蜀中耶?”刘璋大喜,收拾金珠锦绮,为进献之物,遣张松为使。松乃暗画西川地理图本藏之,带从人数骑,取路赴许都。早有人报入荆州。孔明便使人入许都打探消息。 却说张松到了许都馆驿中住定,每日去相府伺候,求见曹操。原来曹操自破马超回,傲睨得志,每日饮宴,无事少出,国政皆在相府商议。张松候了三日,方得通姓名。左右近侍先要贿赂,却才引入。操坐于堂上,松拜毕,操问曰:“汝主刘璋连年不进贡,何也?”松曰:“为路途艰难,贼寇窃发,不能通进。”操叱曰:“吾扫清中原,有何盗贼?”松曰:“南有孙权,北有张鲁,西有刘备,至少者亦带甲十余万,岂得为太平耶?”操先见张松人物猥琐,五分不喜;又闻语言冲撞,遂拂袖而起,转入后堂。左右责松曰:“汝为使命,何不知礼,一味冲撞?幸得丞相看汝远来之面,不见罪责。汝可急急回去!”松笑曰:“吾川中无诌佞之人也。”忽然阶下一人大喝曰:“汝川中不会谄佞,吾中原岂有谄佞者乎?” 松观其人,单眉细眼,貌白神清。问其姓名,乃太尉杨彪之子杨修,字德祖,现为丞相门下掌库主簿。此人博学能言,智识过人。松知修是个舌辩之士,有心难之。修亦自恃其才,小觑天下之士。当时见张松言语讥讽,遂邀出外面书院中,分宾主而坐,谓松曰:“蜀道崎岖,远来劳苦。”松曰:“奉主之命,虽赴汤蹈火,弗敢辞也。”修问:“蜀中风土何如?”松曰:“蜀为西郡,古号益州。路有锦江之险,地连剑阁之雄。回还二百八程,纵横三万余里。鸡鸣犬吠相闻,市井闾阎不断。田肥地茂,岁无水旱之忧;国富民丰,时有管弦之乐。所产之物,阜如山积。天下莫可及也!”修又问曰:“蜀中人物如何?”松曰:“文有相如之赋,武有伏波之才;医有仲景之能,卜有君平之隐。九流三教,出乎其类,拔乎其萃者,不可胜记,岂能尽数!”修又问曰:“方今刘季玉手下,如公者还有几人?”松曰:“文武全才,智勇足备,忠义慷慨之士,动以百数。如松不才之辈,车载斗量,不可胜记。”修曰:“公近居何职?”松曰:“滥充别驾之任,甚不称职。敢问公为朝廷何官?”修曰:“现为丞相府主簿。 @@ -1105,7 +1105,7 @@ 却说玄德归到寨中。庞统入见曰:“主公今日席上见刘季玉动静乎?”玄德吾:“季玉真诚实人也。”统曰:“季玉虽善,其臣刘璝、张任等皆有不平之色,其间吉凶未可保也。以统之计,莫若来日设宴,请季玉赴席;于壁衣中埋伏刀斧手一百人,主公掷杯为号,就筵上杀之;一拥入成都,刀不出鞘,弓不上弦,可坐而定也。”玄德曰:“季玉是吾同宗,诚心待吾;更兼吾初到蜀中,恩信未立;若行此事,上天不容,下民亦怨。公此谋,虽霸者亦不为也。”统曰:“此非统之谋,是法孝直得张松密书,言事不宜迟,只在早晚当图之。”言未已,法正入见,曰:“某等非为自己,乃顺天命也。”玄德曰:“刘季玉与吾同宗,不忍取之。”正曰:“明公差矣。若不如此,张鲁与蜀有杀母之仇,必来攻取。明公远涉山川,驱驰士马,既到此地,进则有功,退则无益。若执狐疑之心,迁延日久,大为失计。且恐机谋一泄,反为他人所算。不若乘此天与人归之时,出其不意,早立基业,实为上策。”庞统亦再三相劝。正是:人主几番存厚道,才臣一意进权谋。 未知玄德心下如何,且看下文分解。 (本章完) -第61章 赵云截江夺阿斗 孙权遗书退老瞒 +第61章 赵云截江夺阿斗 孙权遗书退老瞒   却说庞统、法正二人,劝玄德就席间杀刘璋,西川唾手可得。玄德曰:“吾初入蜀中,恩信未立,此事决不可行。”二人再三说之,玄德只是不从。次日,复与刘璋宴于城中,彼此细叙衷曲,情好甚密。酒至半酣,庞统与法正商议曰:“事已至此,由不得主公了。”便教魏延登堂舞剑,乘势杀刘璋。延遂拔剑进曰:“筵间无以为乐,愿舞剑为戏。”庞统便唤众武士入,列于堂下,只待魏延下手。刘璋手下诸将,见魏延舞剑筵前,又见阶下武士手按刀靶,直视堂上,从事张任亦掣剑舞曰:“舞剑必须有对,某愿与魏将军同舞。”二人对舞于筵前。魏延目视刘封,封亦拔剑助舞。于是刘璝、泠苞、邓贤各掣剑出曰:“我等当群舞,以助一笑。”玄德大惊,急掣左右所佩之剑,立于席上曰:“吾兄弟相逢痛饮,并无疑忌。 又非鸿门会上,何用舞剑?不弃剑者立斩!”刘璋亦叱曰:“兄弟相聚,何必带刀?”命侍卫者尽去佩剑。众皆纷然下堂。玄德唤诸将士上堂,以酒赐之,曰:“吾弟兄同宗骨血,共议大事,并无二心。汝等勿疑。”诸将皆拜谢。刘璋执玄德之手而泣曰:“吾兄之恩,誓不敢忘!”二人欢饮至晚而散。玄德归寨,责庞统曰:“公等奈何欲陷备于不义耶?今后断勿为此。”统嗟叹而退。却说刘璋归寨,刘璝等曰:“主公见今日席上光景乎?不如早回,免生后患。刘璋曰:“吾兄刘玄德,非比他人。”众将曰:“虽玄德无此心,他手下人皆欲吞并西川,以图富贵。”璋曰:“汝等无间吾兄弟之情。”遂不听,日与玄德欢叙。忽报张鲁整顿兵马,将犯葭萌关。刘璋便请玄德往拒之。玄德慨然领诺,即日引本部兵望葭萌关去了。众将劝刘璋令大将紧守各处关隘,以防玄德兵变。璋初时不从,后因众人苦劝,乃令白水都督杨怀、高沛二人,守把涪水关。刘璋自回成都。玄德到葭萌关,严禁军士,广施恩惠,以收民心。 早有细作报入东吴。吴侯孙权会文武商议。顾雍进曰:“刘备分兵远涉山险而去,未易往还。何不差一军先截川口,断其归路,后尽起东吴之兵,一鼓而下荆襄?此不可失之机会也。”权曰:“此计大妙!”正商议间,忽屏风后一人大喝而出曰:“进此计者可斩之!欲害吾女之命耶!”众惊视之,乃吴国太也。国太怒曰:“吾一生惟有一女,嫁与刘备。今若动兵,吾女性命如何!”因叱孙权曰:“汝掌父兄之业,坐领八十一州,尚自不足,乃顾小利而不念骨肉!”孙权喏喏连声,答曰:“老母之训,岂敢有违!”遂叱退众官。国太恨恨而入。孙权立于轩下,自思:“此机会一失,荆襄何日可得?”正沉吟间,只见张昭入问曰:“主公有何忧疑?”孙权曰:“正思适间之事。”张昭曰:“此极易也:今差心腹将一人,只带五百军。潜入荆州,下一封密书与郡主,只说国太病危,欲见亲女,取郡主星夜回东吴。玄德平生只有一子,就教带来。那时玄德定把荆州来换阿斗。 @@ -1122,7 +1122,7 @@ 忽报东吴有使赍书到。操启视之。书略曰:“孤与丞相,彼此皆汉朝臣宰。丞相不思报国安民,乃妄动干戈,残虐生灵,岂仁人之所为哉?即日春水方生,公当速去。如其不然,复有赤壁之祸矣。公宜自思焉。”书背后又批两行云:“足下不死,孤不得安。”曹操看毕,大笑曰:“孙仲谋不欺我也。”重赏来使,遂下令班师,命庐江太守朱光镇守皖城,自引大军回许昌。孙权亦收军回秣陵。权与众将商议:“曹操虽然北去,刘备尚在葭萌关未还。何不引拒曹操之兵,以取荆州?”张昭献计曰:“且未可动兵。某有一计,使刘备不能再还荆州。”正是:孟德雄兵方退北,仲谋壮志又图南。 不知张昭说出甚计来,且看下文分解。 (本章完) -第62章 取涪关杨高授首 攻雒城黄魏争功 +第62章 取涪关杨高授首 攻雒城黄魏争功   却说张昭献计曰:“且休要动兵。若一兴师,曹操必复至。不如修书二封:一封与刘璋,言刘备结连东吴,共取西川,使刘璋心疑而攻刘备;一封与张鲁,教进兵向荆州来。着刘备首尾不能救应。我然后起兵取之,事可谐矣。”权从之,即发使二处去讫。且说玄德在葭萌关日久,甚得民心。忽接得孔明文书。知孙夫人已回东吴。又闻曹操兴兵犯濡须,乃与庞统议曰:“曹操击孙权,操胜必将取荆州,权胜亦必取荆州矣。为之奈何?”庞统曰:“主公勿忧。有孔明在彼,料想东吴不敢犯荆州。主公可驰书去刘璋处,只推曹操攻击孙权,权求救于荆州。吾与孙权唇齿之邦,不容不相援。张鲁自守之贼,决不敢来犯界。吾今欲勒兵回荆州,与孙权会同破曹操,奈兵少粮缺。望推同宗之谊,速发精兵三、四万,行粮十万斛相助。请勿有误。若得军马钱粮,却另作商议。” 玄德从之,遣人往成都。来到关前,杨怀、高沛闻知此事,遂教高沛守关,杨怀同使者入成都,见刘璋呈上书信。刘璋看毕,问杨怀为何亦同来。杨怀曰:“专为此书而来。刘备自从入川,广布恩德,以收民心,其意甚是不善。今求军马钱粮,切不可与。如若相助,是把薪助火也。”刘璋曰:“吾与玄德有兄弟之情,岂可不助?”一人出曰:“刘备枭雄,久留于蜀而不遣,是纵虎入室矣。今更助之以军马钱粮,何异与虎添翼乎?”众视其人,乃零陵烝阳人,姓刘名巴,字子初。刘璋闻刘巴之言,犹豫未决。黄权又复苦谏。璋乃量拨老弱军四千,米一万斛,发书遣使报玄德。仍令杨怀、高沛紧守关隘。刘璋使者到葭萌关见玄德,呈上回书。玄德大怒曰:“吾为汝御敌,费力劳心。汝今积财吝赏,何以使士卒效命乎?”遂扯毁回书,大骂而起。使者逃回成都。庞统曰:“主公只以仁义为重,今日毁书发怒,前情尽弃矣。”玄德曰:“如此,当若何?”庞统曰:“某有三条计策,请主公自择而行。” 玄德问:“那三条计?”统曰:“只今便选精兵,昼夜兼道径袭成都:此为上计。杨怀、高沛乃蜀中名将,各仗强兵拒守关隘;今主公佯以回荆州为名,二将闻知,必来相送;就送行处,擒而杀之,夺了关隘,先取涪城,然后却向成都:此中计也。退还白帝,连夜回荆州,徐图进取:此为下计。若沉吟不去,将至大困,不可救矣。”玄德曰:“军师上计太促,下计太缓;中计不迟不疾,可以行之。” @@ -1144,7 +1144,7 @@ 却说玄德令黄忠、魏延各守一寨,自回涪城,与军师庞统商议。细作报说:“东吴孙权遣人结好东川张鲁,将欲来攻葭萌关。”玄德惊曰:“若葭萌关有失,截断后路,吾进退不得,当如之何?”庞统谓孟达曰:“公乃蜀中人,多知地理,去守葭萌关如何?”达曰:“某保一人与某同去守关,万无一失。”玄德问何人。达曰:“此人曾在荆州刘表部下为中郎将,乃南郡枝江人,姓霍,名峻,字仲邈。”玄德大喜,即时遣孟达、霍峻守葭萌关去了。庞统退归馆舍,门吏忽报:“有客特来相访。”统出迎接,见其人身长八尺,形貌甚伟;头发截短,披于颈上;衣服不甚齐整。统问曰:“先生何人也?”其人不答,径登堂仰卧床上。统甚疑之。再三请问。其人曰:“且消停,吾当与汝说知天下大事。”统闻之愈疑,命左右进酒食。其人起而便食,并无谦逊;饮食甚多,食罢又睡。统疑惑不定,使人请法正视之,恐是细作。法正慌忙到来。统出迎接,谓正曰:“有一人如此如此。”法正曰:“莫非彭永言乎?”升阶视之。其人跃起曰:“孝直别来无慈!正是:只为川人逢旧识,遂令涪水息洪流。 毕竟此人是谁,且看下文分解。 (本章完) -第63章 诸葛亮痛哭庞统 张翼德义释严颜 +第63章 诸葛亮痛哭庞统 张翼德义释严颜   却说法正与那人相见,各抚掌而笑。庞统问之。正曰:“此公乃广汉人,姓彭,名羕,字永言,蜀中豪杰也。因直言触忤刘璋,被璋髡钳为徒隶,因此短发。”统乃以宾礼待之,问羕从何而来。羕曰:“吾特来救汝数万人性命,见刘将军方可说。”法正忙报玄德。玄德亲自谒见,请问其故。羕曰:“将军有多少军马在前寨?”玄德实告:“有魏延、黄忠在彼。”羕曰:“为将之道,岂可不知地理乎?前寨紧靠涪江,若决动江水,前后以兵塞之,一人无可逃也。”玄德大悟。彭羕曰:“罡星在西方,太白临于此地,当有不吉之事,切宜慎之。”玄德即拜彭羕为幕宾,使人密报魏延、黄忠,教朝暮用心巡警,以防决水。黄忠、魏延商议:二人各轮一日,如遇敌军到来,互相通报。却说泠苞见当夜风雨大作,引了五千军,径循江边而进,安排决江。只听得后面喊声乱起,泠苞知有准备,急急回军。 前面魏延引军赶来,川兵自相践踏。泠苞正奔走间,撞着魏延。交马不数合,被魏延活捉去了。比及吴兰、雷铜来接应时,又被黄忠一军杀退。魏延解泠苞到涪关。玄德责之曰:“吾以仁义相待,放汝回去,何敢背我!今次难饶!”将泠苞推出斩之,重赏魏延。玄德设宴管待彭羕,忽报荆州诸葛亮军师特遣马良奉书至此。玄德召入问之。马良礼毕曰:“荆州平安,不劳主公忧念。”遂呈上军师书信。玄德拆书观之,略曰:“亮夜算太乙数,今年岁次癸巳,罡星在西方;又观乾象,太白临于雒城之分:主将帅身上多凶少吉。切宜谨慎。”玄德看了书,便教马良先回。玄德曰:“吾将回荆州,去论此事。”庞统暗思:“孔明怕我取了西川,成了功,故意将此书相阻耳。”乃对玄德曰:“统亦算太乙数,已知罡星在西,应主公合得西川,别不主凶事。统亦占天文,见太白临于雒城,先斩蜀将泠苞,已应凶兆矣。主公不可疑心,可急进兵。” 玄德见庞统再三催促,乃引军前进。黄忠同魏延接入寨去。庞统问法正曰:“前至雒城,有多少路?”法正画地作图。玄德取张松所遗图本对之,并无差错。法正言:“山北有条大路,正取雒城东门;山南有条小路,却取雒城西门:两条路皆可进兵。”庞统谓玄德曰:“统令魏延为先锋,取南小路而进;主公令黄忠作先锋,从山北大路而进:并到雒城取齐。”玄德曰:“吾自幼熟于弓马,多行小路。军师可从大路去取东门,吾取西门。”庞统曰:“大路必有军邀拦,主公引兵当之。统取小路。”玄德曰:“军师不可。吾夜梦一神人,手执铁棒击吾右臂,觉来犹自臂疼。此行莫非不佳。”庞统曰:“壮士临阵,不死带伤,理之自然也。何故以梦寐之事疑心乎?”玄德曰:“吾所疑者,孔明之书也。军师还守涪关,如何?”庞统大笑曰:“主公被孔明所惑矣:彼不欲令统独成大功,故作此言以疑主公之心。心疑则致梦,何凶之有?统肝脑涂地,方称本心。主公再勿多言,来早准行。” @@ -1165,7 +1165,7 @@ 张飞杀到巴郡城下,后军已自入城。张飞叫休杀百姓,出榜安民。群刀手把严颜推至。飞坐于厅上,严颜不肯下跪。飞怒目咬牙大叱曰:“大将到此,何为不降,而敢拒敌?”严颜全无惧色,回叱飞曰:“汝等无义,侵我州郡!但有断头将军,无降将军!”飞大怒,喝左右斩来。严颜喝曰:“贼匹夫!砍头便砍,何怒也?”张飞见严颜声音雄壮,面不改色,乃回嗔作喜,下阶喝退左右,亲解其缚,取衣衣之,扶在正中高坐,低头便拜曰:“适来言语冒渎,幸勿见责。吾素知老将军乃豪杰之士也。”严颜感其恩义,乃降。后人有诗赞严颜曰:“白发居西蜀,清名震大邦。忠心如皎月,浩气卷长江。宁可断头死,安能屈膝降?巴州年老将,天下更无双。”又有赞张飞诗曰:“生获严颜勇绝伦,惟凭义气服军民。至今庙貌留巴蜀,社酒鸡豚日日春。”张飞请问入川之计。严颜曰:“败军之将,荷蒙厚恩,无可以报,愿施犬马之劳,不须张弓只箭,径取成都。”正是:只因一将倾心后,致使连城唾手降。 未知其计如何,且看下文分解。 (本章完) -第64章 孔明定计捉张任 杨阜借兵破马超 +第64章 孔明定计捉张任 杨阜借兵破马超   却说张飞问计于严颜,颜曰:“从此取雒城,凡守御关隘,都是老夫所管,官军皆出于掌握之中。今感将军之恩,无可以报,老夫当为前部,所到之处,尽皆唤出拜降。”张飞称谢不已。于是严颜为前部,张飞领军随后。凡到之处,尽是严颜所管,都唤出投降。有迟疑未决者,颜曰:“我尚且投降,何况汝乎?”自是望风归顺,并不曾厮杀一场。 却说孔明已将起程日期申报玄德,教都会聚雒城。玄德与众官商议:“今孔明、翼德分两路取川,会于雒城,同入成都。水陆舟车,已于七月二十日起程,此时将及待到。今我等便可进兵。”黄忠曰:“张任每日来搦战,见城中不出,彼军懈怠,不做准备,今日夜间分兵劫寨,胜如白昼厮杀。”玄德从之,教黄忠引兵取左,魏延引兵取右,玄德取中路。当夜二更,三路军马齐发。张任果然不做准备。汉军拥入大寨,放起火来,烈焰腾空。蜀兵奔走,连夜直赶到雒城,城中兵接应入去。玄德还中路下寨;次日,引兵直到雒城,围住攻打。张任按兵不出。攻到第四日,玄德自提一军攻打西门,令黄忠、魏延在东门攻打,留南门北门放军行走。原来南门一带都是山路,北门有涪水:因此不围。张任望见玄德在西门,骑马往来,指挥打城,从辰至未,人马渐渐力乏。张任教吴兰、雷铜二将引兵出北门,转东门,敌黄忠、魏延;自己却引军出南门,转西门,单迎玄德。城内尽拨民兵上城,擂鼓助喊。却说玄德见红日平西,教后军先退。军士方回身,城上一片声喊起,南门内军马突出。 张任径来军中捉玄德,玄德军中大乱。黄忠、魏延又被吴兰、雷铜敌住。两下不能相顾。玄德敌不住张任,拨马往山僻小路而走。张任从背后追来,看看赶上。玄德独自一人一马。张任引数骑赶来。玄德正望前尽力加鞭而行,忽山路一军冲来。玄德马上叫苦曰:“前有伏兵,后有追兵,天亡我也!”只见来军当头一员大将,乃是张飞。原来张飞与严颜正从那条路上来,望见尘埃起,知与川兵交战。张飞当先而来,正撞着张任,便就交马。战到十余合,背后严颜引兵大进。张任火速回身。张飞直赶到城下。张任退入城,拽起吊桥。张飞回见玄德曰:“军师溯江而来,尚且未到,反被我夺了头功。”玄德曰:“山路险阻,如何无军阻当,长驱大进,先到于此?”张飞曰:“于路关隘四十五处,皆出老将严颜之功,因此于路并不曾费分毫之力。”遂把义释严颜之事,从头说了一遍,引严颜见玄德。玄德谢曰:“若非老将军,吾弟安能到此?”即脱身上黄金锁子甲以赐之。严颜拜谢。正待安排宴饮,忽闻哨马回报:“黄忠、魏延和川将吴兰、雷铜交锋,城中吴懿、刘璝又引兵助战,两下夹攻,我军抵敌不住,魏、黄二将败阵投东去了。”张飞听得,便请玄德分兵两路,杀去救援。于是张飞在左,玄德在右,杀奔前来。吴懿、刘璝见后面喊声起,慌退入城中。吴兰、雷铜只顾引兵追赶黄忠、魏延,却被玄德、张飞截住归路。黄忠、魏延又回马转攻。吴兰、雷铜料敌不住,只得将本部军马前来投降。玄德准其降,收兵近城下寨。却设张任失了二将,心中忧虑。吴懿、刘璝曰:“兵势甚危,不决一死战,如何得兵退?一面差人去成都见主公告急,一面用计敌之。”张任曰:“吾来日领一军搦战,诈败,引转城北;城内再以一军冲出,截断其中:可获胜也。”吴懿曰:“刘将军相辅公子守城,我引兵冲出助战。”约会已定。次日,张任引数千人马,摇旗呐喊,出城搦战。张飞上马出迎,更不打话,与张任交锋。战不十余合,张任诈败,绕城而走。张飞尽力追之。吴懿一军截住,张任引军复回,把张飞围在垓心,进退不得。正没奈何,只见一队军从江边杀出。当先一员大将,挺枪跃马,与吴懿交锋;只一合,生擒吴懿,战退敌军,救出张飞。视之,乃赵云也。飞问:“军师何在?”云曰:“军师已至,想此时已与主公相见了也。”二人擒吴懿回寨。张任自退入东门去了。 @@ -1183,7 +1183,7 @@ 方看真主来西蜀,又见精兵出汉中。 未知其人是谁,且看下文分解。 (本章完) -第65章 马超大战葭萌关 刘备自领益州牧 +第65章 马超大战葭萌关 刘备自领益州牧   却说阎圃正劝张鲁勿助刘璋,只见马超挺身出曰:“超感主公之恩,无可上报,愿领一军攻取葭萌关,生擒刘备,务要刘璋割二十州奉还主公。”张鲁大喜,先遣黄权从小路而回,随即点兵二万与马超。此时庞德卧病不能行,留于汉中。张鲁令杨柏监军,超与弟马岱选日起程。 却说玄德军马在雒城,法正所差下书人回报说:“郑度劝刘璋尽烧野谷并各处仓廪,率巴西之民,避于涪水西,深沟高垒而不战。”玄德、孔明闻之,皆大惊曰:“若用此言,吾势危矣!”法正笑曰:“主公勿忧。此计虽毒,刘璋必不能用也。”不一日,人传刘璋不肯迁动百姓,不从郑度之言。玄德闻之,方始宽心。孔明曰:“可速进兵取绵竹。如得此处,成都易取矣。”遂遣黄忠、魏延领兵前进。费观听知玄德兵来,差李严出迎。严领三千兵也,各布阵完。黄忠出马,与李严战四五十合,不分胜败。孔明在阵中教鸣金收军。 黄忠回阵,问曰:“正待要擒李严,军师何故收兵?”孔明曰:“吾已见李严武艺,不可力取。来日再战,汝可诈败,引入山峪,出奇兵以胜之。”黄忠领计。次日,李严再引兵来,黄忠又出战,不十合诈败,引兵便走。李严赶来,迤逦赶入出峪,猛然省悟。急待回来,前面魏延引兵摆开。孔明自在山头,唤曰:“公如不降,两下已伏强弩,欲与吾庞士元报仇矣。”李严慌下马卸甲投降。军士不曾伤害一人。孔明引李严见玄德。玄德待之甚厚。严曰:“费观虽是刘盖州亲戚,与某甚密,当往说之。”玄德即命李严回城招降费观。严入绵竹城,对费观赞玄德如此仁德;今若不降,必有大祸。观从其言,开门投降。玄德遂入绵竹,商议分兵取成都。 @@ -1204,7 +1204,7 @@ 却说东吴孙权,知玄德并吞西川,将刘璋逐于公安,遂召张昭、顾雍商议曰:“当初刘备借我荆州时,说取了西川,便还荆州。今已得巴蜀四十一州,须用取索汉上诸郡。如其不还,即动干戈。”张昭曰:“吴中方宁,不可动兵。昭有一计,使刘备将荆州双手奉还主公。”正是:西蜀方开新日月,东吴又索旧山川。 未知其计如何,且看下文分解。 (本章完) -第66章 关云长单刀赴会 伏皇后为国捐生 +第66章 关云长单刀赴会 伏皇后为国捐生   却说孙权要索荆州。张昭献计曰:“刘备所倚仗者,诸葛亮耳。其兄诸葛瑾今仕于吴,何不将瑾老小执下,使瑾入川告其弟,令劝刘备交割荆州:‘如其不还,必累及我老小。’亮念同胞之情,必然应允。”权曰:“诸葛瑾乃诚实君子,安忍拘其老小?”昭曰:“明教知是计策,自然放心。”权从之,召诸葛瑾老小,虚监在府;一面修书,打发诸葛瑾往西川去。 不致日,早到成都,先使人报知玄德。玄德问孔明曰:“令兄此来为何?”孔明曰:“来索荆州耳。”玄德曰:“何以答之?”孔明曰:“只须如此如此。”计会已定,孔明出郭接瑾。不到私宅,径入宾馆。参拜毕,瑾放声大哭。亮曰:“兄长有事但说。何故发哀?”瑾曰:“吾一家老小休矣!”亮曰:“莫非为不还荆州乎?因弟之故,执下兄长老小,弟心何安?兄休忧虑,弟自有计还荆州便了。” 瑾大喜,即同孔明入见玄德,呈上孙权书。玄德看了,怒曰:“孙权既以妹嫁我,却乘我不在荆州,竟将妹子潜地取去,情理难容!我正要大起川兵,杀下江南,报我之恨,却还想来索荆州乎!”孔明哭拜于地,曰:“吴侯执下亮兄长老小,倘若不还,吾兄将全家被戮。兄死,亮岂能独生?望主公看亮之面,将荆州还了东吴,全亮兄弟之情!”玄德再三不肯,孔明只是哭求。玄德徐徐曰:“既如此,看军师面,分荆州一半还之:将长沙、零陵、桂阳三郡与他。”亮曰:“既蒙见允,便可写书与云长令交割三郡。”玄德曰:“子瑜到彼,须用善言求吾弟。吾弟性如烈火,吾尚惧之。切宜仔细。” @@ -1224,7 +1224,7 @@ 此时曹操威势日甚。会大臣商议收吴灭蜀之事。贾诩曰:“须召夏侯惇、曹仁二人回,商议此事。”操即时发使,星夜唤回。夏侯惇未至,曹仁先到,连夜便入府中见操。操方被酒而卧,许褚仗剑立于堂门之内,曹仁欲入,被许褚当住。曹仁大怒曰:“吾乃曹氏宗族,汝何敢阻当耶?”许褚曰:“将军虽亲,乃外藩镇守之官;许褚虽疏,现充内侍。主公醉卧堂上,不敢放入。”仁乃不敢入。曹操闻之,叹曰:“许褚真忠臣也!”不数日,夏侯惇亦至,共议征伐。惇曰:“吴、蜀急未可攻,宜先取汉中张鲁,以得胜之兵取蜀,可一鼓而下也。”曹操曰:“正合吾意。”遂起兵西征。正是:方逞凶谋欺弱主,又驱劲卒扫偏邦。 未知后事如何,且看下文分解。 (本章完) -第67章 曹操平定汉中地 张辽威震逍遥津 +第67章 曹操平定汉中地 张辽威震逍遥津   却说曹操兴师西征,分兵三队:前部先锋夏侯渊;张郃;操自领诸将居中;后部曹仁、夏侯惇,押运粮草。早有细作报入汉中来。张鲁与弟张卫,商议退敌之策。卫曰:“汉中最险无如阳平关;可于关之左右,依山傍林,下十余个寨栅,迎敌曹兵。兄在汉宁,多拨粮草应付。”张鲁依言,遣大将杨昂、杨任,与其弟即日起程。军马到阳平关,下寨已定。夏侯渊、张郃前军随到,闻阳平关已有准备,离关一十五里下寨。是夜,军士疲困,各自歇息。忽寨后一把火起,杨昂、杨任两路兵杀来劫寨。夏侯渊、张郃急上得马,四下里大兵拥入,曹兵大败,退见曹操。操怒曰:“汝二人行军许多年,岂不知兵若远行疲困,可防劫寨?如何不作准备?”欲斩二人,以明军法。众官告免。 操次日自引兵为前队,见山势险恶,林木丛杂,不知路径,恐有伏兵,即引军回寨,谓许褚、徐晃二将曰:“吾若知此处如此险恶,必不起兵来。”许褚曰:“兵已至此,主公不可惮劳。”次日,操上马,只带许褚、徐晃二人,来看张卫寨栅。三匹马转过山坡,早望见张卫寨栅。操扬鞭遥指,谓二将曰:“如此坚固,急切难下!”言未已,背后一声喊起,箭如雨发。杨昂、杨任分两路杀来。操大惊。许褚大呼曰:“吾当敌贼!徐公明善保主公。”说罢,提刀纵马向前,力敌二将。杨昂、杨任不能当许褚之勇,回马退去,其余不敢向前。徐晃保着曹操奔过山坡,前面又一军到;看时,却是夏侯渊;张郃二将,听得喊声,故引军杀来接应。于是杀退杨昂、杨任,救得曹操回寨。操重赏四将。 自此两边相拒五十余日,只不交战。曹操传令退军。贾诩曰:“贼势未见强弱,主公何故自退耶?”操曰:“吾料贼兵每日提备,急难取胜。吾以退军为名,使贼懈而无备,然后分轻骑抄袭其后,必胜贼矣。”贾诩曰:“丞相神机,不可测也。”于是令夏侯渊;张郃分兵两路,各引轻骑三千,取小路抄阳平关后。曹操一面引大军拔寨尽起。杨昂听得曹兵退,请杨任商议,欲乘势击之。杨任曰:“操诡计极多,未知真实,不可追赶。”杨昂曰:“公不往,吾当自去。”杨任苦谏不从。杨昂尽提五寨军马前进,只留些少军士守寨。 @@ -1240,7 +1240,7 @@ 却说孙权令吕蒙、甘宁为前队,自与凌统居中,其余诸将陆续进发,望合淝杀来。吕蒙、甘宁前队兵进,正与乐进相迎。甘宁出马与乐进交锋,战不数合,乐进诈败而走。甘宁招呼吕蒙一齐引军赶去。孙权在第二队,听得前军得胜,催兵行至逍遥津北,忽闻连珠炮响,左边张辽一军杀来,右边李典一军杀来。孙权大惊,急令人唤吕蒙、甘宁回救时,张辽兵已到。凌统手下,止有三百余骑,当不得曹军势如山倒。凌统大呼曰:“主公何不速渡小师桥!”言未毕,张辽引二千余骑,当先杀至。凌统翻身死战。孙权纵马上桥,桥南已折丈余,并无一片板。孙权惊得手足无措。牙将谷利大呼曰:“主公可约马退后,再放马向前,跳过桥去。”孙权收回马来有三丈余远,然后纵辔加鞭,那马一跳飞过桥南。后人有诗曰:“的卢当日跳檀溪,又见吴侯败合淝。退后着鞭驰骏骑,逍遥津上玉龙飞。”孙权跳过桥南,徐盛、董袭驾舟相迎。凌统、谷利抵住张辽。甘宁、吕蒙引军回救,却被乐进从后追来,李典又截住厮杀,吴兵折了大半。凌统所领三百余人,尽被杀死。统身中数枪,杀到桥边,桥已折断,绕河而逃。孙权在舟中望见,急令董袭棹舟接之,乃得渡回。吕蒙、甘宁皆死命逃过河南。这一阵杀得江南人人害怕;闻张辽大名,小儿也不敢夜啼。众将保护孙权回营。权乃重赏凌统、谷利,收军回濡须,整顿船只,商议水陆并进;一面差人回江南,再起人马来助战。却说张辽闻孙权在濡须将欲兴兵进取,恐合淝兵少难以抵敌,急令薛悌星夜往汉中,报知曹操,求请救兵。操同众官议曰:“此时可收西川否?”刘晔曰:“今蜀中稍定,已有提备,不可击也。不如撤兵去救合淝之急,就下江南。”操乃留夏侯渊守汉中定军山隘口,留张郃守蒙头岩等隘口。其余军兵拔寨都起,杀奔濡须坞来。正是:铁骑方能平陇右,旌旄又复指江南。 未知胜负如何,且看下文分解。 (本章完) -第68章 甘宁百骑劫魏营 左慈掷杯戏曹操 +第68章 甘宁百骑劫魏营 左慈掷杯戏曹操   却说孙权在濡须口收拾军马,忽报曹操自汉中领兵四十万前来救合淝。孙权与谋士计议,先拨董袭、徐盛二人领五十只大船,在濡须口埋伏;令陈武带领人马,往来江岸巡哨。张昭曰:“今曹操远来,必须先挫其锐气。”权乃问帐下曰:“曹操远来,谁敢当先破敌,以挫其锐气?”凌统出曰:“某愿往。”权曰:“带多少军去?”统曰:“三千人足矣。”甘宁曰:“只须百骑,便可破敌,何必三千!”凌统大怒。两个就在孙权面前争竞起来。权曰:“曹军势大,不可轻敌。”乃命凌统带三千军出濡须口去哨探,遇曹兵,便与交战。凌统领命,引着三千人马,离濡须坞。尘头起处,曹兵早到。先锋张辽与凌统交锋,斗五十合,不分胜败。孙权恐凌统有失,令吕蒙接应回营。甘宁见凌统回,即告权曰:“宁今夜只带一百人马去劫曹营;若折了一人一骑,也不算功。”孙权壮之,乃调拨帐下一百精锐马兵付宁;又以酒五十瓶,羊肉五十斤,赏赐军士。甘宁回到营中,教一百人皆列坐,先将银碗斟酒,自吃两碗,乃语百人曰:“今夜奉命劫寨,请诸公各满饮一觞,努力向前。”众人闻言,面面相觑。 甘宁见众人有难色,乃拔剑在手,怒叱曰:“我为上将,且不惜命;汝等何得迟疑!”众人见甘宁作色,皆起拜曰:“愿效死力。”甘宁将酒肉与百人共饮食尽,约至二更时候取白鹅翎一百根,插于盔上为号;都披甲上马,飞奔曹操寨边,拔开鹿角,大喊一声,杀入寨中,径奔中军来杀曹操。原来中军人马,以车仗伏路穿连,围得铁桶相似,不能得进。甘宁只将百骑,左冲右突。曹兵惊慌,正不知敌兵多少,自相扰乱。那甘宁百骑,在营内纵横驰骤,逢着便杀。各营鼓噪,举火如星,喊声大震。甘宁从寨之南门杀出,无人敢当。孙权令周泰引一枝兵来接应。甘宁将百骑回到濡须。操兵恐有埋伏,不敢追袭。后人有诗赞曰:“鼙鼓声喧震地来,吴师到处鬼神哀!百翎直贯曹家寨,尽说甘宁虎将才。”甘宁引百骑到寨,不折一人一骑;至营门,令百人皆击鼓吹笛,口称“万岁”,欢声大震。孙权自来迎接。甘宁下马拜伏。权扶起,携宁手曰:“将军此去,足使老贼惊骇。非孤相舍,正欲观卿胆耳!”即赐绢千匹,利刀百口。宁拜受讫,遂分赏百人。权语诸将曰:“孟德有张辽,孤有甘兴霸,足以相敌也。” 次日,张辽引兵搦战。凌统见甘宁有功,奋然曰:“统愿敌张辽。”权许之。统遂领兵五千,离濡须。权自引甘宁临阵观战。对阵圆处,张辽出马,左有李典,右有乐进。凌统纵马提刀,出至阵前。张辽使乐进出迎。两个斗到五十合,未分胜败。曹操闻知,亲自策马到门旗下来看,见二将酣斗,乃令曹休暗放冷箭。曹休便闪在张辽背后,开弓一箭,正中凌统坐下马,那马直立起来,把凌统掀翻在地。乐进连忙持枪来刺。枪还未到,只听得弓弦响处,一箭射中乐进面门,翻身落马。两军齐出,各救一将回营,鸣金罢战。凌统回寨中拜谢孙权。权曰:“放箭救你者,甘宁也。”凌统乃顿首拜宁曰:“不想公能如此垂恩!”自此与甘宁结为生死之交,再不为恶。且说曹操见乐进中箭,令自到帐中调治。次日,分兵五路来袭濡须:操自领中路;左一路张辽,二路李典;右一路徐晃,二路庞德。每路各带一万人马,杀奔江边来。时董袭、徐盛二将,在楼船上见五路军马来到,诸军各有惧色。徐盛曰:“食君之禄,忠君之事,何惧哉!”遂引猛士数百人,用小船渡过江边,杀入李典军中去了。董袭在船上,令众军擂鼓呐喊助威。忽然江上猛风大作,白浪掀天,波涛汹涌。军士见大船将覆,争下脚舰逃命。董袭仗剑大喝曰:“将受君命,在此防贼,怎敢弃船而去!”立斩下船军士十余人。须臾,风急船覆,董袭竟死于江口水中。徐盛在李典军中,往来冲突。 @@ -1258,7 +1258,7 @@ 小童归告主人,主人不敢隐讳,报知曹操。操画影图形,各处捉拿左慈。三日之内,城里城外,所捉眇一目、跛一足、白藤冠、青懒衣、穿木履先生,都一般模样者,有三四百个。哄动街市。操令众将,将猪羊血泼之,押送城南教场。曹操亲自引甲兵五百人围住,尽皆斩之。人人颈腔内各起一道青气,到上天聚成一处,化成一个左慈,向空招白鹤一只骑坐,拍手大笑曰:“土鼠随金虎,奸雄一旦休!”操令众将以弓箭射之。忽然狂风大作,走石扬沙;所斩之尸,皆跳起来,手提其头,奔上演武厅来打曹操。文官武将,掩面惊倒,各不相顾。正是:奸雄权势能倾国,道士仙机更异人。 未知曹操性命如何,且看下文分解。 (本章完) -第69章 卜周易管辂知机 讨汉贼五臣死节 +第69章 卜周易管辂知机 讨汉贼五臣死节   却说当日曹操见黑风中群尸皆起,惊倒于地。须臾风定,群尸皆不见。左右扶操回宫,惊而成疾。后人有诗赞左慈曰:“飞步凌云遍九州,独凭遁甲自遨游。等闲施设神仙术,点悟曹瞒不转头。” 曹操染病,服药无愈。适太史丞许芝,自许昌来见操。操令芝卜易。芝曰:“大王曾闻神卜管辂否?”操曰:“颇闻其名,未知其术。汝可详言之。”芝曰:“管辂字公明,平原人也。容貌粗丑,好酒疏狂。其父曾为琅琊即丘长。辂自幼便喜仰视星辰,夜不肯寐,父母不能禁止。常云家鸡野鹄,尚自知时,何况为人在世乎?与邻儿共戏,辄画地为天文,分布日月星辰。及稍长,即深明《周易》,仰观风角,数学通神,兼善相术。琅琊太守单子春闻其名,召辂相见。时有坐客百余人,皆能言之士。辂谓子春曰:辂年少胆气未坚,先请美酒三升,饮而后言。子春奇之,遂与酒三升。饮毕,辂问子春:今欲与辂为对者,若府君四座之士耶?子春曰:吾自与卿旗鼓相当。于是与辂讲论易理。辂亹亹而谈,言言精奥。子春反覆辩难,辂对答如流。从晓至暮,酒食不行。子春及众宾客,无不叹服。于是天下号为神童。 后有居民郭恩者,兄弟三人,皆得躄疾,请辂卜之。辂曰:卦中有君家本墓中女鬼,非君伯母即叔母也。昔饥荒之年,谋数升米之利,推之落井,以大石压破其头,孤魂痛苦,自诉于天,故君兄弟有此报。不可禳也。郭恩等涕泣伏罪。安平太守王基,知辂神卜,延辂至家。适信都令妻常患头风,其子又患心痛,因请辂卜之。辂曰:此堂之西角有二死尸:一男持矛,一男持弓箭。头在壁内,脚在壁外。持矛者主刺头,故头痛;持弓箭者主刺胸腹,故心痛。乃掘之。入地八尺,果有二棺。一棺中有矛,一棺中有角弓及箭,木俱已朽烂。辂令徙骸骨去城外十里埋之,妻与子遂无恙。馆陶令诸葛原,迁新兴太守,辂往送行。客言辂能覆射。 @@ -1274,7 +1274,7 @@ 却说曹洪领兵到汉中,令张郃、夏侯渊各据险要。曹洪亲自进兵拒敌。时张飞自与雷铜守把巴西。马超兵至下辨,令吴兰为先锋,领军哨出,正与曹洪军相遇。吴兰欲退,牙将任夔曰:“贼兵初至,若不先挫其锐气,何颜见孟起乎?”于是骤马挺枪搦曹洪战。洪自提刀跃马而出。交锋三合,斩夔于马下,乘势掩杀。吴兰大败,回见马超。超责之曰:“汝不得吾令,何故轻敌致败?”吴兰曰:“任夔不听吾言,故有此败?”马超曰:“可紧守隘口,勿与交锋。”一面申报成都,听候行止。曹洪见马超连日不出,恐有诈谋,引军退回南郑。张郃来见曹洪,问曰:“将军既已斩将,如何退兵?”洪曰:“吾见马超不出,恐有别谋。且我在邺都,闻神卜管辂有言:当于此地折一员大将。吾疑此言,故不敢轻进。”张郃大笑曰:“将军行兵半生,今奈何信卜者之言而惑其心哉!郃虽不才,愿以本部兵取巴西。若得巴西,蜀郡易耳。”洪曰:“巴西守将张飞,非比等闲,不可轻敌。”张郃曰:“人皆怕张飞,吾视之如小儿耳!此去必擒之!”洪曰:“倘有疏失,若何?”郃曰:“甘当军令。”洪勒了文状,张郃进兵。正是:自古骄兵多致败,从来轻敌少成功。 未知胜负如何,且看下文分解。 (本章完) -第70章 猛张飞智取瓦口隘 老黄忠计夺天荡山 +第70章 猛张飞智取瓦口隘 老黄忠计夺天荡山   却说张郃部兵三万,分为三寨,各傍山险:一名宕渠寨,一名蒙头寨。一名荡石寨。当日张郃于三寨中,各分军一半去取巴西,留一半守寨。早有探马报到巴西,说张郃引兵来了。张飞急唤雷铜商议。铜曰:“阆中地恶山险,可以埋伏。将军引兵出战,我出奇兵相助,郃可擒矣。”张飞拨精兵五千与雷铜去讫。飞自引兵一万,离阆中三十里,与张郃兵相遇。两军摆开,张飞出马,单搦张郃。郃挺枪纵马而出。战到二十余合,郃后军忽然喊起:原来望见山背后有蜀兵旗幡,故此扰乱。张郃不敢恋战,拨马回走。张飞从后掩杀。前面雷铜又引兵杀出。两下夹攻,郃兵大败。张飞、雷铜连夜追袭,直赶到宕渠山。张郃仍旧分兵守住三寨,多置擂木炮石,坚守不战。张飞离宕渠十里下寨,次日引兵搦战。郃在山上大吹大擂饮酒,并不下山。张飞令军士大骂,郃只不出。飞只得还营。次日,雷铜又去山下搦战,郃又不出。雷铜驱军士上山,山上擂木炮石打将下来。雷铜急退。荡石、蒙头两寨兵出,杀败雷铜。次日,张飞又去搦战,张郃又不出。飞使军人百般秽骂,郃在山上亦骂。张飞寻思,无计可施。相拒五十余日,飞就在山前扎住大寨,每日饮酒;饮至大醉,坐于山前辱骂。 玄德差人犒军,见张飞终日饮酒,使者回报玄德。玄德大惊,忙来问孔明。孔明笑曰:“原来如此!军前恐无好酒;成都佳酿极多,可将五十瓮作三车装,送到军前与张将军饮。”玄德曰:“吾弟自来饮酒失事,军师何故反送酒与他?”孔明笑曰:“主公与翼德做了许多年兄弟,还不知其为人耶?翼德自来刚强,然前于收川之时,义释严颜,此非勇夫所为也。今与张郃相拒五十余日,酒醉之后,便坐山前辱骂,傍若无人:此非贪杯,乃败张郃之计耳。”玄德曰:“虽然如此,未可托大。可使魏延助之。”孔明令魏延解酒赴军前,车上各插黄旗,大书“军前公用美酒”。魏延领命,解酒到寨中,见张飞,传说主公赐酒。飞拜受讫,分付魏延、雷铜各引一枝人马,为左右翼;只看军中红旗起,便各进兵;教将酒摆列帐下,令军士大开旗鼓而饮。有细作报上山来,张郃自来山顶观望,见张飞坐于帐下饮酒,令二小卒于面前相扑为戏。 郃曰:“张飞欺我太甚!”传令今夜下山劫飞寨,令蒙头、荡石二寨,皆出为左右援。当夜张郃乘着月色微明,引军从山侧而下,径到寨前。遥望张飞大明灯烛,正在帐中饮酒。张郃当先大喊一声,山头擂鼓为助,直杀入中军。但见张飞端坐不动。张郃骤马到面前,一枪刺倒,却是一个草人。急勒马回时,帐后连珠炮起。一将当先,拦住去路,睁圆环眼,声如巨雷:乃张飞也。挺矛跃马,直取张郃。两将在火光中,战到三五十合。张郃只盼两寨来救,谁知两寨救兵,已被魏延,雷铜两将杀退,就势夺了二寨。张郃不见救兵至,正没奈何,又见山上火起,已被张飞后军夺了寨栅。张郃三寨俱失,只得奔瓦口关去了。张飞大获胜捷,报入成都。玄德大喜,方知翼德饮酒是计,只要诱张郃下山。却说张郃退守瓦口关,三万军已折了二万,遣人问曹洪求救。洪大怒曰:“汝不听吾言,强要进兵,失了紧要隘口,却又来求救!”遂不肯发兵,使人催督张郃出战。 @@ -1294,7 +1294,7 @@ 但今汉中定军山,乃南郑保障,粮草积聚之所;若得定军山,阳平一路,无足忧矣。将军还敢取定军山否?黄忠慨然应诺,便要领兵前去。孔明急止之曰:“老将军虽然英勇,然夏侯渊非张郃之比也。渊深通韬略,善晓兵机,曹操倚之为西凉藩蔽:先曾屯兵长安,拒马孟起;今又屯兵汉中。操不托他人,而独托渊者,以渊有将才也。今将军虽胜张郃,未卜能胜夏侯渊。吾欲酌量着一人去荆州,替回关将军来,方可敌之。”忠奋然答曰:“昔廉颇年八十,尚食斗米、肉十斤,诸侯畏其勇,不敢侵犯赵界,何况黄忠未及七十乎?军师言吾老,吾今并不用副将,只将本部兵三千人去,立斩夏侯渊首级,纳于麾下。”孔明再三不容。黄忠只是要去。孔明曰:“既将军要去,吾使一人为监军同去,若何?”正是:请将须行激将法,少年不若老年人。 未知其人是谁,且看下文分解。 (本章完) -第71章 占对山黄忠逸待劳 据汉水赵云寡胜众 +第71章 占对山黄忠逸待劳 据汉水赵云寡胜众   却说孔明吩咐黄忠:“你既要去,吾教法正助你。凡事计议而行。吾随后拨人马来接应。”黄忠应允,和法正领本部兵去了。孔明告玄德曰:“此老将不着言语激他,虽去不能成功。他今既去,须拨人马前去接应。”乃唤赵云:“将一枝人马,从小路出奇兵接应黄忠:若忠胜,不必出战;倘忠有失,即去救应。”又遣刘封、孟达:“领三千兵于山中险要去处,多立旌旗,以壮我兵之声势,令敌人惊疑。”三人各自领兵去了。又差人往下辨,授计与马超,令他如此而行。又差严颜往巴西阆中守隘,替张飞、魏延来同取汉中。 却说张郃与夏侯尚来见夏侯渊,说:“天荡山已失,折了夏侯德、韩浩。今闻刘备亲自领兵来取汉中,可速奏魏王,早发精兵猛将,前来策应。”夏侯渊便差人报知曹洪。洪星夜前到许昌,禀知曹操。操大惊,急聚文武,商议发兵救汉中。长史刘晔进曰:“汉中若失,中原震动。大王休辞劳苦,必须亲自征讨。”操自悔曰:“恨当时不用卿言,以致如此!”忙传令旨,起兵四十万亲征。时建安二十三年秋七月也。 曹操兵分三路而进:前部先锋夏侯惇,操自领中军,使曹休押后,三军陆续起行。操骑白马金鞍,玉带锦衣;武士手执大红罗销金伞盖,左右金瓜银钺,镫棒戈矛,打日月龙凤旌旗;护驾龙虎官军二万五千,分为五队,每队五千,按青、黄、赤、白、黑五色,旗幡甲马,并依本色:光辉灿烂,极其雄壮。兵出潼关,操在马上望见一簇林木,极其茂盛,问近侍曰:“此何处也?”答曰:“此名蓝田。林木之间,乃蔡邕庄也。今邕女蔡琰,与其夫董祀居此。”原来操素与蔡邕相善。先时其女蔡琰,乃卫仲道之妻;后被北方掳去,于北地生二子,作《胡笳十八拍》,流入中原。操深怜之,使人持千金入北方赎之。左贤王惧操之势,送蔡琰还汉。操乃以琰配与董祀为妻。当日到庄前,因想起蔡邕之事,令军马先行,操引近侍百余骑,到庄门下马。时董祀出仕于外,止有蔡琰在家,琰闻操至,忙出迎接。 @@ -1313,7 +1313,7 @@ 玄德大喜,看了山前山后险峻之路,欣然谓孔明曰:“子龙一身都是胆也!”后人有诗赞曰:“昔日战长坂,威风犹未减。突阵显英雄,被围施勇敢。鬼哭与神号,天惊并地惨。常山赵子龙,一身都是胆!”于是玄德号子龙为虎威将军,大劳将士,欢宴至晚。忽报曹操复遣大军从斜谷小路而进,来取汉水。玄德笑曰:“操此来无能为也。我料必得汉水矣。”乃率兵于汉水之西以迎之。曹操命徐晃为先锋,前来决战。帐前一人出曰:“某深知地理,愿助徐将军同去破蜀。”操视之,乃巴西宕渠人也,姓王,名平,字子均;现充牙门将军。操大喜,遂命王平为副先锋,相助徐晃。操屯兵于定军山北。徐晃、王平引军至汉水,晃令前军渡水列阵。平曰:“军若渡水,倘要急退,如之奈何?”晃曰:“昔韩信背水为阵,所谓致之死地而后生也。”平曰:“不然。昔者韩信料敌人无谋而用此计;今将军能料赵云、黄忠之意否?”晃曰:“汝可引步军拒敌,看我引马军破之。”遂令搭起浮桥,随即过河来战蜀兵。正是:魏人妄意宗韩信,蜀相那知是子房。 未知胜负如何,且看下文分解。 (本章完) -第72章 诸葛亮智取汉中 曹阿瞒兵退斜谷 +第72章 诸葛亮智取汉中 曹阿瞒兵退斜谷   却说徐晃引军渡汉水,王平苦谏不听,渡过汉水扎营。黄忠、赵云告玄德曰:“某等各引本部兵去迎曹兵。”玄德应允。二人引兵而行。忠谓云曰:“今徐晃恃勇而来,且休与敌;待日暮兵疲,你我分兵两路击之可也。”云然之,各引一军据住寨栅。徐晃引兵从辰时搦战,直至申时,蜀兵不动。晃尽教弓弩手向前,望蜀营射去。黄忠谓赵云曰:“徐晃令弓弩射者,其军必将退也:可乘时击之。”言未已,忽报曹兵后队果然退动。于是蜀营鼓声大震:黄忠领兵左出,赵云领兵右出。两下夹攻,徐晃大败,军士逼入汉水,死者无数。晃死战得脱,回营责王平曰:“汝见吾军势将危,如何不救?”平曰:“我若来救,此寨亦不能保。我曾谏公休去,公不肯所,以致此败。”晃大怒,欲杀王平。平当夜引本部军就营中放起火来,曹兵大乱,徐晃弃营而走。王平渡汉水来投赵云,云引见玄德。王平尽言汉水地理。 玄德大喜曰:“孤得王子均,取汉中无疑矣。”遂命王平为偏将军,领向导使。却说徐晃逃回见操,说:“王平反去降刘备矣!”操大怒,亲统大军来夺汉水寨栅。赵云恐孤军难立,遂退于汉水之西。两军隔水相拒,玄德与孔明来观形势。孔明见汉水上流头,有一带土山,可伏千余人;乃回到营中,唤赵云分付:“汝可引五百人,皆带鼓角,伏于土山之下;或半夜,或黄昏,只听我营中炮响:炮响一番,擂鼓一番。只不要出战。”子龙受计去了。孔明却在高山上暗窥。次日,曹兵到来搦战,蜀营中一人不出,弓弩亦都不发。曹兵自回。当夜更深,孔明见曹营灯火方息,军士歇定,遂放号炮。子龙听得,令鼓角齐鸣。曹兵惊慌,只疑劫寨。及至出营,不见一军。方才回营欲歇,号炮又响,鼓角又鸣,呐喊震地,山谷应声。曹兵彻夜不安。一连三夜,如此惊疑,操心怯,拔寨退三十里,就空阔处扎营。孔明笑曰:“曹操虽知兵法,不知诡计。”遂请玄德亲渡汉水,背水结营。玄德问计,孔明曰:“可如此如此。” 曹操见玄德背水下寨,心中疑惑,使人来下战书。孔明批来日决战。次日,两军会于中路五界山前,列成阵势。操出马立于门旗下,两行布列龙凤旌旗,擂鼓三通,唤玄德答话。玄德引刘封、孟达并川中诸将而出。操扬鞭大骂曰:“刘备忘恩失义,反叛朝廷之贼!”玄德曰:“吾乃大汉宗亲,奉诏讨贼。汝上弑母后,自立为王,僭用天子銮舆,非反而何?”操怒,命徐晃出马来战,刘封出迎。交战之时,玄德先走入阵。封敌晃不住,拨马便走。操下令:“捉得刘备,便为西川之主。”大军齐呐喊杀过阵来。蜀兵望汉水而逃,尽弃营寨;马匹军器,丢满道上。曹军皆争取。操急鸣金收军。众将曰:“某等正待捉刘备,大王何故收军?”操曰:“吾见蜀兵背汉水安营,其可疑一也;多弃马匹军器,其可疑二也。可急退军,休取衣物。”遂下令曰:“妄取一物者立斩。火速退兵。”曹兵方回头时,孔明号旗举起:玄德中军领兵便出,黄忠左边杀来,赵云右边杀来。曹兵大溃而逃,孔明连夜追赶。 @@ -1328,7 +1328,7 @@ 曹操既杀杨修,佯怒夏侯惇,亦欲斩之。众官告免。操乃叱退夏侯惇,下令来日进兵。次日,兵出斜谷界口,前面一军相迎,为首大将乃魏延也。操招魏延归降,延大骂。操令庞德出战。二将正斗间,曹寨内火起。人报马超劫了中后二寨。操拔剑在手曰:“诸将退后者斩!”众将努力向前,魏延诈败而走。操方麾军回战马超,自立马于高阜处,看两军争战。忽一彪军撞至面前,大叫:“魏延在此!”拈弓搭箭,射中曹操。操翻身落马。延弃弓绰刀,骤马上山坡来杀曹操。刺斜里闪出一将,大叫:“休伤吾主!”视之,乃庞德也。德奋力向前,战退魏延,保操前行。马超已退。操带伤归寨:原来被魏延射中人中,折却门牙两个,急令医士调治。方忆杨修之言,随将修尸收回厚葬,就令班师;却教庞德断后。操卧于毡车之中,左右虎贲军护卫而行。忽报斜谷山上两边火起,伏兵赶来。曹兵人人惊恐。正是:依稀昔日潼关厄,仿佛当年赤壁危。 未知曹操性命如何,且看下文分解。 (本章完) -第73章 玄德进位汉中王 云长攻拔襄阳郡 +第73章 玄德进位汉中王 云长攻拔襄阳郡   却说曹操退兵至斜谷,孔明料他必弃汉中而走,故差马超等诸将,分兵十数路,不时攻劫。因此操不能久住;又被魏延射了一箭,急急班师。三军锐气堕尽。前队才行,两下火起,乃是马超伏兵追赶。曹兵人人丧胆。操令军士急行,晓夜奔走无停;直至京兆,方始安心。 且说玄德命刘封、孟达、王平等,攻取上庸诸郡,申耽等闻操已弃汉中而走,遂皆投降,玄德安民已定,大赏三军,人心大悦。于是众将皆有推尊玄德为帝之心;未敢径启,却来禀告诸葛军师,孔明曰:“吾意已有定夺了。”随引法正等入见玄德,曰:“今曹操专权,百姓无主;主公仁义著于天下,今已抚有两川之地,可以应天顺人,即皇帝位,名正言顺,以讨国贼。事不宜迟,便请择吉。”玄德大惊曰:“军师之言差矣。刘备虽然汉之宗室,乃臣子也;若为此事,是反汉矣。”孔明曰:“非也。 方今天下分崩,英雄并起,各霸一方,四海才德之士,舍死亡生而事其上者,皆欲攀龙附凤,建立功名也。今主公避嫌守义,恐失众人之望。愿主公熟思之。”玄德曰:“要吾僭居尊位,吾必不敢。可再商议长策。”诸将齐言曰:“主公若只推却,众心解矣。”孔明曰:“主公平生以义为本,未肯便称尊号。今有荆襄、两川之地,可暂为汉中王。”玄德曰:“汝等虽欲尊吾为王,不得天子明诏,是僭也。”孔明曰:“今宜从权,不可拘执常理。”张飞大叫曰:“异姓之人,皆欲为君何况哥哥乃汉朝宗派!莫说汉中王,就称皇帝,有何不可!”玄德叱曰:“汝勿多言!”孔明曰:“主公宜从权变,先进位汉中王,然后表奏天子,未为迟也。” @@ -1348,7 +1348,7 @@ 却说曹仁折了二将,退守樊城,谓满宠曰:“不听公言,兵败将亡,失却襄阳,如之奈何?”宠曰:“云长虎将,足智多谋,不可轻敌,只宜坚守。”正言间,人报云长渡江而来,攻打樊城。仁大惊,宠曰:“只宜坚守。”部将吕常奋然曰:“某乞兵数千,愿当来军于襄江之内。”宠谏曰:“不可。”吕常怒曰:“据汝等文官之言,只宜坚守,何能退敌?岂不闻兵法云:军半渡可击。今云长军半渡襄江,何不击之?若兵临城下,将至壕边,急难抵当矣。”仁即与兵二千,令吕常出樊城迎战。吕常来至江口,只见前面绣旗开处,云长横刀出马。吕常却欲来迎,后面众军见云长神威凛凛,不战先走,吕常喝止不住。云长混杀过来,曹兵大败,马步军折其大半,残败军奔入樊城。曹仁急差人求救,使命星夜至长安,将书呈上曹操,言:“云长破了襄阳,现围樊城甚急。望拨大将前来救援。”曹操指班部内一人而言曰:“汝可去解樊城之围。”其人应声而出。众视之,乃于禁也。禁曰:“某求一将作先锋,领兵同去。”操又问众人曰:“谁敢作先锋?”一人奋然出曰:“某愿施犬马之劳,生擒关某,献于麾下。”操观之大喜。正是:未见东吴来伺隙,先看北魏又添兵。 未知此人是谁,且看下文分解。 (本章完) -第74章 庞令明抬榇决死战 关云长放水淹七军 +第74章 庞令明抬榇决死战 关云长放水淹七军   却说曹操欲使于禁赴樊城救援,问众将谁敢作先锋。一人应声愿往。操视之,乃庞德也。操大喜曰:“关某威震华夏,未逢对手;今遇令明,真劲敌也。”遂加于禁为征南将军,加宠德为征西都先锋,大起七军,前往樊城。这七军,皆北方强壮之士。两员领军将校:一名董衡,一名董超;当日引各头目参拜于禁。董衡曰:“今将军提七枝重兵,去解樊城之厄,期在必胜,乃用庞德为先锋,岂不误事?”禁惊问其故。衡曰:“庞德原系马超手下副将,不得已而降魏;今其故主在蜀,职居五虎上将;况其亲兄庞柔亦在西川为官,今使他为先锋,是泼油救火也。将军何不启知魏王,别换一人去?” 禁闻此语,遂连夜入府启知曹操。操省悟,即唤庞德至阶下,令纳下先锋印。德大惊曰:“某正欲与大王出力,何故不肯见用?”操曰:“孤本无猜疑;但今马超现在西川,汝兄庞柔亦在西川,俱佐刘备。孤纵不疑,奈众口何?”庞德闻之,免冠顿首,流血满面而告曰:“某自汉中投降大王,每感厚恩,虽肝脑涂地,不能补报;大王何疑于德也?德昔在故乡时,与兄同居,嫂甚不贤,德乘醉杀之;兄恨德入骨髓,誓不相见,恩已断矣。故主马超,有勇无谋,兵败地亡,孤身入川,今与德各事其主,旧义已绝。德感大王恩遇,安敢萌异志?惟大王察之。”操乃扶起庞德,抚慰曰:“孤素知卿忠义,前言特以安众人之心耳。卿可努力建功。卿不负孤,孤亦必不负卿也。”德拜谢回家,令匠人造一木榇。次日,请诸友赴席,列榇于堂。众亲友见之,皆惊问曰:“将军出师,何用此不祥之物?”德举杯谓亲友曰:“吾受魏王厚恩,誓以死报。 今去樊城与关某决战,我若不能杀彼,必为彼所杀;即不为彼所杀,我亦当自杀。故先备此榇,以示无空回之理。”众皆嗟叹。德唤其妻李氏与其子庞会出,谓其妻曰:“吾今为先锋,义当效死疆场。我若死,汝好生看养吾儿;吾儿有异相,长大必当与吾报仇也。”妻子痛哭送别,德令扶榇而行。临行,谓部将曰:“吾今去与关某死战,我若被关某所杀,汝等即取吾尸置此榇中;我若杀了关某,吾亦即取其首,置此榇内,回献魏王。”部将五百人皆曰:“将军如此忠勇,某等敢不竭力相助!”于是引军前进。有人将此言报知曹操。操喜曰:“庞德忠勇如此,孤何忧焉!”贾诩曰:“庞德恃血气之勇,欲与关某决死战,臣窃虑之。”操然其言,急令人传旨戒庞德曰:“关某智勇双全,切不可轻敌。可取则取,不可取则宜谨守。”庞德闻命,谓众将曰:“大王何重视关某也?吾料此去,当挫关某三十年之声价。”禁曰:“魏王之言,不可不从。”德奋然趱军前至樊城,耀武扬威,鸣锣击鼓。 @@ -1365,7 +1365,7 @@ 却说关公分兵一半,直抵郏下。公自领兵四面攻打樊城。当日关公自到北门,立马扬鞭,指而问曰:“汝等鼠辈,不早来降,更待何时?”正言间,曹仁在敌楼上,见关公身上止披掩心甲,斜袒着绿袍,乃急招五百弓弩手,一齐放箭。公急勒马回时,右臂上中一弩箭,翻身落马。正是:水里七军方丧胆,城中一箭忽伤身。 未知关公性命如何,且看下文分解。 (本章完) -第75章 关云长刮骨疗毒 吕子明白衣渡江 +第75章 关云长刮骨疗毒 吕子明白衣渡江   却说曹仁见关公落马,即引兵冲出城来;被关平一阵杀回,救关公归寨,拔出臂箭。原来箭头有药,毒已入骨,右臂青肿,不能运动。关平慌与众将商议曰:“父亲若损此臂,安能出敌?不如暂回荆州调理。”于是与众将入帐见关公。公问曰:“汝等来有何事?”众对曰:“某等因见君侯右臂损伤,恐临敌致怒,冲突不便。众议可暂班师回荆州调理。”公怒曰:“吾取樊城,只在目前;取了樊城,即当长驱大进,径到许都,剿灭操贼,以安汉室。岂可因小疮而误大事?汝等敢慢吾军心耶!”平等默然而退。 众将见公不肯退兵,疮又不痊,只得四方访问名医。忽一日,有人从江东驾小舟而来,直至寨前。小校引见关平。平视其人:方巾阔服,臂挽青囊;自言姓名,乃沛国谯郡人,姓华,名伦,字元化。因闻关将军乃天下英雄,今中毒箭,特来医治。平曰:“莫非昔日医东吴周泰者乎?”佗曰:“然。”平大喜,即与众将同引华佗入帐见关公。时关公本是臂疼,恐慢军心,无可消遣,正与马良弈棋;闻有医者至,即召入。礼毕,赐坐。茶罢,佗请臂视之。公袒下衣袍,伸臂令佗看视。佗曰:“此乃弩箭所伤,其中有乌头之药,直透入骨;若不早治,此臂无用矣。”公曰:“用何物治之?”佗曰:“某自有治法,但恐君侯惧耳。”公笑曰:“吾视死如归,有何惧哉?”佗曰:“当于静处立一标柱,上钉大环,请君侯将臂穿于环中,以绳系之,然后以被蒙其首。吾用尖刀割开皮肉,直至于骨,刮去骨上箭毒,用药敷之,以线缝其口,方可无事。但恐君侯惧耳。”公笑曰:“如此,容易!何用柱环?”令设酒席相待。 公饮数杯酒毕,一面仍与马良弈棋,伸臂令佗割之。佗取尖刀在手,令一小校捧一大盆于臂下接血。佗曰:“某便下手,君侯勿惊。”公曰:“任汝医治,吾岂比世间俗子惧痛者耶!”佗乃下刀,割开皮肉,直至于骨,骨上已青;佗用刀刮骨,悉悉有声。帐上帐下见者,皆掩面失色。公饮酒食肉,谈笑弈棋,全无痛苦之色。须臾,血流盈盆。佗刮尽其毒,敷上药,以线缝之。公大笑而起,谓众将曰:“此臂伸舒如故,并无痛矣。先生真神医也!”佗曰:“某为医一生,未尝见此。君侯真天神也!”后人有诗曰:“治病须分内外科,世间妙艺苦无多。神威罕及惟关将,圣手能医说华佗。” @@ -1381,7 +1381,7 @@ 却说傅士仁听知荆州有失,急令闭城坚守。虞翻至,见城门紧闭,遂写书拴于箭上,射入城中。军士拾得,献与傅士仁。士仁拆书视之,乃招降之意。览毕,想起“关公去日恨吾之意,不如早降。”即令大开城门,请虞翻入城。二人礼毕,各诉旧情。翻说吴侯宽洪大度,礼贤下土;士仁大喜,即同虞翻赍印绶来荆州投降。孙权大悦,仍令去守公安。吕蒙密谓权曰:“今云长未获,留士仁于公安,久必有变;不若使往南郡招糜芳归降。”权乃召傅士仁谓曰:“糜芳与卿交厚,卿可招来归降,孤自当有重赏。”傅士仁慨然领诺,遂引十余骑,径投南郡招安糜芳。正是:今日公安无守志,从前王甫是良言。 未知此去如何,且看下文分解。 (本章完) -第76章 徐公明大战沔水 关云长败走麦城 +第76章 徐公明大战沔水 关云长败走麦城   却说糜芳闻荆州有失,正无计可施。忽报公安守将傅士仁至,芳忙接入城,问其事故。士仁曰:“吾非不忠。势危力困,不能支持,我今已降东吴。将军亦不如早降。”芳曰:“吾等受汉中王厚恩,安忍背之?“士仁曰:“关公去日,痛恨吾二人;倘一日得胜而回,必无轻恕。公细察之。”芳曰:“吾兄弟久事汉中王,岂可一朝相背?”正犹豫间,忽报关公遣使至,接入厅上。使者曰:“关公军中缺粮,特来南郡、公安二处取白米十万石,令二将军星夜解去军前交割。如迟立斩。”芳大惊,顾谓傅士仁曰:“今荆州已被东吴所取,此粮怎得过去?”士仁厉声曰:“不必多疑!”遂拔剑斩来使于堂上。芳惊曰:“公如何斩之?”士仁曰:“关公此意,正要斩我二人。我等安可束手受死?公今不早降东吴,必被关公所杀。”正说间,忽报吕蒙引兵杀至城下。芳大惊,乃同傅士仁出城投降。蒙大喜,引见孙权。权重赏二人。安民已毕,大犒三军。 时曹操在许都,正与众谋士议荆州之事,忽报东吴遣使奉书至。操召人,使者呈上书信。操拆视之,书中具言吴兵将袭荆州,求操夹攻云长;且嘱勿泄漏,使云长有备也。操与众谋士商议,主簿董昭曰:“今樊城被困,引颈望救,不如令人将书射入樊城,以宽军心;且使关公知东吴将袭荆州。彼恐荆州有失,必速退兵,却令徐晃乘势掩杀,可获全功。”操从其谋,一面差人催徐晃急战;一面亲统大兵,径往洛阳之南阳陵坡驻扎,以救曹仁。 却说徐晃正坐帐中,忽报魏王使至。晃接入问之,使曰:“今魏王引兵,已过洛阳;令将军急战关公,以解樊城之困。”正说间,探马报说:“关平屯兵在偃城,廖化屯兵在四冢:前后一十二个寨栅,连络不绝。”晃即差副将徐商、吕建假着徐晃旗号,前赴偃城与关平交战。晃却自引精兵五百,循沔水去袭偃城之后。且说关平闻徐晃自引兵至,遂提本部兵迎敌。两阵对圆,关平出马,与徐商交锋,只三合,商大败而走;吕建出战,五六合亦败走。平乘胜追杀二十余里,忽报城中火起。平知中计,急勒兵回救偃城。正遇一彪军摆开,徐晃立马在门旗下,高叫曰:“关平贤侄,好不知死!汝荆州已被东吴夺了,犹然在此狂为!”平大怒,纵马轮刀,直取徐晃;不三四合,三军喊叫,偃城中火光大起。平不敢恋战,杀条大路,径奔四冢寨来。廖化接着。化曰:“人言荆州已被吕蒙袭了,军心惊慌,如之奈何?”平曰:“此必讹言也。军士再言者斩之。” @@ -1401,7 +1401,7 @@ 汝勿多言,速请出城,吾欲与孙权决一死战!”瑾曰:“吴侯欲与君侯结秦晋之好,同力破曹,共扶汉室,别无他意。君侯何执迷如是?”言未毕,关平拔剑而前,欲斩诸葛瑾。公止之曰:“彼弟孔明在蜀,佐汝伯父,今若杀彼,伤其兄弟之情也。”遂令左右逐出诸葛瑾。瑾满面羞惭,上马出城,回见吴侯曰:“关公心如铁石,不可说也。”孙权曰:“真忠臣也!似此如之奈何?’吕范曰:“某请卜其休咎。”权即令卜之。范揲蓍成象,乃“地水师卦”,更有玄武临应,主敌人远奔。权问吕蒙曰:“卦主敌人远奔,卿以何策擒之?”蒙笑曰:“卦象正合某之机也。关公虽有冲天之翼,飞不出吾罗网矣!”正是:龙游沟壑遭虾戏,凤入牢笼被鸟欺。 毕竟吕蒙之计若何,且看下文分解。 (本章完) -第77章 玉泉山关公显圣 洛阳城曹操感神 +第77章 玉泉山关公显圣 洛阳城曹操感神   却说孙权求计于吕蒙。蒙曰:“吾料关某兵少,必不从大路而逃,麦成正北有险峻小路,必从此路而去。可令朱然引精兵五千,伏于麦城之北二十里;彼军至,不可与敌,只可随后掩杀。彼军定无战心,必奔临沮。却令潘璋引精兵五百,伏于临沮山僻小路,关某可擒矣。今遣将士各门攻打,只空北门,待其出走。”权闻计,令吕范再卜之。卦成,范告曰:“此卦主敌人投西北而走,今夜亥时必然就擒。”权大喜,遂令朱然、潘璋领两枝精兵,各依军令埋伏去讫。 且说关公在麦城,计点马步军兵,止剩三百余人;粮草又尽。是夜,城外吴兵招唤各军姓名,越城而去者甚多。救兵又不见到。心中无计,谓王甫曰:“吾悔昔日不用公言!今日危急,将复何如?”甫哭告曰:“今日之事,虽子牙复生,亦无计可施也。”赵累曰:“上庸救兵不至,乃刘封、孟达按兵不动之故。何不弃此孤城,奔入西川,再整兵来,以图恢复?”公曰:“吾亦欲如此。”遂上城观之。见北门外敌军不多,因问本城居民:“此去往北,地势若何?”答曰:“此去皆是山僻小路,可通西川。”公曰:“今夜可走此路。。王甫谏曰:“小路有埋伏,可走大路。”公曰:“虽有埋伏,吾何惧哉!”即下令马步官军:严整装束,准备出城。甫哭曰:“君侯于路,小心保重!某与部卒百余人,死据此城;城虽破,身不降也!专望君侯速来救援!”公亦与泣别。遂留周仓与王甫同守麦城,关公自与关平、赵累引残卒二百余人,突出北门。 关公横刀前进,行至初更以后,约走二十余里,只见山凹处,金鼓齐鸣,喊声大震,一彪军到,为首大将朱然,骤马挺枪叫曰:“云长休走!趁早投降,免得一死!”公大怒,拍马轮刀来战。朱然便走,公乘势追杀。一棒鼓响,四下伏兵皆起。公不敢战,望临沮小路而走,朱然率兵掩杀。关公所随之兵,渐渐稀少。走不得四五里,前面喊声又震,火光大起,潘璋骤马舞刀杀来。公大怒,轮刀相迎,只三合,潘璋败走。公不敢恋战,急望山路而走。背后关平赶来,报说赵累已死于乱军中。关公不胜悲惶,遂令关平断后,公自在前开路,随行止剩得十余人。行至决石,两下是山,山边皆芦苇败草,树木丛杂。时已五更将尽。正走之间,一声喊起,两下伏兵尽出,长钩套索,一齐并举,先把关公坐下马绊倒。关公翻身落马,被潘璋部将马忠所获。关平知父被擒,火速来救;背后潘璋、朱然率兵齐至,把关平四下围住。平孤身独战,力尽亦被执。至天明,孙权闻关公父子已被擒获,大喜,聚众将于帐中。 @@ -1418,7 +1418,7 @@ 二人正说之间,忽然殿内转出一人,扯住孔明衣袖而言曰:“如此凶信,公何瞒我!”孔明视之,乃玄德也。孔明、许靖奏曰:“适来所言,皆传闻之事,未足深信。愿王上宽怀,勿生忧虑。”玄德曰:“孤与云长,誓同生死;彼若有失,孤岂能独生耶!”孔明、许靖正劝解之间,忽近侍奏曰:“马良、伊籍至。”玄德急召入问之。二人具说荆州已失,关公兵败求救,呈上表章。未及拆观,侍臣又奏荆州廖化至。玄德急召入。化哭拜于地,细奏刘封、孟达不发救兵之事。玄德大惊曰:“若如此,吾弟休矣!”孔明曰:“刘封、孟达如此无礼,罪不容诛!王上宽心,亮亲提一旅之师,去救荆襄之急。”玄德泣曰:“云长有失,孤断不独生!孤来日自提一军去救云长!”遂一面差人赴阆中报知翼德,一面差人会集人马。 未及天明,一连数次,报说关公夜走临沮,为吴将所获,义不屈节,父子归神。玄德听罢,大叫一声,昏绝于地。正是:为念当年同誓死,忍教今日独捐生!未知玄德性命如何,且看下文分解。 (本章完) -第78章 治风疾神医身死 传遗命奸雄数终 +第78章 治风疾神医身死 传遗命奸雄数终   却说汉中王闻关公父子遇害,哭倒于地;众文武急救,半晌方醒,扶入内殿。孔明劝曰:“王上少忧。自古道死生有命;关公平日刚而自矜,故今日有此祸。王上且宜保养尊体,徐图报仇。”玄德曰:“孤与关、张二弟桃园结义时,誓同生死。今云长已亡,孤岂能独享富贵乎!”言未已,只见关兴号恸而来。玄德见了,大叫一声,又哭绝于地。众官救醒。一日哭绝三五次,三日水浆不进,只是痛哭;泪湿衣襟,斑斑成血。孔明与众官再三劝解。玄德曰:“孤与东吴,誓不同日月也!”孔明曰:“闻东吴将关公首级献与曹操,操以王侯礼祭葬之。”玄德曰:“此何意也?”孔明曰:“此是东吴欲移祸于曹操,操知其谋,故以厚礼葬关公,令王上归怨于吴也。”玄德曰:“吾今即提兵问罪于吴,以雪吾恨!”孔明谏曰:“不可。方今吴欲令我伐魏,魏亦欲令我伐吴,各怀谲计,伺隙而乘。王上只宜按兵不动,且与关公发丧。待吴、魏不和,乘时而伐之,可也。”众官又再三劝谏,玄德方才进膳,传旨川中大小将士,尽皆挂孝。汉中王亲出南门招魂祭奠,号哭终日。 却说曹操在洛阳,自葬关公后,每夜合眼便见关公。操甚惊惧,问于众官。众官曰:“洛阳行宫旧殿多妖,可造新殿居之。”操曰:“吾欲起一殿,名建始殿。恨无良工。”贾诩曰:“洛阳良工有苏越者,最有巧思。”操召入,令画图像。苏越画成九间大殿,前后廊庑楼阁,呈与操。操视之曰:“汝画甚合孤意,但恐无栋梁之材。”苏越曰:“此去离城三十里,有一潭,名跃龙潭;前有一祠,名跃龙祠。祠傍有一株大梨树,高十余丈,堪作建始殿之梁。” 操大喜,即令人工到彼砍伐。次日,回报此树锯解不开,斧砍不入,不能斩伐。操不信,自领数百骑,直至跃龙祠前下马,仰观那树,亭亭如华盖,直侵云汉,并无曲节。操命砍之,乡老数人前来谏曰:“此树已数百年矣,常有神人居其上,恐未可伐。”操大怒曰:“吾平生游历,普天之下,四十余年,上至天子,下及庶人,无不惧孤;是何妖神,敢违孤意!”言讫,拔所佩剑亲自砍之,铮然有声,血溅满身。操愕然大惊,掷剑上马,回至宫内。是夜二更,操睡卧不安,坐于殿中,隐几而寐。忽见一人披发仗剑,身穿皂衣,直至面前,指操喝曰:“吾乃梨树之神也。汝盖建始殿,意欲篡逆,却来伐吾神木!吾知汝数尽,特来杀汝!”操大惊,急呼:“武士安在?”皂衣人仗剑砍操。操大叫一声,忽然惊觉,头脑疼痛不可忍。急传旨遍求良医治疗,不能痊可。众官皆忧。 @@ -1433,7 +1433,7 @@ 正宴会庆贺间,忽报鄢陵侯曹彰,自长安领十万大军来到。丕大惊,遂问群臣曰:“黄须小弟;平日性刚,深通武艺。今提兵远来,必与孤争王位也。如之奈何?”忽阶下一人应声出曰:“臣请往见鄢陵侯,以片言折之。”众皆曰:“非大夫莫能解此祸也。”正是:试看曹氏丕彰事,几作袁家谭尚争。 未知此人是谁,且看下文分解。 (本章完) -第79章 兄逼弟曹植赋诗 侄陷叔刘封伏法 +第79章 兄逼弟曹植赋诗 侄陷叔刘封伏法   却说曹丕闻曹彰提兵而来,惊问众官;一人挺身而出,愿往折服之。众视其人,乃谏议大夫贾逵也。曹丕大喜,即命贾逵前往。逵领命出城,迎见曹彰。彰问曰:“先王玺绶安在?”逵正色而言曰:“家有长子,国有储君。先王玺绶,非君侯之所宜问也。”彰默然无语,乃与贾逵同入城。至宫门前,逵问曰:“君侯此来,欲奔丧耶?欲争位耶?”彰曰:“吾来奔丧,别无异心。”逵曰:“既无异心,何故带兵入城?”彰即时叱退左右将士,只身入内,拜见曹丕。兄弟二人,相抱大哭。曹彰将本部军马尽交与曹丕。丕令彰回鄢陵自守,彰拜辞而去。 于是曹丕安居王位,改建安二十五年为延康元年;封贾诩为太尉,华歆为相国,王朗为御史大夫;大小官僚,尽皆升赏。谥曹操曰武王,葬于邺郡高陵,令于禁董治陵事。禁奉命到彼,只见陵屋中白粉壁上,图画关云长水淹七军擒获于禁之事:画云长俨然上坐,庞德愤怒不屈,于禁拜伏于地,哀求乞命之状。原来曹丕以于禁兵败被擒,不能死节,既降敌而复归,心鄙其为人,故先令人图画陵屋粉壁,故意使之往见以愧之。当下于禁见此画像,又羞又恼,气愤成病,不久而死。后人有诗叹曰:“三十年来说旧交,可怜临难不忠曹。知人未向心中识,画虎今从骨里描。” 却说华歆奏曹丕曰:“鄢陵侯已交割军马,赴本国去了;临淄侯植、萧怀侯熊,二人竟不来奔丧,理当问罪,丕从之,即分遣二使往二处问罪。不一日,萧怀使者回报:“萧怀侯曹熊惧罪,自缢身死。”丕令厚葬之,追赠萧怀王。又过了一日,临淄使者回报,说:“临淄侯日与丁仪、丁廙兄弟二人酣饮,悖慢无礼,闻使命至,临淄侯端坐不动;丁仪骂曰:昔者先王本欲立吾主为世子,被谗臣所阻;今王丧未远,便问罪于骨肉,何也?丁廙又曰:据吾主聪明冠世,自当承嗣大位,今反不得立。汝那庙堂之臣,何不识人才若此!临淄侯因怒,叱武士将臣乱棒打出。” @@ -1450,7 +1450,7 @@ 且说魏王曹丕,自即王位,将文武官僚,尽皆升赏;遂统甲兵三十万,南巡沛国谯县,大飨先茔。乡中父老,扬尘遮道,奉觞进酒,效汉高祖还沛之事。人报大将军夏侯惇病危,丕即还邺郡。时惇已卒,不为挂孝,以厚礼殉葬。 是岁八月间,报称石邑县凤凰来仪,临淄城麒麟出现,黄龙现于邺郡。于是中郎将李伏、太史丞许芝商议:种种瑞徵,乃魏当代汉之兆,可安排受禅之礼,令汉帝将天下让于魏王。遂同华歆、王朗、辛毗、贾诩、刘廙、刘晔、陈矫、陈群、桓阶等一班文武官僚,四十余人,直入内殿,来奏汉献帝,请禅位于魏王曹丕。正是:魏家社稷今将建,汉代江山忽已移。未知献帝如何回答,且看下文分解。 (本章完) -第80章 曹丕废帝篡炎刘 汉王正位续大统 +第80章 曹丕废帝篡炎刘 汉王正位续大统   却说华歆等一班文武,入见献帝。歆奏曰:“伏睹魏王,自登位以来,德布四方,仁及万物,越古超今,虽唐、虞无以过此。群臣会议,言汉祚已终,望陛下效尧、舜之道,以山川社稷,禅与魏王,上合天心,下合民意,则陛下安享清闲之福,祖宗幸甚!生灵幸甚!臣等议定,特来奏请。”帝国奏大惊,半晌无言,觑百官而哭曰:“朕想高祖提三尺剑,斩蛇起义,平秦灭楚,创造基业,世统相传,四百年矣。朕虽不才,初无过恶,安忍将祖宗大业,等闲弃了?汝百官再从公计议。”华歆引李伏、许芝近前奏曰:“陛下若不信,可问此二人。”李伏奏曰:“自魏王即位以来,麒麟降生,凤凰来仪,黄龙出现,嘉禾蔚生,甘露下降。 此是上天示瑞,魏当代汉之象也。”许芝又奏曰:“臣等职掌司天,夜观乾象,见炎汉气数已终,陛下帝垦隐匿不明;魏国乾象,极天际地,言之难尽。更兼上应图谶,其谶曰:鬼在边,委相连;当代汉,无可言。言在东,午在西;两日并光上下移。以此论之,陛下可早禅位。鬼在边,委相连,是魏字也;言在东,午在西,乃许字也;两日并光上下移,乃昌字也:此是魏在许昌应受汉禅也。愿陛下察之。”帝曰:“祥瑞图谶,皆虚妄之事;奈何以虚妄之事,而遽欲朕舍祖宗之基业乎?”王朗奏曰:“自古以来,有兴必有废,有盛必有衰,岂有不亡之国、不败之家乎?汉室相传四百余年,延至陛下,气数已尽,宜早退避,不可迟疑;迟则生变矣。”帝大哭,入后殿去了。百官哂笑而退。 次日,官僚又集于大殿,令宦官入请献帝。帝忧惧不敢出。曹后曰:“百官请陛下设朝,陛下何故推阻?”帝泣曰:“汝兄欲篡位,令百官相逼,朕故不出。”曹后大怒曰:“吾兄奈何为此乱逆之事耶!”言未已,只见曹洪、曹休带剑而入,请帝出殿。曹后大骂曰:“俱是汝等乱贼,希图富贵,共造逆谋!吾父功盖寰区,威震天下,然且不敢篡窃神器。今吾兄嗣位未几,辄思篡汉,皇天必不祚尔!”言罢,痛哭入宫。左右侍者皆歔欷流涕。曹洪、曹休力请献帝出殿。帝被逼不过,只得更衣出前殿。华歆奏曰:“陛下可依臣等昨日之议,免遭大祸。”帝痛哭曰:“卿等皆食汉禄久矣;中间多有汉朝功臣子孙,何忍作此不臣之事?”歆曰:“陛下若不从众议,恐旦夕萧墙祸起。非臣等不忠于陛下也。”帝曰:“谁敢弑朕耶?”歆厉声曰:“天下之人,皆知陛下无人君之福,以致四方大乱!若非魏王在朝,弑陛下者,何止一人?陛下尚不知恩报德,直欲令天下人共伐陛下耶?”帝大惊,拂袖而起,王朗以目视华歆。歆纵步向前,扯住龙袍,变色而言曰:“许与不许,早发一言!”帝战栗不能答,曹洪、曹休拔剑大呼曰:“符宝郎何在?”祖弼应声出曰:“符宝郎在此!”曹洪索要玉玺。祖弼叱曰:“玉玺乃天子之宝,安得擅索!”洪喝令武士推出斩之。祖弼大骂不绝口而死。后人有诗赞曰:“奸宄专权汉室亡,诈称禅位效虞唐。满朝百辟皆尊魏,仅见忠臣符宝郎。” @@ -1467,7 +1467,7 @@ 惟神飨祚汉家,永绥历服!”读罢祭文,孔明率众官恭上玉玺。汉中王受了,捧于坛上,再三推辞曰:“备无才德,请择有才德者受之。”孔明奏曰:“王上平定四海,功德昭于天下,况是大汉宗派,宜即正位。已祭告天神,复何让焉!”文武各官,皆呼万岁。拜舞礼毕,改元章武元年。立妃吴氏为皇后,长子刘禅为太子;封次子刘永为鲁王,三子刘理为梁王;封诸葛亮为丞相,许靖为司徒;大小官僚,一一升赏。大赦天下。两川军民,无不欣跃。次日设朝,文武官僚拜毕,列为两班。先主降诏曰:“朕自桃园与关、张结义,誓同生死。不幸二弟云长,被东吴孙权所害;若不报仇,是负盟也。朕欲起倾国之兵,剪伐东吴,生擒逆贼,以雪此恨!”言未毕,班内一人拜伏于阶下,谏曰:“不可。”先主视之,乃虎威将军赵云也。正是:君王未及行天讨,臣下曾闻进直言。 未知子龙所谏若何,且看下文分解。 (本章完) -第81章 急兄仇张飞遇害 雪弟恨先主兴兵 +第81章 急兄仇张飞遇害 雪弟恨先主兴兵   却说先主欲起兵东征,赵云谏曰:“国贼乃曹操,非孙权也。今曹丕篡汉,神人共怒。陛下可早图关中,屯兵渭河上流,以讨凶逆,则关东义士,必裹粮策马以迎王师;若舍魏以伐吴,兵势一交,岂能骤解。愿陛下察之。”先主曰:“孙权害了朕弟;又兼傅士仁、糜芳、潘璋、马忠皆有切齿之仇:啖其肉而灭其族,方雪朕恨!卿何阻耶?”云曰:“汉贼之仇,公也;兄弟之仇,私也。愿以天下为重。”先主答曰:“朕不为弟报仇,虽有万里江山,何足为贵?”遂不听赵云之谏,下令起兵伐吴;且发使往五溪,借番兵五万,共相策应;一面差使往阆中,迁张飞为车骑将军,领司隶校尉,封西乡侯,兼阆中牧。使命赍诏而去。却说张飞在阆中,闻知关公被东吴所害,旦夕号泣,血湿衣襟。诸将以酒解劝,酒醉,怒气愈加。帐上帐下,但有犯者即鞭挞之;多有鞭死者。每日望南切齿睁目怒恨,放声痛哭不已。忽报使至,慌忙接入,开读诏旨。飞受爵望北拜毕,设酒款待来使。 飞曰:“吾兄被害,仇深似海;庙堂之臣,何不早奏兴兵?”使者曰:“多有劝先灭魏而后伐吴者。”飞怒曰:“是何言也!昔我三人桃园结义,誓同生死;今不幸二兄半途而逝,吾安得独享富贵耶!吾当面见天子,愿为前部先锋,挂孝伐吴,生擒逆贼,祭告二兄,以践前盟!”言讫,就同使命望成都而来。却说先主每日自下教场操演军马,克日兴师,御驾亲征。于是公卿都至丞相府中见孔明,曰:“今天子初临大位,亲统军伍,非所以重社稷也。丞相秉钧衡之职,何不规谏?”孔明曰:“吾苦谏数次,只是不听。今日公等随我入教场谏去。”当下孔明引百官来奏先主曰:“陛下初登宝位,若欲北讨汉贼,以伸大义于天下,方可亲统六师;若只欲伐吴,命一上将统军伐之可也,何必亲劳圣驾?”先主见孔明苦谏,心中稍回。忽报张飞到来,先主急召入。飞至演武厅拜伏于地,抱先主足而哭。先主亦哭。飞曰:“陛下今日为君,早忘了桃园之誓!二兄之仇,如何不报?”先主曰:“多官谏阻,未敢轻举。 ”飞曰:“他人岂知昔日之盟?若陛下不去,臣舍此躯与二兄报仇!若不能报时,臣宁死不见陛下也!”先主曰:“朕与卿同往:卿提本部兵自阆州而出,朕统精兵会于江州,共伐东吴,以雪此恨!”飞临行,先主嘱曰:“朕素知卿酒后暴怒,鞭挞健儿,而复令在左右:此取祸之道也。今后务宜宽容,不可如前。”飞拜辞而去。次日,先主整兵要行。学士秦宓奏曰:“陛下舍万乘之躯,而徇小义,古人所不取也。愿陛下思之。”先主曰:“云长与朕,犹一体也。大义尚在,岂可忘耶?”宓伏地不起曰:“陛下不从臣言,诚恐有失。”先主大怒曰:“朕欲兴兵,尔何出此不利之言!”叱武士推出斩之,宓面不改色,回顾先主而笑曰:“臣死无恨,但可惜新创之业,又将颠覆耳!”众官皆为秦宓告免。先主曰:“暂且囚下,待朕报仇回时发落。”孔明闻知,即上表救秦宓。其略曰:“臣亮等窃以吴贼逞奸诡之计,致荆州有覆亡之祸;陨将星于斗牛,折天柱于楚地:此情哀痛,诚不可忘。但念迁汉鼎者,罪由曹操;移刘祚者,过非孙权。窃谓魏贼若除,则吴自宾服。 @@ -1481,7 +1481,7 @@ 二将方欲交锋,先主喝曰:“二子休得无礼!”兴、苞二人慌忙下马,各弃兵器,拜伏请罪。先主曰:“朕自涿郡与卿等之父结异姓之交,亲如骨肉;今汝二人亦是昆仲之分,正当同心协力,共报父仇;奈何自相争竞,失其大义!父丧未远而犹如此,况日后乎?”二人再拜伏罪。先主问曰:“卿二人谁年长?”苞曰:“臣长关兴一岁。”先主即命兴拜苞为兄。二人就帐前折箭为誓,永相救护。先主下诏使吴班为先锋,令张苞、关兴护驾。水陆并进,船骑双行,浩浩荡荡,杀奔吴国来。却说范疆、张达将张飞首级,投献吴侯,细告前事。孙权听罢,收了二人,乃谓百官曰:“今刘玄德即了帝位,统精兵七十余万,御驾亲征,其势甚大,如之奈何?”百官尽皆失色,面面相觑。诸葛瑾出曰:“某食君侯之禄久矣,无可报效,愿舍残生,去见蜀主,以利害说之,使两国相和,共讨曹丕之罪。”权大喜,即遣诸葛瑾为使,来说先主罢兵。正是:两国相争通使命,一言解难赖行人。 未知诸葛瑾此去如何,且看下文分解。 (本章完) -第82章 孙权降魏受九锡 先主征吴赏六军 +第82章 孙权降魏受九锡 先主征吴赏六军   却说章武元年秋八月,先主起大军至夔关,驾屯白帝城。前队军马已出川口。近臣奏曰:“吴使诸葛瑾至。”先主传旨教休放入。黄权奏曰:“瑾弟在蜀为相,必有事而来。陛下何故绝之?当召入,看他言语。可从则从;如不可,则就借彼口说与孙权,令知问罪有名也。”先主从之,召瑾入城。瑾拜伏于地。先主问曰:“子瑜远来,有何事故?”瑾曰:“臣弟久事陛下,臣故不避斧钺,特来奏荆州之事。前者,关公在荆州时,吴侯数次求亲,关公不允。后关公取襄阳,曹操屡次致书吴侯,使袭荆州;吴侯本不肯许,因吕蒙与关公不睦,故擅自兴兵,误成大事,今吴侯悔之不及。此乃吕蒙之罪,非吴侯之过也。今吕蒙已死,冤仇已息。 孙夫人一向思归。今吴侯令臣为使,愿送归夫人,缚还降将,并将荆州仍旧交还,永结盟好,共灭曹丕,以正篡逆之罪。”先主怒曰:“汝东吴害了朕弟,今日敢以巧言来说乎!”瑾曰:“臣请以轻重大小之事,与陛下论之:陛下乃汉朝皇叔,今汉帝已被曹丕篡夺,不思剿除;却为异姓之亲,而屈万乘之尊:是舍大义而就小义也。中原乃海内之地,两都皆大汉创业之方,陛下不取,而但争荆州:是弃重而取轻也。天下皆知陛下即位,必兴汉室,恢复山河;今陛下置魏不问,反欲伐吴:窃为陛下不取。”先主大怒曰:“杀吾弟之仇,不共戴天!欲朕罢兵,除死方休!不看丞相之面,先斩汝首!今且放汝回去,说与孙权:洗颈就戮!”诸葛瑾见先主不听,只得自回江南。 却说张昭见孙权曰:“诸葛子瑜知蜀兵势大,故假以请和为辞,欲背吴入蜀。此去必不回矣。”权曰:“孤与子瑜,有生死不易之盟;孤不负子瑜,子瑜亦不负孤。昔子瑜在柴桑时,孔明来吴,孤欲使子瑜留之。子瑜曰:弟已事玄德,义无二心;弟之不留,犹瑾之不往。其言足贯神明。今日岂肯降蜀乎?孤与子瑜可谓神交,非外言所得间也。”正言间,忽报诸葛瑾回。权曰:“孤言若何?”张昭满面羞惭而退。瑾见孙权,言先主不肯通和之意。权大惊曰:“若如此,则江南危矣!”阶下一人进曰:“某有一计,可解此危。”视之,乃中大夫赵咨也。权曰:“德度有何良策?”咨曰:“主公可作一表,某愿为使,往见魏帝曹丕,陈说利害,使袭汉中,则蜀兵自危矣。”权曰:“此计最善。但卿此去,休失了东吴气象。”咨曰:“若有些小差失,即投江而死,安有面目见江南人物乎!” @@ -1498,7 +1498,7 @@ 却说先主从巫峡建平起,直接彝陵界分,七十余里,连结四十余寨;见关兴、张苞屡立大功,叹曰:“昔日从朕诸将,皆老迈无用矣;复有二侄如此英雄,朕何虑孙权乎!”正言间,忽报韩当、周泰领兵来到。先主方欲遣将迎敌,近臣奏曰:“老将黄忠,引五六人投东吴去了。”先主笑曰:“黄汉升非反叛之人也;因朕失口误言老者无用,彼必不服老,故奋力去相持矣。”即召关兴、张苞曰:“黄汉升此去必然有失。贤侄休辞劳苦,可去相助。略有微功,便可令回,勿使有失。”二小将拜辞先主,引本部军来助黄忠。正是:老臣素矢忠君志,年少能成报国功。 未知黄忠此去如何,且看下文分解。 (本章完) -第83章 战猇亭先主得仇人 守江口书生拜大将 +第83章 战猇亭先主得仇人 守江口书生拜大将   却说章武二年春正月,武威后将军黄忠随先主伐吴;忽闻先主言老将无用,即提刀上马,引亲随五六人,径到彝陵营中。吴班与张南、冯习接入,问曰:“老将军此来,有何事故?”忠曰:“吾自长沙跟天子到今,多负勤劳。今虽七旬有余,尚食肉十斤,臂开二石之弓,能乘千里之马,未足为老。昨日主上言吾等老迈无用,故来此与东吴交锋,看吾斩将,老也不老!”正言间,忽报吴兵前部已到,哨马临营。忠奋然而起,出帐上马。冯习等劝曰:“老将军且休轻进。”忠不听,纵马而去。吴班令冯习引兵助战。忠在吴军阵前,勒马横刀,单搦先锋潘璋交战。璋引部将史迹出马。迹欺忠年老,挺枪出战;斗不三合,被忠一刀斩于马下。潘璋大怒,挥关公使的青龙刀,来战黄忠。交马数合,不分胜负。忠奋力恶战,璋料敌不过,拨马便走。忠乘势追杀,全胜而回。路逢关兴、张苞。兴曰:“我等奉圣旨来助老将军;既已立了功,速请回营。”忠不听。 次日,潘璋又来搦战。黄忠奋然上马。兴、苞二人要助战,忠不从;吴班要助战,忠亦不从;只自引五千军出迎。战不数合,璋拖刀便走。忠纵马追之,厉声大叫曰:“贼将休走!吾今为关公报仇!”追至三十余里,四面喊声大震,伏兵齐出:右边周泰,左边韩当,前有潘璋,后有凌统,把黄忠困在垓心。忽然狂风大起,忠急退时,山坡上马忠引一军出,一箭射中黄忠肩窝,险些儿落马。吴兵见忠中箭,一齐来攻,忽后面喊声大起,两路军杀来,吴兵溃散,救出黄忠,乃关兴、张苞也。二小将保送黄忠径到御前营中。忠年老血衰,箭疮痛裂,病甚沉重。先主御驾自来看视,抚其背曰:“令老将军中伤,朕之过也!”忠曰:“臣乃一武夫耳,幸遇陛下。臣今年七十有五,寿亦足矣。望陛下善保龙体,以图中原!”言讫,不省人事。是夜殒于御营。后人有诗叹曰:“老将说黄忠,收川立大功。重披金锁甲,双挽铁胎弓。胆气惊河北,威名镇蜀中。临亡头似雪,犹自显英雄。” 先主见黄忠气绝,哀伤不已,敕具棺椁,葬于成都。先主叹曰:“五虎大将,已亡三人。朕尚不能复仇,深可痛哉!”乃引御林军直至猇亭,大会诸将,分军八路,水陆俱进。水路令黄权领兵,先主自率大军于旱路进发。时章武二年二月中旬也。韩当、周泰听知先主御驾来征,引兵出迎。两阵对圆,韩当、周泰出马,只见蜀营门旗开处,先主自出,黄罗销金伞盖,左右白旌黄钺,金银旌节,前后围绕。当大叫曰:“陛下今为蜀主,何自轻出?倘有疏虞,悔之何及!”先主遥指骂曰:“汝等吴狗,伤朕手足,誓不与立于天地之间!”当回顾众将曰:“谁敢冲突蜀兵?”部将夏恂,挺枪出马。先主背后张苞挺丈八矛,纵马而出,大喝一声,直取夏恂。恂见苞声若巨雷,心中惊惧;恰待要走,周泰弟周平见恂抵敌不住,挥刀纵马而来。关兴见了,跃马提刀来迎。 @@ -1518,7 +1518,7 @@ 若陆逊知朕移营,必乘势来击,却令吴班诈败;逊若追来,朕引兵突出,断其归路,小子可擒矣。”文武皆贺曰:“陛下神机妙算,诸臣不及也!”马良曰:“近闻诸葛丞相在东川点看各处隘口,恐魏兵入寇。陛下何不将各营移居之地,画成图本,问于丞相?”先主曰:“朕亦颇知兵法,何必又问丞相?”良曰:“古云兼听则明,偏听则蔽。望陛下察之。”先主曰:“卿可自去各营,画成四至八道图本,亲到东川去向丞相。如有不便,可急来报知。”马良领命而去。于是先主移兵于林木阴密处避暑。早有细作报知韩当、周泰。二人听得此事,大喜,来见陆逊曰:“目今蜀兵四十余营,皆移于山林密处,依溪傍涧,就水歇凉。都督可乘虚击之。”正是:蜀主有谋能设伏,吴兵好勇定遭擒。 未知陆逊可听其言否,且看下文分解。 (本章完) -第84章 陆逊营烧七百里 孔明巧布八阵图 +第84章 陆逊营烧七百里 孔明巧布八阵图   却说韩当、周泰探知先主移营就凉,急来报知陆逊。逊大喜,遂引兵自来观看动静;只见平地一屯,不满万余人,大半皆是老弱之众,大书“先锋吴班”旗号。周泰曰:“吾视此等兵如儿戏耳。愿同韩将军分两路击之。如其不胜,甘当军令。”陆逊看了良久,以鞭指曰:“前面山谷中。隐隐有杀气起;其下必有伏兵,故于平地设此弱兵,以诱我耳。诸公切不可出。”众将听了,皆以为懦。 次日,吴班引兵到关前搦战,耀武扬威,辱骂不绝;多有解衣卸甲,赤身裸体,或睡或坐。徐盛、丁奉入帐禀陆逊曰:“蜀兵欺我太甚!某等愿出击之!”逊笑曰:“公等但恃血气之勇,未知孙、吴妙法,此彼诱敌之计也:三日后必见其诈矣。”徐盛曰:“三日后,彼移营已定,安能击之乎?”逊曰:“吾正欲令彼移营也。”诸将哂笑而退。过三日后,会诸将于关上观望,见吴班兵已退去。逊指曰:“杀气起矣。刘备必从山谷中出也。”言未毕,只见蜀兵皆全装惯束,拥先主而过。吴兵见了,尽皆胆裂。逊曰:“吾之不听诸公击班者,正为此也。今伏兵已出,旬日之内,必破蜀矣。”诸将皆曰:“破蜀当在初时,今连营五六百里,相守经七八月,其诸要害,皆已固守,安能破乎?”逊曰:“诸公不知兵法。备乃世之枭雄,更多智谋,其兵始集,法度精专;今守之久矣,不得我便,兵疲意阻,取之正在今日。”诸将方才叹服。后人有诗赞曰:“虎帐谈兵按六韬,安排香饵钓鲸鳌。三分自是多英俊,又显江南陆逊高。”却说陆逊已定了破蜀之策,遂修笺遣使奏闻孙权,言指日可以破蜀之意。权览毕,大喜曰:“江东复有此异人,孤何忧哉!诸将皆上书言其懦,孤独不信,今观其言,果非懦也。”于是大起吴兵来接应。却说先主于猇亭尽驱水军,顺流而下,沿江屯扎水寨,深入吴境。黄权谏曰:“水军沿江而下,进则易,退则难。臣愿为前驱。陛下宜在后阵,庶万无一失。”先主曰:“吴贼胆落,朕长驱大进,有何碍乎?”众官苦谏,先主不从。遂分兵两路:命黄权督江北之兵,以防魏寇;先主自督江南诸军,夹江分立营寨,以图进取。细作探知,连夜报知魏主,言蜀兵伐吴,树栅连营,纵横七百余里,分四十余屯,皆傍山林下寨;今黄权督兵在江北岸,每日出哨百余里,不知何意。魏主闻之,仰面笑曰:“刘备将败矣!”群臣请问其故。魏主曰:“刘玄德不晓兵法;岂有连营七百里,而可以拒敌者乎?包原隰险阻屯兵者,此兵法之大忌也。玄德必败于东吴陆逊之手,旬日之内,消息必至矣。”群臣犹未信,皆请拨兵备之。魏主曰:“陆逊若胜,必尽举吴兵去取西川;吴兵远去,国中空虚,朕虚托以兵助战,令三路一齐进兵,东吴唾手可取也。”众皆拜服。 魏主下令,使曹仁督一军出濡须,曹休督一军出洞口,曹真督一军出南郡:“三路军马会合日期,暗袭东吴。朕随后自来接应。”调遣已定。不说魏兵袭吴。且说马良至川,入见孔明,呈上图本而言曰:“今移营夹江,横占七百里,下四十余屯,皆依溪傍涧,林木茂盛之处。皇上令良将图本来与丞相观之。”孔明看讫,拍案叫苦曰:“是何人教主上如此下寨?可斩此人!”马良曰:“皆主上自为,非他人之谋。”孔明叹曰:“汉朝气数休矣!”良问其故。孔明曰:“包原隰险阻而结营,此兵家之大忌。倘彼用火攻,何以解救?又,岂有连营七百里而可拒敌乎?祸不远矣!陆逊拒守不出,正为此也。汝当速去见天子,改屯诸营,不可如此。”良曰:“倘今吴兵已胜,如之奈何?”孔明曰:“陆逊不敢来追,成都可保无虞。”良曰:“逊何故不追?”孔明曰:“恐魏兵袭其后也。主上若有失,当投白帝城避之。吾入川时,已伏下十万兵在鱼腹浦矣。”良大惊曰:“某于鱼腹浦往来数次,未尝见一卒,丞相何作此诈语?”孔明曰:“后来必见,不劳多问。”马良求了表章,火速投御营来。孔明自回成都,调拨军马救应。却说陆逊见蜀兵懈怠,不复提防,升帐聚大小将士听令曰:“吾自受命以来,未尝出战。今观蜀兵,足知动静,故欲先取江南岸一营。谁敢去取?”言未毕,韩当、周泰、凌统等应声而出曰:“某等愿往。”逊教皆退不用,独唤阶下末将淳于丹曰:“吾与汝五千军,去取江南第四营:蜀将傅彤所守。今晚就要成功。吾自提兵接应。”淳于丹引兵去了,又唤徐盛、丁奉曰:“汝等各领兵三千,屯于寨外五里,如淳于丹败回,有兵赶来,当出救之,却不可追去。”二将自引军去了。 @@ -1533,7 +1533,7 @@ 每日每时,变化无端,可比十万精兵。临去之时,曾分付老夫道:后有东吴大将迷于阵中,莫要引他出来。老夫适于山岩之上,见将军从死门而入,料想不识此阵,必为所迷。老夫平生好善,不忍将军陷没于此,故特自生门引出也。”逊曰:“公曾学此阵法否?”黄承彦曰:“变化无穷,不能学也。”逊慌忙下马拜谢而回。后杜工部有诗曰:“功盖三分国,名成八阵图。江流石不转,遗恨失吞吴。”陆逊回寨,叹曰:“孔明真卧龙也!吾不能及!”于是下令班师。左右曰:“刘备兵败势穷,困守一城,正好乘势击之;今见石阵而退,何也?”逊曰:“吾非惧石阵而退;吾料魏主曹丕,其奸诈与父无异,今知吾追赶蜀兵,必乘虚来袭。吾若深入西川,急难退矣。”遂令一将断后,逊率大军而回。退兵未及二日,三处人来飞报:“魏兵曹仁出濡须,曹休出洞口,曹真出南郡:三路兵马数十万,星夜至境,未知何意。”逊笑曰:“不出吾之所料。吾已令兵拒之矣。”正是:雄心方欲吞西蜀,胜算还须御北朝。 未知如何退兵,且看下文分解。 (本章完) -第85章 刘先主遗诏托孤儿 诸葛亮安居平五路 +第85章 刘先主遗诏托孤儿 诸葛亮安居平五路   却说章武二年夏六月,东吴陆逊大破蜀兵于猇亭彝陵之地;先主奔回白帝城,赵云引兵据守。忽马良至,见大军已败,懊悔不及,将孔明之言,奏知先主。先主叹曰:“朕早听丞相之言,不致今日之败!今有何面目复回成都见群臣乎!”遂传旨就白帝城住扎,将馆驿改为永安宫。人报冯习、张南、傅彤,程畿、沙摩柯等皆殁于王事,先主伤感不已。又近臣奏称:“黄权引江北之兵,降魏去了。陛下可将彼家属送有司问罪。”先主曰:“黄权被吴兵隔断在江北岸,欲归无路,不得已而降魏:是朕负权,非权负朕也,何必罪其家属?”仍给禄米以养之。却说黄权降魏,诸将引见曹丕,丕曰:“卿今降朕,欲追慕于陈、韩耶?”权泣而奏曰:“臣受蜀帝之恩,殊遇甚厚,令臣督诸军于江北,被陆逊绝断。臣归蜀无路,降吴不可,故来投陛下。败军之将,免死为幸,安敢追慕于古人耶!”丕大喜,遂拜黄权为镇南将军。权坚辞不受。忽近臣奏曰:“有细作人自蜀中来,说蜀主将黄权家属尽皆诛戮。”权曰:“臣与蜀主,推诚相信,知臣本心,必不肯杀臣之家小也。”丕然之。后人有诗责黄权曰:“降吴不可却降曹,忠义安能事两朝?堪叹黄权惜一死,紫阳书法不轻饶。” 曹丕问贾诩曰:“朕欲一统天下,先取蜀乎?先取吴乎?”诩曰:“刘备雄才,更兼诸葛亮善能治国;东吴孙权,能识虚实,陆逊现屯兵于险要,隔江泛湖,皆难卒谋。以臣观之,诸将之中,皆无孙权、刘备敌手。虽以陛下天威临之,亦未见万全之势也。只可持守,以待二国之变。”丕曰:“朕已遣三路大兵伐吴,安有不胜之理?”尚书刘晔曰:“近东吴陆逊,新破蜀兵七十万,上下齐心,更有江湖之阻,不可卒制,陆逊多谋,必有准备。”丕曰:“卿前劝朕伐吴,今又谏阻,何也?”晔曰:“时有不同也。昔东吴累败于蜀,其势顿挫,故可击耳;今既获全胜,锐气百倍,未可攻也。”丕曰:“朕意已决,卿勿复言。”遂引御林军亲往接应三路兵马。早有哨马报说东吴已有准备:令吕范引兵拒住曹休,诸葛瑾引兵在南郡拒住曹真,朱桓引兵当住濡须以拒曹仁。刘晔曰:“既有准备,去恐无益。”丕不从,引兵而去。 却说吴将朱桓,年方二十七岁,极有胆略,孙权甚爱之;时督军于濡须,闻曹仁引大军去取羡溪,桓遂尽拨军守把羡溪去了,止留五千骑守城。忽报曹仁令大将常雕同诸葛虔、王双、引五万精兵飞奔濡须城来。众军皆有惧色。桓按剑而言曰:“胜负在将,不在兵之多寡。兵法云:客兵倍而主兵半者,主兵尚能胜于客兵。今曹仁千里跋涉,人马疲困。吾与汝等共据高城,南临大江,北背山险,以逸待劳,以主制客:此乃百战百胜之势。虽曹丕自来,尚不足忧,况仁等耶!”于是传令,教众军偃旗息鼓,只作无人守把之状。 @@ -1550,7 +1550,7 @@ 孔明与后主共饮数杯,送后主出府。众官皆环立于门外,见后主面有喜色。后主别了孔明,上御车回朝。众皆疑惑不定。孔明见众官中,一人仰天而笑,面亦有喜色。孔明视之,乃义阳新野人,姓邓,名芝,字伯苗,现为户部尚书;汉司马邓禹之后。孔明暗令人留住邓芝。多官皆散,孔明请芝到书院中,问芝曰:“今蜀、魏、吴鼎分三国,欲讨二国,一统中兴,当先伐何国?”芝曰:“以愚意论之:魏虽汉贼,其势甚大,急难摇动,当徐徐缓图;今主上初登宝位,民心未安,当与东吴连合,结为唇齿,一洗先帝旧怨,此乃长久之计也。未审丞相钧意若何?”孔明大笑曰:“吾思之久矣,奈未得其人。今日方得也!”芝曰:“丞相欲其人何为?”孔明曰:“吾欲使人往结东吴。公既能明此意,必能不辱君命。使吴之任,非公不可。”芝曰:“愚才疏智浅,恐不堪当此任。”孔明曰:“吾来日奏知天子,便请伯苗一行,切勿推辞。”芝应允而退。至次日,孔明奏准后主,差邓芝往说东吴。芝拜辞,望东吴而来。正是:吴人方见干戈息,蜀使还将玉帛通。 未知邓芝此去若何,且看下文分解。 (本章完) -第86章 难张温秦宓逞天辩 破曹丕徐盛用火攻 +第86章 难张温秦宓逞天辩 破曹丕徐盛用火攻   却说东吴陆逊,自退魏兵之后,吴王拜逊为辅国将军,江陵侯,领荆州牧,自此军权皆归于逊。张昭、顾雍启奏吴王,请自改元。权从之,遂改为黄武元年。忽报魏主遣使至,权召入。使命陈说:“蜀前使人求救于魏,魏一时不明,故发兵应之;今已大悔,欲起四路兵取川,东吴可来接应。若得蜀土,各分一半。”权闻言,不能决,乃问于张昭、顾雍等。昭曰:“陆伯言极有高见,可问之。”权即召陆逊至。逊奏曰:“曹丕坐镇中原,急不可图;今若不从,必为仇矣。臣料魏与吴皆无诸葛亮之敌手。今且勉强应允,整军预备,只探听四路如何。若四路兵胜,川中危急,诸葛亮首尾不能救,主上则发兵以应之,先取成都,深为上策;如四路兵败,别作商议。”权从之,乃谓魏使曰:“军需未办,择日便当起程。”使者拜辞而去。 权令人探得西番兵出西平关,见了马超,不战自退;南蛮孟获起兵攻四郡,皆被魏延用疑兵计杀退回洞去了;上庸孟达兵至半路,忽然染病不能行;曹真兵出阳平关,赵子龙拒住各处险道,果然“一将守关,万夫莫开”。曹真屯兵于斜谷道,不能取胜而回。孙权知了此信,乃谓文武曰:“陆伯言真神算也。孤苦妄动,又结怨于西蜀矣。”忽报西蜀遣邓芝到。张昭曰:“此又是诸葛亮退兵之计,遣邓芝为说客也。”权曰:“当何以答之?”昭曰:“先于殿前立一大鼎,贮油数百斤,下用炭烧。待其油沸,可选身长面大武士一千人,各执刀在手,从宫门前直摆至殿上,却唤芝入见。休等此人开言下说词,责以郦食其说齐故事,效此例烹之,看其人如何对答。” 权从其言,遂立油鼎,命武士立于左右,各执军器,召邓芝入。芝整衣冠而入。行至宫门前,只见两行武士,威风凛凛,各持钢刀、大斧、长戟、短剑,直列至殿上。芝晓其意,并无惧色,昂然而行。至殿前,又见鼎镬内热油正沸。左右武士以目视之,芝但微微而笑。近臣引至帘前,邓芝长揖不拜。权令卷起珠帘,大喝曰:“何不拜!”芝昂然而答曰:“上国天使,不拜小邦之主。”权大怒曰:“汝不自料,欲掉三寸之舌,效郦生说齐乎!可速入油鼎。”芝大笑曰:“人皆言东吴多贤,谁想惧一儒生!”权转怒曰:“孤何惧尔一匹夫耶?”芝曰:“既不惧邓伯苗,何愁来说汝等也?”权曰:“尔欲为诸葛亮作说客,来说孤绝魏向蜀,是否?”芝曰:“吾乃蜀中一儒生,特为吴国利害而来。 @@ -1568,7 +1568,7 @@ 方见东吴敌北魏,又看西蜀战南蛮。 未知胜负如何,且看下文分解。 (本章完) -第87章 征南寇丞相大兴师 抗天兵蛮王初受执 +第87章 征南寇丞相大兴师 抗天兵蛮王初受执   却说诸葛丞相在于成都,事无大小,皆亲自从公决断。两川之民,忻乐太平,夜不闭户,路不拾遗。又幸连年大熟,老幼鼓腹讴歌,凡遇差徭,争先早办。因此军需器械应用之物,无不完备;米满仓廒,财盈府库。 建兴三年,益州飞报:蛮王孟获,大起蛮兵十万,犯境侵掠。建宁太守雍闿,乃汉朝什方侯雍齿之后,今结连孟获造反。牂牁郡太守朱褒、越嶲郡太守高定,二人献了城。止有永昌太守王伉不肯反。现今雍闿、朱褒、高定三人部下人马,皆与孟获为向导官,攻打永昌郡。今王伉与功曹吕凯,会集百姓,死守此城,其势甚急。孔明乃入朝奏后主曰:“臣观南蛮不服,实国家之大患也。臣当自领大军,前去征讨。”后主曰“东有孙权,北有曹丕,今相父弃朕而去,倘吴、魏来攻,如之奈何?”孔明曰:“东吴方与我国讲和,料无异心;若有异心,李严在白帝城,此人可当陆逊也。 曹丕新败,锐气已丧,未能远图;且有马超守把汉中诸处关口,不必忧也。臣又留关兴、张苞等分两军为救应,保陛下万无一失。今臣先去扫荡蛮方,然后北伐,以图中原,报先帝三顾之恩,托孤之重。”后主曰:“朕年幼无知,惟相父斟酌行之。”言未毕,班部内一人出曰:“不可!不可!”众视之,乃南阳人也,姓王,名连,字文仪,现为谏议大夫。连谏曰:“南方不毛之地,瘴疫之乡;丞相秉钧衡之重任,而自远征,非所宜也。且雍闿等乃疥癣之疾,丞相只须遣一大将讨之,必然成功。”孔明曰:“南蛮之地,离国甚远,人多不习王化,收伏甚难,吾当亲去征之。可刚可柔,别有斟酌,非可容易托人。” @@ -1588,7 +1588,7 @@ 寇入掌中还放去,人居化外未能降。 未知再来交战若何,且看下文分解。 (本章完) -第88章 渡泸水再缚番王 识诈降三擒孟获 +第88章 渡泸水再缚番王 识诈降三擒孟获   却说孔明放了孟获,众将上帐问曰:“孟获乃南蛮渠魁,今幸被擒,南方便定;丞相何故放之?”孔明笑曰:“吾擒此人,如囊中取物耳。直须降伏其心,自然平矣。”诸将闻言,皆未肯信。当日孟获行至泸水,正遇手下败残的蛮兵,皆来寻探。众兵见了孟获,且惊且喜,拜问曰:“大王如何能勾回来?”获曰:“蜀人监我在帐中,被我杀死十余人,乘夜黑而走;正行间,逢着一哨马军,亦被我杀之,夺了此马:因此得脱。”众皆大喜,拥孟获渡了泸水,下住寨栅,会集各洞酋长,陆续招聚原放回的蛮兵,约有十余万骑。此时董荼那、阿会喃已在洞中。孟获使人去请,二人惧怕,只得也引洞兵来。获传令曰:“吾已知诸葛亮之计矣,不可与战,战则中他诡计。彼川兵远来劳苦,况即日天炎,彼兵岂能久住?吾等有此泸水之险,将船筏尽拘在南岸,一带皆筑土城,深沟高垒,看诸葛亮如何施谋!”众酋长从其计,尽拘船筏于南岸,一带筑起土城:有依山傍崖之地,高竖敌楼;楼上多设弓弩炮石,准备久处之计。粮草皆是各洞供运。孟获以为万全之策,坦然不忧。却说孔明提兵大进,前军已至泸水,哨马飞报说:“泸水之内,并无船筏;又兼水势甚急,隔岸一带筑起土城,皆有蛮兵守把。”时值五月,天气炎热,南方之地,分外炎酷,军马衣甲,皆穿不得。孔明自至泸水边观毕,回到本寨,聚诸将至帐中,传令曰:“今孟获兵屯泸水之南,深沟高垒,以拒我兵;吾既提兵至此,如何空回?汝等各各引兵,依山傍树,拣林木茂盛之处,与我将息人马。”乃遣吕凯离泸水百里,拣阴凉之地,分作四个寨子;使王平、张嶷、张翼、关索各守一寨,内外皆搭草棚,遮盖马匹,将士乘凉,以避暑气。 参军蒋琬看了,入问孔明曰:“某看吕凯所造之寨甚不好,正犯昔日先帝败于东吴时之地势矣,倘蛮兵偷渡泸水,前来劫寨,若用火攻,如何解救?”孔明笑曰:“公勿多疑,吾自有妙算。”蒋琬等皆不晓其意。忽报蜀中差马岱解暑药并粮米到。孔明令入。岱参拜毕,一面将米药分派四寨。孔明问曰:“汝将带多少军来?”马岱曰:“有三千军。”孔明曰:“吾军累战疲困,欲用汝军,未知肯向前否?”岱曰:“皆是朝廷军马,何分彼我?丞相要用,虽死不辞。”孔明曰:“今孟获拒住泸水,无路可渡。吾欲先断其粮道,令彼军自乱。”岱曰:“如何断得?”孔明曰:“离此一百五十里,泸水下流沙口,此处水慢,可以扎筏而渡。汝提本部三千军渡水,直入蛮洞,先断其粮,然后会合董荼那、阿会喃两个洞主,便为内应。不可有误。” 马岱欣然去了,领兵前到沙口,驱兵渡水;因见水浅,大半不下筏,只裸衣而过,半渡皆倒;急救傍岸,口鼻出血而死。马岱大惊,连夜回告孔明。孔明随唤向导土人问之。土人曰:“目今炎天,毒聚泸水,日间甚热,毒气正发,有人渡水,必中其毒;或饮此水,其人必死。若要渡时。须待夜静水冷,毒气不起,饱食渡之,方可无事。”孔明遂令土人引路,又选精壮军五六百,随着马岱,来到泸水沙口,扎起木筏,半夜渡水,果然无事,岱领着二千壮军,令土人引路,径取蛮洞运粮总路口夹山峪而来。那夹山峪,两下是山,中间一条路,止容一人一马而过。马岱占了夹山峪,分拨军士,立起寨栅。 @@ -1605,7 +1605,7 @@ 若非洞主威风猛,怎显军师手段高! 未知胜负如何,且看下文分解。 (本章完) -第89章 武乡侯四番用计 南蛮王五次遭擒 +第89章 武乡侯四番用计 南蛮王五次遭擒   却说孔明自驾小车,引数百骑前来探路。前有一河,名曰西洱河,水势虽慢,并无一只船筏。孔明令伐木为筏而渡,其木到水皆沉。孔明遂问吕凯,凯曰:“闻西洱河上流有一山,其山多竹,大者数围。可令人伐之,于河上搭起竹桥,以渡军马。”孔明即调三万人入山,伐竹数十万根,顺水放下,于河面狭处,搭起竹桥,阔十余丈。乃调大军于河北岸一字儿下寨,便以河为壕堑,以浮桥为门,垒土为城;过桥南岸,一字下三个大营,以待蛮兵。 却说孟获引数十万蛮兵,恨怒而来。将近西洱河,孟获引前部一万刀牌獠丁,直扣前寨搦战。孔明头戴纶巾,身披鹤氅,手执羽扇,乘驷马车,左右众将簇拥而出。孔明见孟获身穿犀皮甲,头顶朱红盔,左手挽牌,右手执刀,骑赤毛牛,口中辱骂;手下万余洞丁,各舞刀牌,往来冲突。孔明急令退回本寨,四面紧闭,不许出战。蛮兵皆裸衣赤身,直到寨门前叫骂。诸将大怒,皆来禀孔明曰:“某等情愿出寨决一死战!”孔明不许。诸将再三欲战,孔明止曰:“蛮方之人,不遵王化,今此一来,狂恶正盛,不可迎也;且宜坚守数日,待其猖獗少懈,吾自有妙计破之。” 于是蜀兵坚守数日。孔明在高阜处探之,窥见蛮兵已多懈怠,乃聚诸将曰:“汝等敢出战否?”众将欣然要出。孔明先唤赵云、魏延入帐,向耳畔低言,分付如此如此。二人受了计策先进。却唤王平、马忠入帐,受计去了。又唤马岱分付曰:“吾今弃此三寨,退过河北;吾军一退,汝可便拆浮桥,移于下流,却渡赵云、魏延军马过河来接应。”岱受计而去。又唤张翼曰:“吾军退去,寨中多设灯火。孟获知之,必来追赶,汝却断其后。”张翼受计而退。孔明只教关索护车。众军退去,寨中多设灯火。蛮兵望见,不敢冲突。 @@ -1624,7 +1624,7 @@ 于是各洞蛮兵,皆走回本乡。杨锋将孟获、孟优、朵思等解赴孔明寨来。孔明令入,杨锋等拜于帐下曰:“某等子侄皆感丞相恩德,故擒孟获、孟优等呈献。”孔明重赏之,令驱孟获入。孔明笑曰:“汝今番心服乎?”获曰:“非汝之能,乃吾洞中之人,自相残害,以致如此。要杀便杀,只是不服!”孔明曰:“汝赚吾入无水之地,更以哑泉、灭泉、黑泉、柔泉如此之毒,吾军无恙,岂非天意乎?汝何如此执迷?”获又曰:“吾祖居银坑山中,有三江之险,重关之固。汝若就彼擒之,吾当子子孙孙,倾心服事。”孔明曰:“吾再放汝回去,重整兵马,与吾共决胜负;如那时擒住,汝再不服,当灭九族。”叱左右去其缚,放起孟获。获再拜而去。孔明又将孟优并朵思大王皆释其缚,赐酒食压惊。二人悚惧,不敢正视。孔明令鞍马送回。正是:深临险地非容易,更展奇谋岂偶然! 未知孟获整兵再来,胜负如何,且看下文分解。 (本章完) -第90章 驱巨善六破蛮兵 烧藤甲七擒孟获 +第90章 驱巨善六破蛮兵 烧藤甲七擒孟获   却说孔明放了孟获等一干人,杨锋父子皆封官爵,重赏洞兵。杨锋等拜谢而去。孟获等连夜奔回银坑洞。那洞外有三江:乃是泸水、甘南水、西城水。三路水会合,故为三江。其洞北近平坦三百余里,多产万物。洞西二百里,有盐井。西南二百里,直抵泸、甘。正南三百里,乃是梁都洞,洞中有山,环抱其洞;山上出银矿,故名为银坑山。山中置宫殿楼台,以为蛮王巢穴。其中建一祖庙,名曰“家鬼”。四时杀牛宰马享祭,名为“卜鬼”。每年常以蜀人并外乡之人祭之。若人患病,不肯服药,只祷师巫,名为“药鬼”。其处无刑法,但犯罪即斩。有女长成,却于溪中沐浴,男女自相混淆,任其自配,父母不禁,名为“学艺”。年岁雨水均调,则种稻谷;倘若不熟,杀蛇为羹,煮象为饭。每方隅之中,上户号曰“洞主”,次曰“酋长”。每月初一、十五两日,皆在三江城中买卖,转易货物。其风俗如此。 却说孟获在洞中,聚集宗党千余人,谓之曰:“吾屡受辱于蜀兵,立誓欲报之。汝等有何高见?”言未毕,一人应曰:“吾举一人,可破诸葛亮。”众视之,乃孟获妻弟,现为八番部长,名曰带来洞主。获大喜,急问何人。带来洞主曰:“此去西南八纳洞,洞主木鹿大王,深通法术:出则骑象,能呼风唤雨,常有虎豹豺狼、毒蛇恶蝎跟随。手下更有三万神兵,甚是英勇。大王可修书具礼,某亲往求之。此人若允,何惧蜀兵哉!”获忻然,令国舅赍书而去。却令朵思大王守把三江城,以为前面屏障。却说孔明提兵直至三江城,遥望见此城三面傍江,一面通旱;即遣魏延、赵云同领一军,于旱路打城。军到城下时,城上弓弩齐发:原来洞中之人,多习弓弩,一弩齐发十矢,箭头上皆用毒药;但有中箭者,皮肉皆烂,见五脏而死。赵云、魏延不能取胜,回见孔明,言药箭之事。孔明自乘小车,到军前看了虚实,回到寨中,令军退数里下寨。 蛮兵望见蜀兵远退,皆大笑作贺,只疑蜀兵惧怯而退,因此夜间安心稳睡,不去哨探。却说孔明约军退后,即闭寨不出。一连五日,并无号令。黄昏左侧,忽起微风。孔明传令曰:“每军要衣襟一幅,限一更时分应点。无者立斩。”诸将皆不知其意,众军依令预备。初更时分,又传令曰:“每军衣襟一幅,包土一包。无者立斩。”众军亦不知其意,只得依令预备。孔明又传令曰:“诸军包土,俱在三江城下交割。先到者有赏。”众军闻令,皆包净土,飞奔城下。孔明令积土为蹬道,先上城者为头功。于是蜀兵十余万,并降兵万余,将所包之土,一齐弃于城下。一霎时,积土成山,接连城上。一声暗号,蜀兵皆上城。蛮兵急放弩时,大半早被执下,余者弃城而走。朵思大王死于乱军之中。蜀将督军分路剿杀。孔明取了三江城,所得珍宝,皆赏三军。败残蛮兵逃回见孟获说:“朵思大王身死。失了三江城。”获大惊。正虑之间,人报蜀兵已渡江,现在本洞前下寨。孟获甚是慌张。 @@ -1648,7 +1648,7 @@ 却说孔明犒军已毕,班师回蜀,令魏延引本部兵为前锋。延引兵方至泸水,忽然阴云四合,水面上一阵狂风骤起,飞沙走石,军不能进。延退兵回报孔明。孔明遂请孟获问之。正是:塞外蛮人方帖服,水边鬼卒又猖狂。 未知孟获所言若何,且看下文分解。 (本章完) -第91章 祭泸水汉相班师 伐中原武侯上表 +第91章 祭泸水汉相班师 伐中原武侯上表   却说孔明班师回国,孟获率引大小洞主酋长及诸部落,罗拜相送。前军至泸水,时值九月秋天,忽然阴云布合,狂风骤起;兵不能渡,回报孔明。孔明遂问孟获,获曰:“此水原有猖神作祸,往来者必须祭之。”孔明曰:“用何物祭享?”获曰:“旧时国中因猖神作祸,用七七四十九颗人头并黑牛白羊祭之,自然风恬浪静,更兼连年丰稔。”孔明曰:“吾今事已平定,安可妄杀一人?”遂自到泸水岸边观看。果见阴风大起,波涛汹涌,人马皆惊。孔明甚疑,即寻土人问之。土人告说:“自丞相经过之后,夜夜只闻得水边鬼哭神号。自黄昏直至天晓,哭声不绝。瘴烟之内,阴鬼无数。因此作祸,无人敢渡。”孔明曰:“此乃我之罪愆也。前者马岱引蜀兵千余,皆死于水中;更兼杀死南人,尽弃此处。狂魂怨鬼,不能解释,以致如此。吾今晚当亲自往祭。”土人曰:“须依旧例,杀四十九颗人头为祭,则怨鬼自散也。”孔明曰:“本为人死而成怨鬼,岂可又杀生人耶?吾自有主意。”唤行厨宰杀牛马;和面为剂,塑成人头,内以牛羊等肉代之,名曰馒头。当夜于泸水岸上,设香案,铺祭物,列灯四十九盏,扬幡招魂;将馒头等物,陈设于地。三更时分,孔明金冠鹤氅,亲自临祭,令董厥读祭文。其文曰:“维大汉建兴三年秋九月一日,武乡侯、领益州牧、丞相诸葛亮,谨陈祭仪,享于故殁王事蜀中将校及南人亡者阴魂曰:我大汉皇帝,威胜五霸,明继三王。昨自远方侵境,异俗起兵;纵虿尾以兴妖,盗狼心而逞乱。我奉王命,问罪遐荒;大举貔貅,悉除蝼蚁;雄军云集,狂寇冰消;才闻破竹之声,便是失猿之势。但士卒儿郎,尽是九州豪杰;官僚将校,皆为四海英雄:习武从戎,投明事主,莫不同申三令,共展七擒;齐坚奉国之诚,并效忠君之志。 何期汝等偶失兵机,缘落奸计:或为流矢所中,魂掩泉台;或为刀剑所伤,魄归长夜:生则有勇,死则成名,今凯歌欲还,献俘将及。汝等英灵尚在,祈祷必闻:随我旌旗,逐我部曲,同回上国,各认本乡,受骨肉之蒸尝,领家人之祭祀;莫作他乡之鬼,徒为异域之魂。我当奏之天子,使汝等各家尽沾恩露,年给衣粮,月赐廪禄。用兹酬答,以慰汝心。至于本境土神,南方亡鬼,血食有常,凭依不远;生者既凛天威,死者亦归王化,想宜宁帖,毋致号啕。聊表丹诚,敬陈祭祀。呜呼,哀哉!伏惟尚飨!”读毕祭文,孔明放声大哭,极其痛切,情动三军,无不下泪。孟获等众,尽皆哭泣。只见愁云怨雾之中,隐隐有数千鬼魂,皆随风而散。于是孔明令左右将祭物尽弃于泸水之中。次日,孔明引大军俱到泸水南岸,但见云收雾散,风静浪平。蜀兵安然尽渡泸水,果然鞭敲金镫响,人唱凯歌还。行到永昌,孔明留王伉、吕凯守四郡;发付孟获领众自回,嘱其勤政驭下,善抚居民,勿失农务。孟获涕泣拜别而去。 孔明自引大军回成都。后主排銮驾出郭三十里迎接,下辇立于道傍,以侯孔明。孔明慌下车伏道而言曰:“臣不能速平南方,使主上怀忧,臣之罪也。”后主扶起孔明,并车而回,设太平筵会,重赏三军。自此远邦进贡来朝者二百余处。孔明奏准后主,将殁于王事者之家,一一优恤。人心欢悦,朝野清平。却说魏主曹丕,在位七年,即蜀汉建兴四年也。丕先纳夫人甄氏,即袁绍次子袁熙之妇,前破邺城时所得。后生一子,名睿,字元仲,自幼聪明,不甚爱之。后丕又纳安平广宗人郭永之女为贵妃,甚有颜色;其父尝曰:“吾女乃女中之王也。”故号为女王。自丕纳为贵妃,因甄夫人失宠,郭贵妃欲谋为后,却与幸臣张韬商议。时丕有疾,韬乃诈称于甄夫人宫中掘得桐木偶人,上书天子年月日时,为魇镇之事。丕大怒,遂将甄夫人赐死,立郭贵妃为后。因无出,养曹睿为己子。虽甚爱之,不立为嗣。 @@ -1666,7 +1666,7 @@ 孔明出师,后主引百官送于北门外十里。孔明辞了后主,旌旗蔽野,戈戟如林,率军望汉中迤逦进发。却说边庭探知此事,报入洛阳。是日曹睿设朝,近臣奏曰:“边官报称:诸葛亮率领大兵三十余万,出屯汉中,令赵云、邓芝为前部先锋,引兵入境。”睿大惊,问群臣曰:“谁可为将,以退蜀兵?”忽一人应声而出曰:“臣父死于汉中,切齿之恨,未尝得报。今蜀兵犯境,臣愿引本部猛将,更乞陛下赐关西之兵,前往破蜀,上为国家效力,下报父仇,臣万死不恨!”众视之,乃夏侯渊之子夏侯楙也。楙字子休,其性最急,又最吝,自幼嗣与夏侯惇为子。后夏侯渊为黄忠所斩,曹操怜之,以女清河公主招楙为驸马,因此朝中钦敬。虽掌兵权,未尝临阵。当时自请出征,曹睿即命为大都督,调关西诸路军马前去迎敌。司徒王朗谏曰:“不可。夏侯驸马素不曾经战,今付以大任,非其所宜。更兼诸葛亮足智多谋,深通韧略,不可轻敌。”夏侯楙叱曰:“司徒莫非结连诸葛亮,欲为内应耶?吾自幼从父学习韬略,深通兵法。汝何欺我年幼?吾若不生擒诸葛亮,誓不回见天子!”王朗等皆不敢言。夏侯楙辞了魏主,星夜到长安,调关西诸路军马二十余万,来敌孔明。正是:欲秉白旄摩将士,却教黄吻掌兵权。 未知胜负如何,且看下文分解。 (本章完) -第92章 赵子龙力斩五将 诸葛亮智取三城 +第92章 赵子龙力斩五将 诸葛亮智取三城   却说孔明率兵前至沔阳,经过马超坟墓,乃令其弟马岱挂孝,孔明亲自祭之。祭毕,回到寨中,商议进兵。忽哨马报道:“魏主曹睿遣驸马夏侯楙,调关中诸路军马,前来拒敌。”魏延上帐献策曰:“夏侯楙乃膏粱子弟,懦弱无谋。延愿得精兵五干,取路出褒中,循秦岭以东,当子午谷而投北,不过十日,可到安长。夏侯楙若闻某骤至,必然弃城望横门邸阁而走。某却从东方而来,丞相可大驱士马,自斜谷而进。如此行之,则咸阳以西,一举可定也。”孔明笑曰:“此非万全之计也。汝欺中原无好人物,倘有人进言,于山僻中以兵截杀,非惟五千人受害,亦大伤锐气。决不可用。”魏延又曰:“丞相兵从大路进发,彼必尽起关中之兵,于路迎敌,则旷日持久,何时而得中原?”孔明曰:“吾从陇右取平坦大路,依法进兵,何忧不胜!”遂不用魏延之计。魏延怏怏不悦。孔明差人令赵云进兵。却说夏侯楙在长安聚集诸路军马。时有西凉大将韩德,善使开山大斧,有万夫不当之勇,引西羌诸路兵八万到来;见了夏侯楙,楙重赏之,就遣为先锋。 德有四子,皆精通武艺,弓马过人:长子韩瑛,次子韩瑶,三子韩琼,四子韩班。韩德带四子并西羌兵八万,取路至凤鸣山,正遇蜀兵。两阵对圆。韩德出马,四子列于两边。德厉声大骂曰:“反国之贼,安敢犯吾境界!”赵云大怒,挺枪纵马,单搦韩德交战。长子韩瑛,跃马来迎;战不三合,被赵云一枪刺死于马下。次子韩瑶见之,纵马挥刀来战。赵云施逞旧日虎威,抖擞精神迎战。瑶抵敌不住。三子韩琼,急挺方天戟骤马前来夹攻。云全然不惧,枪法不乱。四子韩琪,见二兄战云不下,也纵马抡两口日月刀而来,围住赵云。云在中央独战三将。少时,韩琪中枪落马,韩阵中偏将急出救去。云拖枪便走。韩琼按戟,急取弓箭射之,连放三箭,皆被云用枪拨落。琼大怒,仍绰方天戟纵马赶来;却被云一箭射中面门,落马而死,韩瑶纵马举宝刀便砍赵云。云弃枪于地,闪过宝刀,生擒韩瑶归阵,复纵马取枪杀过阵来。韩德见四子皆丧于赵云之手,肝胆皆裂,先走入阵去。西凉兵素知赵云之名,今见其英勇如昔,谁敢交锋?赵云马到处,阵阵倒退。赵云匹马单枪,往来冲突,如入无人之境。后人有诗赞曰:“忆昔常山赵子龙,年登七十建奇功。独诛四将来冲阵,犹似当阳救主雄。” 邓芝见赵云大胜,率蜀兵掩杀,西凉兵大败而走。韩德险被赵云擒住,弃甲步行而逃。云与邓芝收军回寨。芝贺曰:“将军寿已七旬,英勇如昨。今日阵前力斩四将,世所罕有!”云曰:“丞相以吾年迈,不肯见用,吾故聊以自表耳。”遂差人解韩瑶,申报捷书,以达孔明。 @@ -1683,7 +1683,7 @@ 马遵正欲起兵,忽一人自外而入曰:“太守中诸葛亮之计矣!”众视之,乃天水冀人也,姓姜名维,字伯约。父名囧,昔日曾为天水郡功曹,因羌人乱,没于王事。维自幼博览群书,兵法武艺,无所不通;奉母至孝,郡人敬之;后为中郎将,就参本郡军事。当日姜维谓马遵曰:“近闻诸葛亮杀败夏侯楙,困于南安,水泄不通,安得有人自重围之中而出?又且裴绪乃无名下将,从不曾见;况安定报马,又无公文,以此察之,此人乃蜀将诈称魏将。赚得太守出城,料城中无备,必然暗伏一军于左近,乘虚而取天水也,”马遵大悟曰:“非伯约之言,则误中奸计矣!”维笑曰:“太守放心。某有一计,可擒诸葛亮,解南安之危。”正是:运筹又遇强中手,斗智还逢意外人。 未知其计如何,且看下文分解。 (本章完) -第93章 姜伯约归降孔明 武乡侯骂死王朝 +第93章 姜伯约归降孔明 武乡侯骂死王朝   却说姜维献计于马遵曰:“诸葛亮必伏兵于郡后,赚我兵出城,乘虚袭我。某愿请精兵三千,伏于要路。太守随后发兵出城,不可远去,止行三十里便回;但看火起为号,前后来攻,可获大胜。如诸葛亮自来,必为某所擒矣。”遵用其计,付精兵与姜维去讫,然后自与梁虔引兵出城等候;只留梁绪、尹赏守城。原来孔明果遣赵云引一军埋伏于山僻之中,只待天水人马离城,便乘虚袭之。当日细作回报赵云,说天水太守马遵,起兵出城,只留文官守城。赵云大喜,又令人报与张翼、高翔,教于要路截杀马遵。此二处兵亦是孔明预先埋伏。却说赵云引五千兵,径投天水郡城下,高叫曰:“吾乃常山赵子龙也!汝知中计,早献城池,免遭诛戮!”城上梁绪大笑曰:“汝中吾姜伯约之计,尚然不知耶?”云恰待攻城,忽然喊声大震,四面火光冲天。当先一员少年将军,挺枪跃马而言曰:“汝见天水姜伯约乎!”云挺枪直取姜维。战不数合,维精神倍长。云大惊,暗忖曰:“谁想此处有这般人物!”正战时,两路军夹攻来,乃是马遵、梁虔引军杀回。赵云首尾不能相顾,冲开条路,引败兵奔走,姜维赶来。亏得张翼、高翔两路军杀出,接应回去。 赵云归见孔明,说中了敌人之计。孔明惊问曰:“此是何人,识吾玄机?”有南安人告曰:“此人姓姜名维,字伯约,天水冀人也;事母至孝,文武双全,智勇足备,真当世之英杰也。”赵云又夸奖姜维枪法,与他人大不同。孔明曰:“吾今欲取天水,不想有此人。”遂起大军前来。 却说姜维回见马遵曰:“赵云败去,孔明必然自来。彼料我军必在城中。今可将本部军马,分为四枝:某引一军伏于城东,如彼兵到则截之。太守与梁虚、尹赏各引一军城外埋伏。梁绪率百姓在城上守御。”分拨已定。 @@ -1702,7 +1702,7 @@ 却说魏先锋曹遵、朱赞黄昏离寨,迤逦前进。二更左侧,遥望山前隐隐有军行动。曹遵自思曰:“郭都督真神机妙算!”遂催兵急进。到蜀寨时,将及三更。曹遵先杀入寨,却是空寨,并无一人。料知中计,急撤军回。寨中火起。朱赞兵到,自相掩杀,人马大乱。曹遵与朱赞交马,方知自相践踏。急合兵时,忽四面喊声大震,王平、马岱、张嶷、张翼杀到。曹、朱二人引心腹军百余骑,望大路奔走。忽然鼓角齐鸣,一彪军截住去路,为首大将乃常山赵子龙也,大叫曰:“贼将那里去?早早受死!”曹、朱二人夺路而走。忽喊声又起,魏延又引一彪军杀到。曹、朱二人大败,夺路奔回本寨。守寨军士,只道蜀兵来劫寨,慌忙放起号火。左边曹真杀至,右边郭淮杀至,自相掩杀。背后三路蜀兵杀到:中央魏延,左边关兴,右边张苞,大杀一阵。魏兵败走十余里,魏将死者极多。孔明全获大胜,方始收兵。曹真、郭淮收拾败军回寨,商议曰:“今魏兵势孤,蜀兵势大,将何策以退之?”淮曰:“胜负乃兵家常事,不足为忧。某有一计,使蜀兵首尾不能相顾,定然自走矣。”正是:可怜魏将难成事,欲向西方索救兵。 未知其计如何,且看下文分解。 (本章完) -第94章 诸葛亮乘雪破羌兵 司马懿克日擒孟达 +第94章 诸葛亮乘雪破羌兵 司马懿克日擒孟达   却说郭淮谓曹真曰:“西羌之人,自太祖时连年入贡,文皇帝亦有恩惠加之;我等今可据住险阻,遣人从小路直入羌中求救,许以和亲,羌人必起兵袭蜀兵之后。吾却以大兵击之,首尾夹攻,岂不大胜?”真从之,即遣人星夜驰书赴羌。 却说西羌国王彻里吉,自曹操时年年入贡;手下有一文一武:文乃雅丹丞相,武乃越吉元帅。时魏使赍金珠并书到国,先来见雅丹丞相,送了礼物,具言求救之意。雅丹引见国王,呈上书礼。彻里吉览了书,与众商议。雅丹曰:“我与魏国素相往来,今曹都督求救,且许和亲,理合依允。”彻里吉从其言,即命雅丹与越吉元帅起羌兵一十五万,皆惯使弓弩、枪刀、蒺藜、飞锤等器;又有战车,用铁叶裹钉,装载粮食军器什物:或用骆驼驾车,或用骡马驾车,号为铁车兵。二人辞了国王,领兵直扣西平关。守关蜀将韩祯,急差人赍文报知孔明。孔明闻报,问众将曰:“谁敢去退羌兵?”张苞、关兴应曰:“某等愿往。”孔明曰:“汝二人要去,奈路途不熟。”遂唤马岱曰:“汝素知羌人之性,久居彼处,可作向导。”便起精兵五万,与兴、苞二人同往。兴、苞等引兵而去。行有数日,早遇羌兵。关兴先引百余骑登山坡看时,只见羌兵把铁车首尾相连,随处结寨;车上遍排兵器,就似城池一般。兴睹之良久,无破敌之策,回寨与张苞、马岱商议。岱曰:“且待来日见阵,观看虚实,另作计议。”次早,分兵三路:关兴在中,张苞在左,马岱在右,三路兵齐进。羌兵阵里,越吉元帅手挽铁锤,腰悬宝雕弓,跃马奋勇而出。关兴招三路兵径进。忽见羌兵分在两边,中央放出铁车,如潮涌一般,弓弩一齐骤发。蜀兵大败,马岱、张苞两军先退;关兴一军,被羌兵一裹,直围入西北角上去了。 兴在垓心,左冲右突,不能得脱;铁车密围,就如城池。蜀兵你我不能相顾。兴望山谷中寻路而走。看看天晚,但见一簇皂旗,蜂拥而来,一员羌将,手提铁锤大叫曰:“小将休走!吾乃越吉元帅也!”关兴急走到前面,尽力纵马加鞭,正遇断涧,只得回马来战越吉。兴终是胆寒,抵敌不住,望涧中而逃;被越吉赶到,一铁锤打来,兴急闪过,正中马胯。那马望涧中便倒,兴落于水中。忽听得一声响处,背后越吉连人带马,平白地倒下水来。兴就水中挣起看时,只见岸上一员大将,杀退羌兵。兴提刀待砍越吉,吉跃水而走。关兴得了越吉马,牵到岸上,整顿鞍辔,绰刀上马。只见那员将,尚在前面追杀羌兵。兴自思此人救我性命,当与相见,遂拍马赶来。看看至近,只见云雾之中,隐隐有一大将,面如重枣,眉若卧蚕,绿袍金铠,提青龙刀,骑赤兔马,手绰美髯,分明认得是父亲关公。兴大惊。忽见关公以手望东南指曰:“吾儿可速望此路去。吾当护汝归寨。”言讫不见。关兴望东南急走。 @@ -1722,7 +1722,7 @@ 李辅、邓贤大开城门,迎接司马懿入城。抚民劳军已毕,遂遣人奏知魏主曹睿。睿大喜,教将孟达首级去洛阳城市示众;加申耽、申仪官职,就随司马懿征进;命李辅、邓贤守新城、上庸。却说司马懿引兵到长安城外下寨。懿入城来见魏主。睿大喜曰:“朕一时不明,误中反间之计,悔之无及。今达造反,非卿等制之,两京休矣!”懿奏曰:“臣闻申仪密告反情,意欲表奏陛下,恐往复迟滞,故不待圣旨,星夜而去。若待奏闻,则中诸葛亮之计也。”言罢,将孔明回孟达密书奉上。睿看毕,大喜曰:“卿之学识,过于孙、吴矣!”赐金钺斧一对,后遇机密重事,不必奏闻,便宜行事。就令司马懿出关破蜀。懿奏曰:“臣举一大将,可为先锋。”睿曰:“卿举何人?”懿曰:“右将军张郃,可当此任。”睿笑曰:“朕正欲用之。”遂命张郃为前部先锋,随司马懿离长安来破蜀兵。正是:既有谋臣能用智,又求猛将助施威。 未知胜负如何,且看下文分解。 (本章完) -第95章 马谡拒谏失街亭 武侯弹琴退仲达 +第95章 马谡拒谏失街亭 武侯弹琴退仲达   却说魏主曹睿令张郃为先锋,与司马懿一同征进;一面令辛毗、孙礼二人领兵五万,往助曹真。二人奉诏而去。且说司马懿引二十万军,出关下寨,请先锋张郃至帐下曰:“诸葛亮平生谨慎,未敢造次行事。若是吾用兵,先从子午谷径取长安,早得多时矣。他非无谋,但怕有失,不肯弄险。今必出军斜谷,来取郿城。若取郿城,必分兵两路,一军取箕谷矣。吾已发檄文,令子丹拒守郿城,若兵来不可出战;令孙礼、辛毗截住箕谷道口,若兵来则出奇兵击之。”郃曰:“今将军当于何处进兵?”懿曰:“吾素知秦岭之西,有一条路,地名街亭;傍有一城,名列柳城:此二处皆是汉中咽喉。诸葛亮欺子丹无备,定从此进。吾与汝径取街亭,望阳平关不远矣。亮若知吾断其街亭要路,绝其粮道,则陇西一境,不能安守,必然连夜奔回汉中去也。彼若回动,吾提兵于小路击之,可得全胜;若不归时,吾却将诸处小路,尽皆垒断,俱以兵守之。一月无粮,蜀兵皆饿死,亮必被吾擒矣。”张郃大悟,拜伏于地曰:“都督神算也!”懿曰:“虽然如此,诸葛亮不比孟达。将军为先锋,不可轻进。当传与诸将:循山西路,远远哨探。如无伏兵,方可前进。若是怠忽,必中诸葛亮之计。”张郃受计引军而行。 却说孔明在祁山寨中,忽报新城探细人来到。孔明急唤入问之,细作告曰:“司马懿倍道而行,八日已到新城,孟达措手不及;又被申耽、申仪、李辅、邓贤为内应:孟达被乱军所杀。今司马懿撤兵到长安,见了魏主,同张郃引兵出关,来拒我师也。”孔明大惊曰:“孟达做事不密,死固当然。今司马懿出关,必取街亭,断吾咽喉之路。”便问:“谁敢引兵去守街亭?”言未毕,参军马谡曰:“某愿往。”孔明曰:“街亭虽小,干系甚重:倘街亭有失,吾大军皆休矣。汝虽深通谋略,此地奈无城郭,又无险阻,守之极难。”谡曰:“某自幼熟读兵书,颇知兵法。岂一街亭不能守耶?”孔明曰:“司马懿非等闲之辈;更有先锋张郃,乃魏之名将:恐汝不能敌之。”谡曰:“休道司马懿、张郃,便是曹睿亲来,有何惧哉!若有差失,乞斩全家。”孔明曰:“军中无戏言。”谡曰:“愿立军令状。”孔明从之,谡遂写了军令状呈上。孔明曰:“吾与汝二万五千精兵,再拨一员上将,相助你去。”即唤王平分付曰:“吾素知汝平生谨慎,故特以此重任相托。 汝可小心谨守此地:下寨必当要道之处,使贼兵急切不能偷过。安营既毕,便画四至八道地理形状图本来我看。凡事商议停当而行,不可轻易。如所守无危,则是取长安第一功也。戒之!戒之!”二人拜辞引兵而去。孔明寻思,恐二人有失,又唤高翔曰:“街亭东北上有一城,名列柳城,乃山僻小路,此可以屯兵扎寨。与汝一万兵,去此城屯扎。但街亭危,可引兵救之。”高翔引兵而去。孔明又思:高翔非张郃对手,必得一员大将,屯兵于街亭之右,方可防之,遂唤魏延引本部兵去街亭之后屯扎。延曰:“某为前部,理合当先破敌,何故置某于安闲之地?’孔明曰:“前锋破敌,乃偏裨之事耳。今令汝接应街亭,当阳平关冲要道路,总守汉中咽喉:此乃大任也,何为安闲乎?汝勿以等闲视之,失吾大事。切宜小心在意!”魏延大喜,引兵而去。孔明恰才心安,乃唤赵云、邓芝分付曰:“今司马懿出兵,与旧日不同。汝二人各引一军出箕谷,以为疑兵。如逢魏兵,或战、或不战,以惊其心。吾自统大军,由斜谷径取郿城;若得郿城,长安可破矣。”二人受命而去。孔明令姜维作先锋,兵出斜谷。 @@ -1742,7 +1742,7 @@ 行至一大林,忽听得背后大喝一声曰:“赵子龙在此!”惊得魏兵落马者百余人,余者皆越岭而去。万政勉强来敌,被云一箭射中盔缨,惊跌于涧中。云以枪指之曰:“吾饶汝性命回去!快教郭淮赶来!”万政脱命而回。云护送车仗人马,望汉中而去,沿途并无遗失。曹真、郭淮复夺三郡,以为己功。却说司马懿分兵而进。此时蜀兵尽回汉中去了,懿引一军复到西城,因问遗下居民及山僻隐者,皆言孔明止有二千五百军在城中,又无武将,只有几个文官,别无埋伏。武功山小民告曰:“关兴、张苞,只各有三千军,转山呐喊,鼓噪惊追,又无别军,并不敢厮杀。”懿悔之不及,仰天叹曰:“吾不如孔明也!”遂安抚了诸处官民,引兵径还长安,朝见魏主。睿曰:“今日复得陇西诸郡,皆卿之功也。”懿奏曰:“今蜀兵皆在汉中,未尽剿灭。臣乞大兵并力收川,以报陛下。”睿大喜,令懿即便兴兵。忽班内一人出奏曰:“臣有一计,足可定蜀降吴。”正是:蜀中将相方归国,魏地君臣又逞谋。 未知献计者是谁,且看下文分解。 (本章完) -第96章 孔明挥泪斩马谡 周鲂断发赚曹休 +第96章 孔明挥泪斩马谡 周鲂断发赚曹休   却说献计者,乃尚书孙资也。曹睿问曰:“卿有何妙计?”资奏曰:“昔太祖武皇帝收张鲁时,危而后济;常对群臣曰:南郑之地,真为天狱。中斜谷道为五百里石穴,非用武之地。今若尽起天下之兵伐蜀,则东吴又将入寇。不如以现在之兵,分命大将据守险要,养精蓄锐。不过数年,中国日盛,吴、蜀二国必自相残害:那时图之,岂非胜算?乞陛下裁之。”睿乃问司马懿曰:“此论若何?懿奏曰:“孙尚书所言极当。”睿从之,命懿分拨诸将守把险要,留郭淮、张郃守长安。大赏三军,驾回洛阳。却说孔明回到汉中,计点军士,只少赵云、邓芝,心中甚忧;乃令关兴、张苞,各引一军接应。 二人正欲起身,忽报赵云、邓芝到来,并不曾折一人一骑;辎重等器,亦无遗失。孔明大喜,亲引诸将出迎。赵云慌忙下马伏地曰:“败军之将,何劳丞相远接?”孔明急扶起,执手而言曰:“是吾不识贤愚,以致如此!各处兵将败损,惟子龙不折一人一骑,何也?”邓芝告曰:“某引兵先行,子龙独自断后,斩将立功,敌人惊怕,因此军资什物,不曾遗弃。”孔明曰:“真将军也!”遂取金五十斤以赠赵云,又取绢一万匹赏云部卒。云辞曰:“三军无尺寸之功,某等俱各有罪;若反受赏,乃丞相赏罚不明也。且请寄库,候今冬赐与诸军未迟。”孔明叹曰:“先帝在日,常称子龙之德,今果如此!”乃倍加钦敬。 忽报马谡、王平、魏延、高翔至。孔明先唤王平入帐,责之曰:“吾令汝同马谡守街亭,汝何不谏之,致使失事?”平曰:“某再三相劝,要在当道筑土城,安营守把。参军大怒不从,某因此自引五千军离山十里下寨。魏兵骤至,把山四面围合,某引兵冲杀十余次,皆不能入。次日土崩瓦解,降者无数。某孤军难立,故投魏文长求救。半途又被魏兵困在山谷之中,某奋死杀出。比及归寨,早被魏兵占了。及投列柳城时,路逢高翔,遂分兵三路去劫魏寨,指望克复街亭。因见街亭并无伏路军,以此心疑。登高望之,只见魏延、高翔被魏兵围住,某即杀入重围,救出二将,就同参军并在一处。某恐失却阳平关,因此急来回守。非某之不谏也。丞相不信,可问各部将校。”孔明喝退,又唤马谡入帐。 @@ -1760,7 +1760,7 @@ 却说陆逊正望捷音,须臾,徐盛、朱桓、全琮皆到。所得车仗、牛马、驴骡、军资、器械,不计其数,降兵数万余人。逊大喜,即同太守周鲂并诸将班师还吴。吴主孙权,领文武官僚出武昌城迎接,以御盖覆逊而入。诸将尽皆升赏。权见周鲂无发,慰劳曰:“卿断发成此大事,功名当书于竹帛也。”即封周鲂为关内侯;大设筵会,劳军庆贺。陆逊奏曰:“今曹休大败,魏已丧胆;可修国书,遣使入川,教诸葛亮进兵攻之。”权从其言,遂遣使赍书入川去。正是:只因东国能施计,致令西川又动兵。 未知孔明再来伐魏,胜负如何,且看下文分解。 (本章完) -第97章 讨魏国武侯再上表 破曹兵姜维诈献书 +第97章 讨魏国武侯再上表 破曹兵姜维诈献书   却说蜀汉建兴六年秋九月,魏都督曹休被东吴陆逊大破于石亭,车仗马匹,军资器械,并皆罄尽,休惶恐之甚,气忧成病,到洛阳,疽发背而死。魏主曹睿敕令厚葬。司马懿引兵还、众将接入问曰:“曹都督兵败,即元帅之干系,何故急回耶?”懿曰:“吾料诸葛亮知吾兵败,必乘虚来取长安。倘陇西紧急,何人救之?吾故回耳。”众皆以为惧怯,哂笑而退。 却说东吴遣使致书蜀中,请兵伐魏,并言大破曹休之事:一者显自己威风,二者通和会之好。后主大喜,令人持书至汉中,报知孔明。时孔明兵强马壮,粮草丰足,所用之物,一切完备,正要出师。听知此信,即设宴大会诸将,计议出师。忽一阵大风,自东北角上而起,把庭前松树吹折。众皆大惊。孔明就占一课,曰:“此风主损一大将!”诸将未信。正饮酒间,忽报镇南将军赵云长子赵统、次子赵广,来见丞相。孔明大惊,掷杯于地曰:“子龙休矣!”二子入见,拜哭曰:“某父昨夜三更病重而死。”孔明跌足而哭曰:“子龙身故,国家损一栋梁,吾去一臂也!”众将无不挥涕。孔明令二子入成都面君报丧。后主闻云死,放声大哭曰“朕昔年幼,非子龙则死于乱军之中矣!”即下诏追赠大将军,谥封顺平侯,敕葬于成都锦屏山之东;建立庙堂,四时享祭。后人有诗曰:“常山有虎将,智勇匹关张。汉水功勋在,当阳姓字彰。两番扶幼主,一念答先皇。青史书忠烈,应流百世芳。” 却说后主思念赵云昔日之功,祭葬甚厚;封赵统为虎贲中郎,赵广为牙门将,就令守坟。二人辞谢而去。忽近臣奏曰:“诸葛丞相将军马分拨已定,即日将出师伐魏。”后主问在朝诸臣,诸臣多言未可轻动。后主疑虑未决。忽奏丞相令杨仪赍出师表至。后主宜入,仪呈上表章。后主就御案上拆视,其表曰:“先帝虑汉贼不两立,王业不偏安,故托臣以讨贼也。以先帝之明,量臣之才,故知臣伐贼,才弱敌强也。然不伐贼,王业亦亡。惟坐而待亡,孰与伐之?是故托臣而弗疑也。臣受命之日,寝不安席,食不甘味;思惟北征,宜先入南:故五月渡沪,深入不毛,并日而食。——臣非不自惜也,顾王业不可偏安于蜀都,故冒危难以奉先帝之遗意。而议者谓为非计。今贼适疲于西,又务于东,兵法“乘劳”:此进趋之时也。谨陈其事如左:高帝明并日月,谋臣渊深,然涉险被创,危然后安;今陛下未及高帝,谋臣不如良、平,而欲以长策取胜,坐定天下,此臣之未解一也。刘繇、王朗,各据州郡,论安言计,动引圣人,群疑满腹,众难塞胸;今岁不战,明年不征,使孙权坐大,遂并江东,此臣之未解二也。 @@ -1779,7 +1779,7 @@ 却说曹真听知折了费耀,悔之不及,遂与郭淮商议退兵之策。于是孙礼、辛毗星夜具表申奏魏主,言蜀兵又出祁山,曹真损兵折将,势甚危急。睿大惊,即召司马懿入内曰:“曹真损兵折将,蜀兵又出祁山。卿有何策,可以退之?”懿曰:“臣已有退诸葛亮之计。不用魏军扬武耀威,蜀兵自然走矣。”正是:已见子丹无胜术,全凭仲达有良谋。 未知其计如何,且看下文分解。 (本章完) -第98章 追汉军王双受诛 袭陈仓武侯取胜 +第98章 追汉军王双受诛 袭陈仓武侯取胜   却说司马懿奏曰:“臣尝奏陛下,言孔明必出陈仓,故以郝昭守之,今果然矣。彼若从陈仓入寇,运粮甚便。今幸有郝昭、王双守把,不敢从此路运粮。其余小道,搬运艰难。臣算蜀兵行粮止有一月,利在急战。我军只宜久守。陛下可降诏,令曹真坚守诸路关隘,不要出战。不须一月,蜀兵自走。那时乘虚而击之,诸葛亮可擒也。”睿欣然曰:“卿既有先见之明,何不自引一军以袭之?”懿曰:“臣非惜身重命,实欲存下此兵,以防东吴陆逊耳。孙权不久必将僭号称尊;如称尊号,恐陛下伐之,定先入寇也:臣故欲以兵待之。”正言间,忽近臣奏曰:“曹都督奏报军情。”懿曰:“陛下可即令人告戒曹真:凡追赶蜀兵,必须观其虚实,不可深入重地,以中诸葛亮之计。”睿即时下诏,遣太常卿韩暨持节告戒曹真:“切不可战,务在谨守;只待蜀兵退去,方才击之。”司马懿送韩暨于城外,嘱之曰:“吾以此功让与子丹;公见子丹,休言是吾所陈之意,只道天子降诏,教保守为上。追赶之人,大要仔细,勿遣性急气躁者追之。”暨辞去。 却说曹真正升帐议事,忽报天子遣太常卿韩暨持节至。真出寨接入,受诏已毕,退与郭淮、孙礼计议。淮笑曰:“此乃司马仲达之见也。”真曰:“此见若何?”淮曰:“此言深识诸葛亮用兵之法。久后能御蜀兵者,必仲达也。”真曰:“倘蜀兵不退,又将如何?”淮曰:“可密令人去教王双,引兵于小路巡哨,彼自不敢运粮。待其粮尽兵退,乘势追击,可获全胜。”孙礼曰:“某去祁山虚妆做运粮兵,车上尽装干柴茅草,以硫黄焰硝灌之,却教人虚报陇西运粮到。若蜀人无粮,必然来抢。待人其中,放火烧车,外以伏兵应之,可胜矣。”真喜曰:“此计大妙!”即令孙礼引兵依计而行。又遣人教王双引兵于小路上巡哨,郭淮引兵提调箕谷、街亭,令诸路军马守把险要。真又令张辽子张虎为先锋,乐进子乐綝为副先锋,同守头营,不许出战。却说孔明在祁山寨中,每日今人挑战,魏兵坚守不出。孔明唤姜维等商议曰:“魏兵坚守不出,是料吾军中无粮也。 今陈仓转运不通,其余小路盘涉艰难,吾算随军粮草,不敷一月用度,如之奈何?”正踌躇间,忽报:“陇西魏军运粮数千车于祁山之西,运粮官乃孙礼也。”孔明曰:“其人如何?”有魏人告曰:“此人曾随魏主出猎于大石山,忽惊起一猛虎,直奔御前,孙礼下马拔剑斩之。从此封为上将军。乃曹真心腹人也。”孔明笑曰:“此是魏将料吾乏粮,故用此计:车上装载者,必是茅草引火之物。吾平生专用火攻,彼乃欲以此计诱我耶?彼若知吾军去劫粮车,必来劫吾寨矣。可将计就计而行。”遂唤马岱分付曰:“汝引三千军径到魏兵屯粮之所,不可入营,但于上风头放火。若烧着车仗,魏兵必来围吾寨。”又差马忠、张嶷各引五千兵在外围住,内外夹攻。三人受计去了。又唤关兴、张苞分付曰:“魏兵头营接连四通之路。今晚若西山火起,魏兵必来劫吾营。汝二人却伏于魏寨左右,只等他兵出寨,汝二人便可劫之。”又唤吴班、吴懿分付曰:“汝二人各引一军伏于营外。如魏兵到,可截其归路。”孔明分拨已毕,自在祁山上凭高而坐。 @@ -1799,7 +1799,7 @@ 遂辞帝出朝,径到曹真府下,先令人入府报知,懿方进见。问病毕,懿曰:“东吴、西蜀会合,兴兵入寇,今孔明又出祁山下寨,明公知之乎?”真惊讶曰:“吾家人知我病重,不令我知。似此国家危急,何不拜仲达为都督,以退蜀兵耶?”懿曰:“某才薄智浅,不称其职。”真曰:“取印与仲达。”懿曰:“都督少虑。某愿助一臂之力,只不敢受此印也。”真跃起曰:“如仲达不领此任,中国必危矣!吾当抱病见帝以保之!懿曰:“天子已有恩命,但懿不敢受耳。”真大喜曰:“仲达今领此任,可退蜀兵。”懿见真再三让印,遂受之,入内辞了魏主,引兵往长安来与孔明决战。正是:旧帅印为新帅取,两路兵惟一路来。 未知胜负如何,且看下文分解。 (本章完) -第99章 诸葛亮大破魏兵 司马懿入寇西蜀 +第99章 诸葛亮大破魏兵 司马懿入寇西蜀   蜀汉建兴七年夏四月,孔明兵在祁山,分作三寨,专候魏兵。却说司马懿引兵到长安,张郃接见,备言前事。懿令郃为先锋,戴陵为副将,引十万兵到祁山,于渭水之南下寨。郭淮、孙礼入寨参见。懿问曰:“汝等曾与蜀兵对阵否?”二人答曰:“未也。”懿曰:“蜀兵千里而来,利在速战;今来此不战,必有谋也。陇西诸路,曾有信息否?”淮曰:“已有细作探得各郡十分用心,日夜提防,并无他事。只有武都、阴平二处,未曾回报。”懿曰:“吾自差人与孔明交战。汝二人急从小路去救二郡,却掩在蜀兵之后,彼必自乱矣。” 二人受计,引兵五千,从陇西小路来救武都、阴平,就袭蜀兵之后。郭淮于路谓孙礼曰:“仲达比孔明如何?”礼曰:“孔明胜仲达多矣。”淮曰:“孔明虽胜,此一计足显仲达有过人之智。蜀兵如正攻两郡,我等从后抄到,彼岂不自乱乎?”正言间,忽哨马来报:“阴平已被王平打破了,武都已被姜维打破了。前离蜀兵不远。”礼曰:“蜀兵既已打破了城池,如何陈兵于外?必有诈也。不如速退。”郭淮从之。方传令教军退时,忽然一声炮响,山背后闪出一枝军马来,旗上大书:“汉丞相诸葛亮”,中央一辆四轮车,孔明端坐于上;左有关兴,右有张苞。孙、郭二人见之,大惊。孔明大笑曰:“郭淮、孙礼休走!司马懿之计,安能瞒得过吾?他每日令人在前交战,却教汝等袭吾军后。武都、阴平吾已取了。汝二人不早来降,欲驱兵与吾决战耶?”郭淮、孙礼听毕,大慌。忽然背后喊杀连天,王平、姜维引兵从后杀来。兴、苞二将又引军从前面杀来。两下夹攻,魏兵大败。郭、孙二人弃马爬山而走。张苞望见,骤马赶来;不期连人带马,跌入涧内,后军急忙救起,头已跌破。孔明令人送回成都养病。 却说郭、孙二人走脱,回见司马懿曰:“武都、阴平二郡已失。孔明伏于要路,前后攻杀,因此大败,弃马步行,方得逃回。”懿曰:“非汝等之罪,孔明智在吾先。可再引兵守把雍、郿二城,切勿出战。吾自有破敌之策。”二人拜辞而去。懿又唤张郃、戴陵分付曰:“今孔明得了武都、阴平,必然抚百姓以安民心,不在营中矣。汝二人各引一万精兵,今夜起身,抄在蜀兵营后,一齐奋勇杀将过来;吾却引军在前布阵,只待蜀兵势乱,吾大驱士马,攻杀进去:两军并力,可夺蜀寨也。若得此地山势,破敌何难?”二人受计引兵而去。 @@ -1817,7 +1817,7 @@ 却说曹真与司马懿商议曰:“今连阴三十日,军无战心,各有思归之意,如何禁止?”懿曰:“不如且回。”真曰:“倘孔明追来,怎生退之?”懿曰:“先伏两军断后,方可回兵。”正议间,忽使命来召。二人遂将大军前队作后队,后队作前队,徐徐而退。却说孔明计算一月秋雨将尽,天尚未晴,自提一军屯于城固,又传令教大军会于赤坡驻扎。孔明升帐唤众将言曰:“吾料魏兵必走,魏主必下诏来取曹真、司马懿兵回。吾若追之,必有准备;不如任他且去,再作良图。”忽王平令人报来,说魏兵已回。孔明分付来人,传与王平:“不可追袭。吾自有破魏兵之策。”正是:魏兵纵使能埋伏,汉相原来不肯追。 未知孔明怎生破魏,且看下文分解。 (本章完) -第100章 汉兵劫寨破曹真 武侯斗阵辱仲达 +第100章 汉兵劫寨破曹真 武侯斗阵辱仲达   却说众将闻孔明不追魏兵,俱入帐告曰:“魏兵苦雨,不能屯扎,因此回去,正好乘势追之。丞相如何不追?”孔明曰:“司马懿善能用兵,今军退必有埋伏。吾若追之,正中其计。不如纵他远去,吾却分兵径出斜谷而取祁山,使魏人不提防也。”众将曰:“取长安之地,别有路途;丞相只取祁山,何也?”孔明曰:“祁山乃长安之首也:陇西诸郡,倘有兵来,必经由此地;更兼前临渭滨,后靠斜谷,左出右入。可以伏兵,乃用武之地。吾故欲先取此,得地利也。”众将皆拜服。孔明令魏延、张嶷、杜琼、陈式出箕谷;马岱、王平、张翼、马忠出斜谷:俱会于祁山。调拨已定,孔明自提大军,令关兴、廖化为先锋,随后进发。却说曹真、司马懿二人,在后监督人马,令一军入陈仓古道探视,回报说蜀兵不来。又行旬日,后面埋伏众将皆回,说蜀兵全无音耗。真曰:“连绵秋雨,栈道断绝,蜀人岂知吾等退军耶?”懿曰:“蜀兵随后出矣。”真曰:“何以知之?”懿曰:“连日晴明,蜀兵不赶,料吾有伏兵也,故纵我兵远去;待我兵过尽,他却夺祁山矣。”曹真不信。懿曰:“子丹如何不信?吾料孔明必从两谷而来。吾与子丹各守一谷口,十日为期。若无蜀兵来,我面涂红粉,身穿女衣,来营中伏罪。”真曰:“若有蜀兵来,我愿将天子所赐玉带一条、御马一匹与你。”即分兵两路:真引兵屯于祁山之西斜谷口;懿引军屯于祁山之东箕谷口。各下寨已毕。懿先引一枝兵伏于山谷中;其余军马,各于要路安营。懿更换衣装,杂在全军之内,遍观各营。忽到一营,有一偏将仰天而怨曰:“大雨淋了许多时,不肯回去;今又在这里顿住,强要赌赛,却不苦了官军!”懿闻言,归寨升帐,聚众将皆到帐下,挨出那将来。懿叱之曰:“朝廷养军千日,用在一时。汝安敢出怨言,以慢军心!”其人不招。懿叫出同伴之人对证,那将不能抵赖。懿曰:“吾非赌赛;欲胜蜀兵,令汝各人有功回朝,汝乃妄出怨言,自取罪戾!”喝令武士推出斩之。须臾,献首帐下。众将悚然。懿曰:“汝等诸将皆要尽心以防蜀兵。听吾中军炮响,四面皆进。”众将受令而退。 却说魏延、张嶷、陈式、杜琼四将,引二万兵,取箕谷而进。正行之间,忽报参谋邓芝到来。四将问其故,芝曰:“丞相有令:如出箕谷,提防魏兵埋伏,不可轻进。”陈式曰:“丞相用兵何多疑耶?吾料魏兵连遭大雨,衣甲皆毁,必然急归;安得又有埋伏?今吾兵倍道而进,可获大胜,如何又教休进?”芝曰:“丞相计无不中,谋无不成,汝安敢违令?”式笑曰:“丞相若果多谋,不致街亭之失!”魏延想起孔明向日不听其计,亦笑曰:“丞相若听吾言,径出子午谷,此时休说长安,连洛阳皆得矣!今执定要出祁山。有何益耶?既令进兵,今又教休进。何其号令不明!”式曰:“吾自有五千兵,径出箕谷,先到祁山下寨,看丞相羞也不羞!”芝再三阻当,式只不听,径自引五千兵出箕谷去了。邓芝只得飞报孔明。 却说陈式引兵行不数里,忽听的一声炮响,四面伏兵皆出。式急退时,魏兵塞满谷口,围得铁桶相似。式左冲右突,不能得脱。忽闻喊声大震,一彪军杀入,乃是魏延。救了陈式,回到谷中,五千兵只剩得四五百带伤人马。背后魏兵赶来,却得杜琼、张嶷引兵接应,魏兵方退。陈、魏二人方信孔明先见如神,懊悔不及。 @@ -1839,7 +1839,7 @@ 却说司马懿料苟安行计停当,只待蜀兵退时,一齐掩杀。正踌躇间,忽报蜀寨空虚,人马皆去。懿因孔明多谋,不敢轻追,自引百余骑前来蜀营内踏看,教军士数灶,仍回本寨;次日,又教军士赶到那个营内,查点灶数。回报说:“这营内之灶,比前又增一分。”司马懿谓诸将曰:“吾料孔明多谋,今果添兵增灶,吾若追之,必中其计;不如且退,再作良图。”于是回军不追。孔明不折一人,望成都而去。次后,川口土人来报司马懿,说孔明退兵之时,未见添兵,只见增灶。懿仰天长叹曰:“孔明效虞诩之法,瞒过吾也!其谋略吾不如之!”遂引大军还洛阳。正是:棋逢敌手难相胜,将遇良才不敢骄。 未知孔明退回成都,竟是如何,且看下文分解。 (本章完) -第101章 出陇上诸葛妆神 奔剑阁张郃中计 +第101章 出陇上诸葛妆神 奔剑阁张郃中计   却说孔明用减兵添灶之法,退兵到汉中;司马懿恐有埋伏,不敢追赶,亦收兵回长安去了,因此蜀兵不曾折了一人。孔明大赏三军已毕,回到成都,入见后主,奏曰:“老臣出了祁山,欲取长安,忽承陛下降诏召回,不知有何大事?”后主无言可对;良久,乃曰:“朕久不见丞相之面,心甚思慕,故特诏回,一无他事。”孔明曰:“此非陛下本心,必有奸臣谗谮,言臣有异志也。”后主闻言,默然无语。孔明曰:“老臣受先帝厚恩,誓以死报。今若内有奸邪,臣安能讨贼乎?”后主曰:“朕因过听宦官之言,一时召回丞相。今日茅塞方开,悔之不及矣!”孔明遂唤众宦官究问,方知是苟安流言;急令人捕之,已投魏国去了。孔明将妄奏的宦官诛戮,余皆废出宫外;又深责蒋琬、费祎等不能觉察奸邪,规谏天子。二人唯唯服罪。孔明拜辞后主,复到汉中,一面发檄令李严应付粮草,仍运赴军前;一面再议出师。 杨仪曰:“前数兴兵,军力罢敝,粮又不继;今不如分兵两班,以三个月为期:且如二十万之兵,只领十万出祁山,住了三个月,却教这十万替回,循环相转。若此则兵力不乏,然后徐徐而进,中原可图矣。”孔明曰:“此言正合我意。吾伐中原,非一朝一夕之事,正当为此长久之计。”遂下令,分兵两班,限一百日为期,循环相转,违限者按军法处治。建兴九年春二月,孔明复出师伐魏。时魏太和五年也。魏主曹睿知孔明又伐中原,急召司马懿商议。懿曰:“今子丹已亡,臣愿竭一人之力,剿除寇贼,以报陛下。”睿大喜,设宴待之。次日,人报蜀兵寇急。睿即命司马懿出师御敌,亲排銮驾送出城外。懿辞了魏主,径到长安,大会诸路人马,计议破蜀兵之策。张郃曰:“吾愿引一军去守雍、郿,以拒蜀兵。”懿曰:“吾前军不能独当孔明之众,而又分兵为前后,非胜算也。不如留兵守上邽,余众悉往祁山。公肯为先锋否?”郃大喜曰:“吾素怀忠义,欲尽心报国,惜未遇知己;今都督肯委重任,虽万死不辞!”于是司马懿令张郃为先锋,总督大军。又令郭淮守陇西诸郡,其余众将各分道而进。 前军哨马报说:孔明率大军望祁山进发,前部先锋王平、张嶷,径出陈仓,过剑阁,由散关望斜谷而来。司马懿谓张郃曰:“今孔明长驱大进,必将割陇西小麦,以资军粮。汝可结营守祁山,吾与郭淮巡略天水诸郡,以防蜀兵割麦。”郃领诺,遂引四万兵守祁山。懿引大军望陇西而去。 @@ -1862,7 +1862,7 @@ 参军蒋琬出班奏曰:“李严乃先帝托孤之臣,乞望恩宽恕。”后主从之,即谪为庶人,徙于梓潼郡闲住。孔明回到成都,用李严子李丰为长史;积草屯粮,讲阵论武,整治军器,存恤将士:三年然后出征。两川人民军士,皆仰其恩德。光阴茬苒,不觉三年:时建兴十二年春二月。孔明入朝奏曰:“臣今存恤军士,已经三年。粮草丰足,军器完备,人马雄壮,可以伐魏。今番若不扫清奸党,恢复中原,誓不见陛下也!”后主曰:“方今已成鼎足之势,吴、魏不曾入寇,相父何不安享太平?”孔明曰:“臣受先帝知遇之恩,梦寐之间,未尝不设伐魏之策。竭力尽忠,为陛下克复中原,重兴汉室:臣之愿也。”言未毕,班部中一人出曰:“丞相不可兴兵。”众视之,乃谯周也。正是:武侯尽瘁惟忧国,太史知机又论天。 未知谯周有何议论,且看下文分解。 (本章完) -第102章 司马懿占北原渭桥 诸葛亮造木牛流马 +第102章 司马懿占北原渭桥 诸葛亮造木牛流马   却说谯周官居太史,颇明天文;见孔明又欲出师,乃奏后主曰:“臣今职掌司天台,但有祸福,不可不奏:近有群鸟数万,自南飞来,投于汉水而死,此不祥之兆;臣又观天象,见奎星躔于太白之分,盛气在北,不利伐魏;又成都人民,皆闻柏树夜哭:有此数般灾异,丞相只宜谨守,不可妄动。”孔明曰:“吾受先帝托孤之重,当竭力讨贼,岂可以虚妄之灾氛,而废国家大事耶!”遂命有司设太牢祭于昭烈之庙,涕泣拜告曰:“臣亮五出祁山,未得寸土,负罪非轻!今臣复统全师,再出祁山,誓竭力尽心,剿灭汉贼,恢复中原,鞠躬尽瘁,死而后已!”祭毕,拜辞后主,星夜至汉中,聚集诸将,商议出师。忽报关兴病亡。孔明放声大哭,昏倒于地,半晌方苏。众将再三劝解,孔明叹曰:“可怜忠义之人,天不与以寿”我今番出师,又少一员大将也!”后人有诗叹曰:“生死人常理,蜉蝣一样空。但存忠孝节,何必寿乔松。” 孔明引蜀兵三十四万,分五路而进,令姜维、魏延为先锋,皆出祁山取齐;令李恢先运粮草于斜谷道口伺候。 却说魏国因旧岁有青龙自摩坡井内而出,改为青龙元年;此时乃青龙二年春二月也。近臣奏曰:“边官飞报蜀兵三十余万,分五路复出祁山。魏主曹睿大惊,急召司马懿至,谓曰:“蜀人三年不曾入寇;今诸葛亮又出祁山,如之奈何?”懿奏曰:“臣夜观天象,见中原旺气正盛,奎星犯太白,不利于西川。今孔明自负才智,逆天而行,乃自取败亡也。臣托陛下洪福,当往破之。但愿保四人同去。”睿曰:“卿保何人?”懿曰:“夏侯渊有四子:长名霸,字仲权;次名威,字季权;三名惠,字稚权;四名和,字义权。霸、威二人,弓马熟娴;惠、和二人,谙知韬略:此四人常欲为父报仇。臣今保夏侯霸、夏侯威为左右先锋,夏侯惠;夏侯和为行军司马,共赞军机,以退蜀兵。”睿曰:“向者夏侯楙驸马违误军机,失陷了许多人马,至今羞惭不回。今此四人,亦与楙同否?”懿曰:“此四人非夏侯楙所可比也。”睿乃从其请,即命司马懿为大都督,凡将士悉听量才委用,各处兵马皆听调遣。 @@ -1887,7 +1887,7 @@ 且说魏将岑威引军驱木牛流马,装载粮米,正行之间,忽报前面有兵巡粮。岑威令人哨探,果是魏兵,遂放心前进。两军合在一处。忽然喊声大震,蜀兵就本队里杀起,大呼:“蜀中大将王平在此!”魏兵措手不及,被蜀兵杀死大半。岑威引败兵抵敌,被王平一刀斩了,余皆溃散。王平引兵尽驱木牛流马而回。败兵飞奔报入北原寨内。郭淮闻军粮被劫,疾忙引军来救。王平令兵扭转木牛流马舌头,皆弃于道上,且战且走。郭淮教且莫追,只驱回木牛流马。众军一齐驱赶,却那里驱得动?郭淮心中疑惑,正无奈何,忽鼓角喧天,喊声四起,两路兵杀来,乃魏延、姜维也。王平复引兵杀回。三路夹攻,郭淮大败而走。王平令军士将牛马舌头,重复扭转,驱赶而行。郭淮望见,方欲回兵再追,只见山后烟云突起,一队神兵拥出,一个个手执旗剑,怪异之状,驱驾木牛流马如风拥而去。郭淮大惊曰:“此必神助也!”众军见了,无不惊畏,不敢追赶。却说司马懿闻北原兵败,急自引军来救。方到半路,忽一声炮响,两路兵自险峻处杀出,喊声震地。旗上大书汉将张翼、廖化。司马懿见了大惊。魏军着慌,各自逃窜。正是:路逢神将粮遭劫,身遇奇兵命又危。 未知司马懿怎地抵敌,且看下文分解。 (本章完) -第103章 上方谷司马受困 五丈原诸葛禳星 +第103章 上方谷司马受困 五丈原诸葛禳星   却说司马懿被张翼、廖化一阵杀败,匹马单枪,望密林间而走。张翼收住后军,廖化当先追赶。看看赶上,懿着慌,绕树而转。化一刀砍去,正砍在树上;及拔出刀时,懿已走出林外。廖化随后赶出,却不知去向,但见树林之东,落下金盔一个。廖化取盔捎在马上,一直望东追赶。原来司马懿把金盔弃于林东,却反向西走去了。廖化追了一程,不见踪迹,奔出谷口,遇见姜维,同回寨见孔明。张嶷早驱木牛流马到寨,交割已毕,获粮万余石。廖化献上金盔,录为头功。魏延心中不悦,口出怨言。孔明只做不知。 且说司马懿逃回寨中,心甚恼闷。忽使命赍诏至,言东吴三路入寇,朝廷正议命将抵敌,令懿等坚守勿战。懿受命已毕,深沟高垒,坚守不出。 却说曹睿闻孙权分兵三路而来,亦起兵三路迎之:令刘劭引兵救江夏,田豫引兵救襄阳,睿自与满宠率大军救合淝。满宠先引一军至巢湖口,望见东岸战船无数,旌旗整肃。宠入军中奏魏主曰:“吴人必轻我远来,未曾提备;今夜可乘虚劫其水寨,必得全胜。”魏主曰:“汝言正合朕意。”即令骁将张球领五千兵,各带火具,从湖口攻之;满宠引兵五千,从东岸攻之。是夜二更时分,张球、满宠各引军悄悄望湖口进发;将近水寨,一齐呐喊杀入。吴兵慌乱,不战而走;被魏军四下举火,烧毁战船、粮草、器具不计其数。诸葛瑾率败兵逃走沔口。魏兵大胜而回。 @@ -1910,7 +1910,7 @@ 却说司马懿在营中坚守,忽一夜仰观天文,大喜,谓夏侯霸曰:“吾见将星失位,孔明必然有病,不久便死。你可引一千军去五丈原哨探。若蜀人攘乱,不出接战,孔明必然患病矣。吾当乘势击之。”霸引兵而去。孔明在帐中祈禳已及六夜,见主灯明亮,心中甚喜。姜维入帐,正见孔明披发仗剑,踏罡步斗,压镇将星。忽听得寨外呐喊,方欲令人出问,魏延飞步入告曰:“魏兵至矣!”延脚步急,竟将主灯扑灭。孔明弃剑而叹曰!“死生有命,不可得而禳也!”魏延惶恐,伏地请罪;姜维忿怒,拔剑欲杀魏延。 正是:万事不由人做主,一心难与命争衡。未知魏延性命如何,且看下文分解。 (本章完) -第104章 陨大星汉丞相归天 见木像魏都督丧胆 +第104章 陨大星汉丞相归天 见木像魏都督丧胆   却说姜维见魏延踏灭了灯,心中忿怒,拔剑欲杀之。孔明止之曰:“此吾命当绝,非文长之过也。”维乃收剑。孔明吐血数口,卧倒床上,谓魏延曰:“此是司马懿料吾有病,故令人来探视虚实。汝可急出迎敌。”魏延领命,出帐上马,引兵杀出寨来。夏侯霸见了魏延,慌忙引军退走。延追赶二十余里方回。孔明令魏延自回本寨把守。 姜维入帐,直至孔明榻前问安。孔明曰:“吾本欲竭忠尽力,恢复中原,重兴汉室;奈天意如此,吾旦夕将死。吾平生所学,已著书二十四篇,计十万四千一百一十二字,内有八务、七戒、六恐、五惧之法。吾遍观诸将,无人可授,独汝可传我书。切勿轻忽!”维哭拜而受。孔明又曰:“吾有‘连弩’之法,不曾用得。其法矢长八寸,一弩可发十矢,皆画成图本。汝可依法造用。”维亦拜受。孔明又曰:“蜀中诸道,皆不必多忧;惟阴平之地,切须仔细。此地虽险峻,久必有失。”又唤马岱入帐,附耳低言,授以密计;嘱曰:“我死之后,汝可依计行之。”岱领计而出。少顷,杨仪入。孔明唤至榻前,授与一锦囊,密嘱曰:“我死,魏延必反;待其反时,汝与临阵,方开此囊。那时自有斩魏延之人也。”孔明一一调度已毕,便昏然而倒,至晚方苏,便连夜表奏后主。后主闻奏大惊,急命尚书李福,星夜至军中问安,兼询后事。 李福领命,趱程赴五丈原,入见孔明,传后主之命,问安毕。孔明流涕曰:“吾不幸中道丧亡,虚废国家大事,得罪于天下。我死后,公等宜竭忠辅主。国家旧制,不可改易;吾所用之人,亦不可轻废。吾兵法皆授与姜维,他自能继吾之志,为国家出力。吾命已在旦夕,当即有遗表上奏天子也。”李福领了言语,匆匆辞去。孔明强支病体,令左右扶上小车,出寨遍观各营;自觉秋风吹面,彻骨生寒,乃长叹曰:“再不能临阵讨贼矣!悠悠苍天,曷此其极!”叹息良久。回到帐中,病转沉重,乃唤杨仪分付曰:“王平、廖化、张嶷、张翼、吴懿等,皆忠义之士,久经战阵,多负勤劳,堪可委用。我死之后,凡事俱依旧法而行。缓缓退兵,不可急骤。汝深通谋略,不必多嘱。姜伯约智勇足备,可以断后。”杨仪泣拜受命。孔明令取文房四宝,于卧榻上手书遗表,以达后主。 @@ -1927,7 +1927,7 @@ 却说杨仪、姜维排成阵势,缓缓退入栈阁道口,然后更衣发丧,扬幡举哀。蜀军皆撞跌而哭,至有哭死者。蜀兵前队正回到栈阁道口,忽见前面火光冲天,喊声震地,一彪军拦路。众将大惊,急报杨仪。正是:已见魏营诸将去,不知蜀地甚兵来。 未知来者是何处军马,且看下文分解。 (本章完) -第105章 武侯预伏锦囊计 魏主拆取承露盘 +第105章 武侯预伏锦囊计 魏主拆取承露盘 却说杨仪闻报前路有兵拦截,忙令人哨探。回报说魏延烧绝栈道,引兵拦路。仪大惊曰:“丞相在日,料此人久后必反,谁想今日果然如此!今断吾归路,当复如何?”费祎曰:“此人必先捏奏天子,诬吾等造反,故烧绝栈道,阻遏归路。吾等亦当表奏天子,陈魏延反情,然后图之。”姜维曰:“此间有一小径,名槎山,虽崎岖险峻,可以抄出栈道之后。”一面写表奏闻天子,一面将人马望槎山小道进发。 且说后主在成都,寝食不安,动止不宁;夜作一梦,梦见成都锦屏山崩倒;遂惊觉,坐而待旦,聚集文武,入朝圆梦。谯周曰:“臣昨夜仰观天文,见一星,赤色,光芒有角,自东北落于西南,主丞相有大凶之事。今陛下梦山崩,正应此兆。”后主愈加惊怖。忽报李福到,后主急召入问之。福顿首泣奏丞相已亡;将丞相临终言语,细述一遍。后主闻言大哭曰:“天丧我也!”哭倒于龙床之上。侍臣扶入后宫。吴太后闻之,亦放声大哭不已。多官无不哀恸,百姓人人涕泣。后主连日伤感,不能设朝。忽报魏延表奏杨仪造反,群臣大骇,入宫启奏后主,时吴太后亦在宫中。后主闻奏大惊,命近臣读魏延表。其略曰:“征西大将军、南郑侯臣魏延,诚惶诚恐,顿首上言:杨仪自总兵权,率众造反,劫丞相灵柩,欲引敌人入境。臣先烧绝栈道,以兵守御。 谨此奏闻。”读毕,后主曰:“魏延乃勇将,足可拒杨仪等众,何故烧绝栈道?”吴太后曰:“尝闻先帝有言:孔明识魏延脑后有反骨,每欲斩之;因怜其勇,故姑留用。今彼奏杨仪等造反,未可轻信。杨仪乃文人,丞相委以长史之任,必其人可用。今日若听此一面之词,杨仪等必投魏矣。此事当深虑远议,不可造次。”众官正商议间,忽报:长史杨仪有紧急表到。近臣拆表读曰:“长史、绥军将军臣杨仪,诚惶诚恐,顿首谨表:丞相临终,将大事委于臣,照依旧制,不敢变更,使魏延断后,姜维次之。今魏延不遵丞相遗语,自提本部人马,先入汉中,放火烧断栈道,劫丞相灵车,谋为不轨。变起仓卒,谨飞章奏闻。”太后听毕,问:“卿等所见若何?”蒋琬奏曰:“以臣愚见:杨仪为人虽禀性过急,不能容物,至于筹度粮草,参赞军机,与丞相办事多时,今丞相临终,委以大事,决非背反之人。魏延平日恃功务高,人皆下之;仪独不假借,延心怀恨;今见仪总兵,心中不服,故烧栈道,断其归路,又诬奏而图陷害。臣愿将全家良贱,保杨仪不反。实不敢保魏延。”董允亦奏曰:“魏延自恃功高,常有不平之心,口出怨言。向所以不即反者,惧丞相耳。今丞相新亡,乘机为乱,势所必然。若杨仪,才干敏达,为丞相所任用,必不背反。”后主曰:“若魏延果反,当用何策御之?”蒋琬曰:“丞相素疑此人,必有遗计授与杨仪。若仪无恃,安能退入谷口乎?延必中计矣。陛下宽心。”不多时,魏延又表至,告称杨仪背反。正览表之间,杨仪又表到,奏称魏延背反。二人接连具表,各陈是非。忽报费祎到。后主召入,祎细奏魏延反情。后主曰:“若如此,且令董允假节释劝,用好言抚慰。”允奉诏而去。 @@ -1944,7 +1944,7 @@ 忽一日,幽州刺史毋丘俭上表,报称辽东公孙渊造反,自号为燕王,改元绍汉元年,建宫殿,立官职,兴兵入寇,摇动北方。睿大惊,即聚文武官僚,商议起兵退渊之策。正是:才将土木劳中国,又见干戈起外方。 未知何以御之,且看下文分解。 (本章完) -第106章 公孙渊兵败死襄平 司马懿诈病赚曹爽 +第106章 公孙渊兵败死襄平 司马懿诈病赚曹爽   却说公孙渊乃辽东公孙度之孙,公孙康之子也。建安十二年,曹操追袁尚,未到辽东,康斩尚首级献操,操封康为襄平侯;后康死,有二子:长曰晃,次曰渊,皆幼;康弟公孙恭继职。曹丕时封恭为车骑将军、襄平侯。太和二年,渊长大,文武兼备,性刚好斗,夺其叔公孙恭之位,曹睿封渊为扬烈将军、辽东太守。后孙权遣张弥、许晏赍金珠珍玉赴辽东,封渊为燕王。渊惧中原,乃斩张、许二人,送首与曹睿。睿封渊为大司马、乐浪公。渊心不足,与众商议,自号为燕王,改元绍汉元年。副将贾范谏曰:“中原待主公以上公之爵,不为卑贱;今若背反,实为不顺。 更兼司马懿善能用兵,西蜀诸葛武侯且不能取胜,何况主公乎?”渊大怒,叱左右缚贾范,将斩之。参军伦直谏曰:“贾范之言是也。圣人云:国家将亡,必有妖孽。今国中屡见怪异之事:近有犬戴巾帻,身披红衣,上屋作人行;又城南乡民造饭,饭甑之中,忽有一小儿蒸死于内;襄平北市中,地忽陷一穴,涌出一块肉,周围数尺,头面眼耳口鼻都具,独无手足,刀箭不能伤,不知何物。卜者占之曰:有形不成,有口无声;国家亡灭,故现其形。有此三者,皆不祥之兆也。主公宜避凶就吉,不可轻举妄动。”渊勃然大怒,叱武士绑伦直并贾范同斩于市。令大将军卑衍为元帅,杨祚为先锋,起辽兵十五万,杀奔中原来。 边官报知魏主曹睿。睿大惊,乃召司马懿入朝计议。懿奏曰:“臣部下马步官军四万,足可破贼。”睿曰:“卿兵少路远,恐难收复。”懿曰:“兵不在多,在能设奇用智耳。臣托陛下洪福,必擒公孙渊以献陛下。”睿曰:“卿料公孙渊作何举动?”懿曰:“渊若弃城预走,是上计也;守辽东拒大军,是中计也;坐守襄平,是为下计,必被臣所擒矣。”睿曰:“此去往复几时?”懿曰:“四千里之地,往百日,攻百日,还百日,休息六十日,大约一年足矣。”睿曰:“倘吴、蜀入寇,如之奈何?”懿曰:“臣已定下守御之策,陛下勿忧。”睿大喜,即命司马懿兴师征讨公孙渊。 @@ -1965,7 +1965,7 @@ 胜写毕,呈上,懿看之,笑曰:“吾病的耳聋了。此去保重。”言讫,以手指口。侍婢进汤,懿将口就之,汤流满襟,乃作哽噎之声曰:“吾今衰老病笃,死在旦夕矣。二子不肖,望君教之。君若见大将军,千万看觑二子!”言讫,倒在床上,声嘶气喘。李胜拜辞仲达,回见曹爽,细言其事。爽大喜曰:“此老若死,吾无忧矣!”司马懿见李胜去了,遂起身谓二子曰:“李胜此去,回报消息,曹爽必不忌我矣。只待他出城畋猎之时,方可图之。”不一日,曹爽请魏主曹芳去谒高平陵,祭祀先帝。大小官僚,皆随驾出城。爽引三弟,并心腹人何晏等,及御林军护驾正行,司农桓范叩马谏曰:“主公总典禁兵,不宜兄弟皆出。倘城中有变,如之奈何?”爽以鞭指而叱之曰:“谁敢为变!再勿乱言!”当日,司马懿见爽出城,心中大喜,即起旧日手下破敌之人,并家将数十,引二子上马,径来谋杀曹爽。正是:闭户忽然有起色,驱兵自此逞雄风。 未知曹爽性命如何,且看下文分解。 (本章完) -第107章 魏主政归司马氏 姜维兵败牛头山 +第107章 魏主政归司马氏 姜维兵败牛头山   却说司马懿闻曹爽同弟曹羲、曹训、曹彦并心腹何晏,邓飏、丁谧、毕轨、李胜等及御林军,随魏主曹芳,出城谒明帝墓,就去畋猎。懿大喜,即到省中,令司徒高柔,假以节钺行大将军事,先据曹爽营;又令太仆王观行中领军事,据曹羲营。懿引旧官入后宫奏郭太后,言爽背先帝托孤之恩,奸邪乱国,其罪当废。郭太后大惊曰:“天子在外,如之奈何?”懿曰:“臣有奏天子之表,诛奸臣之计。太后勿忧。”太后惧怕,只得从之。懿急令太尉蒋济、尚书令司马孚,一同写表,遣黄门赍出城外,径至帝前申奏。懿自引大军据武库。早有人报知曹爽家。其妻刘氏急出厅前,唤守府官问曰:“今主公在外,仲达起兵何意?”守门将潘举曰:“夫人勿惊,我去问来。”乃引弓弩手数十人,登门楼望之。正见司马懿引兵过府前,举令人乱箭射下,懿不得过。偏将孙谦在后止之曰:“太傅为国家大事,休得放箭。”连止三次,举方不射。司马昭护父司马懿而过,引兵出城屯于洛河,守住浮桥。 且说曹爽手下司马鲁芝,见城中事变,来与参军辛敞商议曰:“今仲达如此变乱,将如之何?”敞曰:“可引本部兵出城去见天子。”芝然其言。敞急入后堂。其姊辛宪英见之,问曰:“汝有何事,慌速如此?”敞告曰:“天子在外,太傅闭了城门,必将谋逆。宪英曰:“司马公未必谋逆,特欲杀曹将军耳。”敞惊曰:“此事未知如何?”宪英曰:“曹将军非司马公之对手,必然败矣。”敞曰:“今鲁司马教我同去,未知可去否?”宪英曰:“职守,人之大义也。凡人在难,犹或恤之;执鞭而弃其事,不祥莫大焉。”敞从其言,乃与鲁芝引数十骑,斩关夺门而出。人报知司马懿。懿恐桓范亦走,急令人召之。范与其子商议。其子曰:“车驾在外,不如南出。”范从其言,乃上马至平昌门,城门已闭,把门将乃桓范旧吏司蕃也。范袖中取出一竹版曰:“太后有诏,可即开门。”司蕃曰:“请诏验之。”范叱曰:“汝是吾故吏,何敢如此!”蕃只得开门放出。 范出的城外,唤司蕃曰:“太傅造反,汝可速随我去。”蕃大惊,追之不及。人报知司马懿。懿大惊曰:“智囊泄矣!如之奈何?”蒋济曰:“驽马恋栈豆,必不能用也。”懿乃召许允、陈泰曰:“汝去见曹爽,说太傅别无他事,只是削汝兄弟兵权而已。”许、陈二人去了。又召殿中校尉尹大目至;令蒋济作书,与目持去见爽。懿分付曰:“汝与爽厚,可领此任。汝见爽,说吾与蒋济指洛水为誓,只因兵权之事,别无他意。”尹大目依令而去。却说曹爽正飞鹰走犬之际,忽报城内有变,太傅有表。爽大惊,几乎落马。黄门官捧表跪于天子之前。爽接表拆封,令近臣读之。表略曰:“征西大都督、太傅臣司马懿,诚惶诚恐,顿首谨表:臣昔从辽东还,先帝诏陛下与秦王及臣等,升御床,把臣臂,深以后事为念。 @@ -1983,7 +1983,7 @@ 却说姜维兵至牛头山,忽听的前军发喊,报说魏兵截住去路。维慌忙自到军前视之。陈泰大喝曰:“汝欲袭吾雍州!吾已等候多时了!”维大怒,挺枪纵马,直取陈泰。泰挥刀而迎。战不三合,泰败走,维挥兵掩杀。雍州兵退回,占住山头。维收兵就牛头山下寨。维每日令兵搦战,不分胜负。夏侯霸谓姜维曰:“此处不是久停之所。连日交战,不分胜负,乃诱兵之计耳,必有异谋。不如暂退,再作良图。”正言间,忽报郭淮引一军取洮水,断了粮道。维大惊,急令夏侯霸先退,维自断后。陈泰分兵五路赶来。维独拒五路总口,战住魏兵。泰勒兵上山,矢石如雨。维急退到洮水之时,郭淮引兵杀来。维引兵往来冲突。魏兵阻其去路,密如铁桶。维奋死杀出,折兵大半,飞奔上阳平关来。前面又一军杀到;为首一员大将,纵马横刀而出。那人生得圆面大耳,方口厚唇,左目下生个黑瘤,瘤上生数十根黑毛,乃司马懿长子骠骑将军司马师也。维大怒曰:“孺子焉敢阻吾归路!”拍马挺枪,直来刺师。师挥刀相迎。只三合,杀败了司马师,维脱身径奔阳平关来。城上人开门放入姜维。司马师也来抢关,两边伏弩齐发,一弩发十矢,乃武侯临终时所遗连弩之法也。正是:难支此日三军败,独赖当年十矢传。 未知司马师性命如何,且看下文分解。 (本章完) -第108章 丁奉雪中奋短兵 孙峻席间施密计 +第108章 丁奉雪中奋短兵 孙峻席间施密计   却说姜维正走,遇着司马师引兵拦截。原来姜维取雍州之时,郭淮飞报入朝,魏主与司马懿商议停当,懿遣长子司马师引兵五万,前来雍州助战;师听知郭淮敌退蜀兵,师料蜀兵势弱,就来半路击之。直赶到阳平关,却被姜维用武侯所传连弩法,于两边暗伏连弩百余张,一弩发十矢,皆是药箭,两边弩箭齐发,前军连人带马射死不知其数。司马师于乱军之中,逃命而回。却说麴山城中蜀将句安,见援兵不至,乃开门降魏。姜维折兵数万,领败兵回汉中屯扎。司马师自还洛阳。至嘉平三年秋八月,司马懿染病,渐渐沉重,乃唤二子至榻前嘱曰:“吾事魏历年,官授太傅,人臣之位极矣;人皆疑吾有异志,吾尝怀恐惧。吾死之后,汝二人善理国政。慎之!慎之!”言讫而亡。 长子司马师,次子司马昭,二人申奏魏主曹芳。芳厚加祭葬,优锡赠谥;封师为大将军,总领尚书机密大事,昭为骠骑上将军。却说吴主孙权,先有太子孙登,乃徐夫人所生,于吴赤乌四年身亡,遂立次子孙和为太子,乃琅琊王夫人所生。和因与全公主不睦,被公主所谮,权废之,和忧恨而死,又立三子孙亮为太子,乃潘夫人所生。此时陆逊、诸葛瑾皆亡,一应大小事务,皆归于诸葛恪。太元元年秋八月初一日,忽起大风,江海涌涛,平地水深八尺。吴主先陵所种松柏,尽皆拔起,直飞到建业城南门外,倒卓于道上。权因此受惊成病。至次年四月内,病势沉重,乃召太傅诸葛恪、大司马吕岱至榻前,嘱以后事。嘱讫而薨。在位二十四年,寿七十一岁,乃蜀汉延熙十五年也。后人有诗曰:“紫髯碧眼号英雄,能使臣僚肯尽忠。二十四年兴大业,龙盘虎踞在江东。” 孙权既亡,诸葛恪立孙亮为帝,大赦天下,改元建兴元年;谥权曰大皇帝,葬于蒋陵。早有细作探知其事,报入洛阳。司马师闻孙权已死,遂议起兵伐吴。尚书傅嘏曰:“吴有长江之险,先帝屡次征伐,皆不遂意;不如各守边疆,乃为上策。”师曰:“天道三十年一变,岂得常为鼎峙乎?吾欲伐吴。”昭曰:“今孙权新亡,孙亮幼懦,其隙正可乘也。”遂令征南大将军王昶引兵十万攻南郡,征东将军胡遵引兵十万攻东兴,镇南都督毋丘俭引兵十万攻武昌:三路进发。又遣弟司马昭为大都督,总领三路军马。 @@ -2001,7 +2001,7 @@ 且说姜维在成都,接得诸葛恪书,欲求相助伐魏,遂入朝,奏准后主,复起大兵,北伐中原。正是:一度兴师未奏绩,两番讨贼欲成功。 未知胜负如何,且看下文分解。 (本章完) -第109章 困司马汉将奇谋 废曹芳魏家果报 +第109章 困司马汉将奇谋 废曹芳魏家果报   蜀汉延熙十六年秋,将军姜维起兵二十万,令廖化、张翼为左右先锋,夏侯霸为参谋,张嶷为运粮使,大兵出阳平关伐魏。维与夏侯霸商议曰:“向取雍州,不克而还;今若再出,必又有准备。公有何高见?”霸曰:“陇上诸郡,只有南安钱粮最广;若先取之,足可为本。向者不克而还,盖因羌兵不至。今可先遣人会羌人于陇右,然后进兵出石营,从董亭直取南安。”维大喜曰:“公言甚妙!”遂遣郤正为使,赍金珠蜀锦入羌,结好羌王。羌王迷当,得了礼物,便起兵五万,令羌将俄何烧戈为大先锋,引兵南安来。 魏左将军郭淮闻报,飞奏洛阳。司马师问诸将曰:“谁敢去敌蜀兵?”辅国将军徐质曰:“某愿往。”师素知徐质英勇过人,心中大喜,即令徐质为先锋,令司马昭为大都督,领兵望陇西进发。军至董亭,正遇姜维,两军列成阵势。徐质使开出大斧,出马挑战。蜀阵中廖化出迎。战不数合,化拖刀败回。张翼纵马挺枪而迎,战不数合,又败入阵。徐质驱兵掩杀,蜀兵大败,退三十余里。司马昭亦收兵回,各自下寨。 姜维与夏侯霸商议曰:“徐质勇甚,当以何策擒之?”霸曰:“来日诈败,以埋伏之计胜之。”维曰:“司马昭乃仲达之子,岂不知兵法?若见地势掩映,必不肯追。吾见魏兵累次断吾粮道,今却用此计诱之,可斩徐质矣。”遂唤廖化分付如此如此,又唤张翼分付如此如此:二人领兵去了。一面令军士于路撒下铁蒺藜,寨外多排鹿角,示以久计。 @@ -2019,7 +2019,7 @@ 正元二年春正月,有细作飞报,说镇东将军毋丘俭、扬州刺史文钦,以废主为名,起兵前来。司马师大惊。正是:汉臣曾有勤王志,魏将还兴讨贼师。 未知如何迎敌,且看下文分解。 (本章完) -第110章 文鸯单骑退雄兵 姜维背水破大敌 +第110章 文鸯单骑退雄兵 姜维背水破大敌   却说魏正元二年正月,扬州都督、镇东将军、领淮南军马毋丘俭,字仲恭,河东闻喜人也。闻司马师擅行废立之事,心中大怒。长子毋丘甸曰:“父亲官居方面,司马师专权废主,国家有累卵之危,安可宴然自守?”俭曰:“吾儿之言是也。”遂请刺史文钦商议。钦乃曹爽门下客,当日闻俭相请,即来参谒。俭邀入后堂,礼毕,说话间,俭流泪不止。钦问其故,俭曰:“司马师专权废主,天地反覆,安得不伤心乎!”钦曰:“都督镇守方面,若肯仗义讨贼,钦愿舍死相助。钦中子文淑,小字阿鸯,有万夫不当之勇,常欲杀司马师兄弟,与曹爽报仇,今可令为先锋。”俭大喜,即时酹酒为誓。二人诈称太后有密诏,令淮南大小官兵将士,皆入寿春城,立一坛于西,宰白马歃血为盟,宣言司马师大逆不道,今奉太后密诏,令尽起淮南军马,仗义讨贼。众皆悦服。俭提六万兵,屯于项城。文钦领兵二万在外为游兵,往来接应。俭移檄诸郡,令各起兵相助。却说司马师左眼肉瘤,不时痛痒,乃命医官割之,以药封闭,连日在府养病;忽闻淮南告急,乃请太尉王肃商议。 肃曰:“昔关云长威震华夏,孙权令吕蒙袭取荆州,抚恤将士家属,因此关公军势瓦解,今淮南将士家属,皆在中原,可急抚恤,更以兵断其归路:必有土崩之势矣。”师曰:“公言极善。但吾新割目瘤,不能自往。若使他人,心又不稳。”时中书侍郎钟会在侧,进言曰:“淮楚兵强,其锋甚锐;若遣人领兵去退,多是不利。倘有疏虞,则大事废矣。”师蹶然起曰:“非吾自在,不可破贼!”遂留弟司马昭守洛阳,总摄朝政。师乘软舆,带病东行。令镇东将军诸葛诞,总督豫州诸军,从安风津取寿春;又令征东将军胡遵,领青州诸军,出谯、宋之地,绝其归路;又遣荆州刺史、监军王基,领前部兵,先取镇南之地。师领大军屯于襄阳,聚文武于帐下商议。光禄勋郑袤曰:“毋丘俭好谋而无断,文钦有勇而无智。今大军出其不意,江、淮之卒锐气正盛,不可轻敌;只宜深沟高垒,以挫其锐。此亚夫之长策也。”监军王基曰:“不可。淮南之反,非军民思乱也;皆因毋丘俭势力所逼,不得已而从之。若大军一临,必然瓦解。”师曰:“此言甚妙。”遂进兵于濦水之上,中军屯于濦桥。基曰:“南顿极好屯兵,可提兵星夜取之。若迟则毋丘俭必先至矣。”师遂令王基领前部兵来南顿城下寨。 却说毋丘俭在项城,闻知司马师自来,乃聚众商议。先锋葛雍曰:“南顿之地,依山傍水,极好屯兵;若魏兵先占,难以驱遣,可速取之。”俭然其言,起兵投南顿来。正行之间,前面流星马报说,南顿已有人马下寨。俭不信,自到军前视之,果然旌旗遍野,营寨齐整。俭回到军中,无计可施。忽哨马飞报:“东吴孙峻提兵渡江袭寿春来了。”俭大惊曰:“寿春若失,吾归何处!”是夜退兵于项城。 @@ -2035,7 +2035,7 @@ 且说后主因姜维有洮西之功,降诏封维为大将军。维受了职,上表谢恩毕,再议出师伐魏之策。正是:成功不必添蛇足,讨贼犹思奋虎威。 不知此番北伐如何,且看下文分解。 (本章完) -第111章 邓士载智败姜伯约 诸葛诞义讨司马昭 +第111章 邓士载智败姜伯约 诸葛诞义讨司马昭   却说姜维退兵屯于钟提,魏兵屯于狄道城外。王经迎接陈泰、邓艾入城,拜谢解围之事,设宴相待,大赏三军。泰将邓艾之功,申奏魏主曹髦,髦封艾为安西将军,假节,领护东羌校尉,同陈泰屯兵于雍、凉等处。邓艾上表谢恩毕,陈泰设席与邓艾作贺曰:“姜维夜遁,其力已竭,不敢再出矣。”艾笑曰:“吾料蜀兵必出有五。”泰问其故,艾曰:“蜀兵虽退,终有乘胜之势;吾兵终有弱败之实:其必出一也。蜀兵皆是孔明教演,精锐之兵,容易调遣;吾将不时更换,军又训练不熟:其必出二也。蜀人多以船行,吾军皆在旱地,劳逸不同;其必出三也。狄道、陇西、南安、祁山四处皆是守战之地;蜀人或声东击西,指南攻北,吾兵必须分头守把;蜀兵合为一处而来,以一分当我四分:其必出四也。若蜀兵自南安、陇西,则可取羌人之谷为食;若出祁山,则有麦可就食:其必出五也。”陈泰叹服曰;“公料敌如神,蜀兵何足虑哉!”于是陈泰与邓艾结为忘年之交。艾遂将雍、凉等处之兵,每日操练;各处隘口,皆立营寨,以防不测。 却说姜维在钟提大设筵宴,会集诸将,商议伐魏之事。令史樊建谏曰:“将军屡出,未获全功;今日洮西之捷,魏人已服威名,何故又欲出也?万一不利,前功尽弃。”维曰:“汝等只知魏国地宽人广,急不可得;却不知攻魏者有五可胜。”众问之,维答曰:“彼洮西一败,挫尽锐气,吾兵虽退,不曾损折:今若进兵,一可胜也。吾兵船载而进,不致劳困,彼兵皆从旱地来迎:二可胜也。吾兵久经训练之众,彼皆乌合之徒,不曾有法度:三可胜也。吾兵自出祁山,掠抄秋谷为食:四可胜也。彼兵须各守备,军力分开,吾兵一处而去,彼安能救:五可胜也。不在此时伐魏,更待何日耶?”夏侯霸曰:“艾年虽幼,而机谋深远;近封为安西将军之职,必于各处准备,非同往日矣。”维厉声曰:“吾何畏彼哉!公等休长他人锐气,灭自己威风!吾意已决,必先取陇西。”众不敢谏。维自领前部,令众将随后而进,于是蜀兵尽离钟提,杀奔祁山来。哨马报说魏兵已先在祁山立下九个寨栅。维不信,引数骑凭高望之,果见祁山九寨势如长蛇,首尾相顾。维回顾左右曰:“夏侯霸之言,信不诬矣。此寨形势绝妙。止吾师诸葛丞相能之;今观邓艾所为,不在吾师之下。”遂回本寨。唤诸将曰:“魏人既有准备,必知吾来矣。吾料邓艾必在此间。汝等可虚张吾旗号,据此谷口下寨;每日令百余骑出哨,每出哨一回,换一番衣甲、旗号、按青、黄、赤、白、黑五方旗帜相换。吾却提大兵偷出董亭,径袭南安去也。”遂令鲍素屯兵于祁山谷口。维尽率大兵,望南安进发。 却说邓艾知蜀兵出祁山,早与陈泰下寨准备;见蜀兵连日不来搦战,一日五番哨马出寨,或十里或十五里而回。艾凭高望毕。慌入帐与陈泰曰:“姜维不在此间,必取董亭袭南安去了。出寨哨马只是这几匹。更换衣甲,往来哨探,其马皆困乏,主将必无能者。陈将军可引一军攻之,其寨可破也。破了寨栅,便引兵袭董亭之路,先断姜维之后。吾当先引一军救南安,径取武城山。若先占此山头,姜维必取上邽。上邽有一谷,名曰段谷,地狭山险,正好埋伏。彼来争武城山时,吾先伏两军于段谷,破维必矣。”泰曰:“吾守陇西二三十年,未尝如此明察地理。公之所言,真神算也!公可速去,吾自攻此处寨栅。”于是邓艾引军星夜倍道而行,径到武城山;下寨已毕,蜀兵未到。即令子邓忠,与帐前校尉师篡,各引五千兵,先去段谷埋伏,如此如此而行。二人受计而去。艾令偃旗息鼓,以待蜀兵。 @@ -2049,7 +2049,7 @@ 东吴先锋朱异,引兵迎敌。两军对圆,魏军中王基出马,朱异来迎。战不三合,朱异败走:唐咨出马,战不三合,亦大败而走。王基驱兵掩杀,吴兵大败,退五十里下寨,报入寿春城中。诸葛诞自引本部锐兵,会合文钦并二子文鸯、文虎,雄兵数万,来敌司马昭。正是:方见吴兵锐气堕。又看魏将劲兵来。 未知胜负如何,且看下文分解。 (本章完) -第112章 救寿春于诠死节 取长城伯约鏖兵 +第112章 救寿春于诠死节 取长城伯约鏖兵   却说司马昭闻诸葛诞会合吴兵前来决战,乃召散骑长史裴秀、黄门侍郎钟会,商议破敌之策。钟会曰:“吴兵之助诸葛诞,实为利也;以利诱之,则必胜矣。”昭从其言,遂令石苞、州泰先引两军于石头城埋伏,王基、陈骞领精兵在后,却令偏将成倅引兵数万先去诱敌;又令陈俊引车仗牛马驴骡,装载赏军之物,四面聚集于阵中,如敌来则弃之。 是日,诸葛诞令吴将朱异在左,文钦在右,见魏阵中人马不整,诞乃大驱士马径进。成倅退走,诞驱兴掩杀,见牛马驴骡,遍满郊野;南兵争取,无心恋战。忽然一声炮响,两路兵杀来:左有石苞,右有州泰,诞大惊,急欲退时,王基、陈骞精兵杀到。诞兵大败。司马昭又引兵接应。诞引败兵奔入寿春,闭门坚守。昭令兵四面围困,并力攻城。 时吴兵退屯安丰,魏主车驾驻于项城。钟会曰:“今诸葛诞虽败,寿春城中粮草尚多,更有吴兵屯安丰以为掎角之势;今吾兵四面攻围,彼缓则坚守,急则死战;吴兵或乘势夹攻:吾军无益。不如三面攻之,留南门大路,容贼自走;走而击之,可全胜也。吴兵远来,粮必不继;我引轻骑抄在其后,可不战而自破矣。”昭抚会背曰:“君真吾之子房也!”遂令王基撤退南门之兵。却说吴兵屯于安丰,孙綝唤朱异责之曰:“量一寿春城不能救,安可并吞中原?如再不胜必斩!”朱异乃回本寨商议。于诠曰:“今寿春南门不围,某愿领一军从南门入去,助诸葛诞守城。 @@ -2066,7 +2066,7 @@ 却说姜维令人于艾寨中下战书,约来日大战,艾佯应之。次日五更,维令三军造饭,平明布阵等候。艾营中偃旗息鼓,却如无人之状。维至晚方回。次日又令人下战书,责以失期之罪。艾以酒食待使,答曰:“微躯小疾,有误相持,明日会战。”次日,维又引兵来,艾仍前不出。如此五六番。傅佥谓维曰:“此必有谋也,宜防之。”维曰:“此必捱关中兵到,三面击我耳。吾今令人持书与东吴孙綝,使并力攻之。”忽探马报说:“司马昭攻打寿春,杀了诸葛诞,吴兵皆降。昭班师回洛阳。便欲引兵来救长城。”维大惊曰:“今番伐魏,又成画饼矣,不如且回。”正是:已叹四番难奏绩,又嗟五度未成功。 未知如何退兵,且看下文分解。 (本章完) -第113章 丁奉定计斩孙綝 姜维斗阵破邓艾 +第113章 丁奉定计斩孙綝 姜维斗阵破邓艾   却说姜维恐救兵到,先将军器车仗,一应军需,步兵先退,然后将马军断后。细作报知邓艾。艾笑曰:“姜维知大将军兵到,故先退去。不必追之,追则中彼之计也。”乃令人哨探,回报果然骆谷道狭之处,堆积柴草,准备要烧追兵。众皆称艾曰:“将军真神算也!”遂遣使赍表奏闻。于是司马昭大喜,又加赏邓艾。却说东吴大将军孙綝,听知全端、唐咨等降魏,勃然大怒,将各人家眷,尽皆斩之。吴主孙亮,时年方十六,见綝杀戮太过,心甚不然。一日出西苑,因食生梅,令黄门取蜜。须臾取至,见蜜内有鼠粪数块,召藏吏责之。藏吏叩首曰:“臣封闭甚严,安有鼠粪?”亮曰:“黄门曾向尔求蜜食否?”藏吏曰:“黄门于数日前曾求蜜食,臣实不敢与。”亮指黄门曰:“此必汝怒藏吏不与尔蜜,故置粪于蜜中,以陷之也。”黄门不服。亮曰:“此事易知耳。若粪久在蜜中,则内外皆湿,若新在蜜中,则外湿内燥。”命剖视之,果然内燥,黄门服罪。亮之聪明,大抵如此。虽然聪明,却被孙綝把持,不能主张,綝令弟威远将军孙据入苍龙宿卫,武卫将军孙恩、偏将军孙干、长水校尉孙闿分屯诸营。 一日,吴主孙亮闷坐,黄门侍郎全纪在侧,纪乃国舅也。亮因泣告曰:“孙綝专权妄杀,欺朕太甚;今不图之,必为后患。”纪曰:“陛下但有用臣处,臣万死不辞。”亮曰:“卿可只今点起禁兵,与将军刘丞各把城门,朕自出杀孙綝。但此事切不可令卿母知之,卿母乃綝之姊也。倘若泄漏,误朕匪轻。”纪曰:“乞陛下草诏与臣。临行事之时,臣将诏示众,使綝手下人皆不敢妄动。”亮从之,即写密诏付纪。纪受诏归家,密告其父全尚。尚知此事,乃告妻曰:“三日内杀孙綝矣。”妻曰:“杀之是也。”口虽应之,却私令人持书报知孙綝。綝大怒,当夜便唤弟兄四人,点起精兵,先围大内;一面将全尚、刘丞并其家小俱拿下。 比及平明,吴主孙亮听得宫门外金鼓大震,内侍慌入奏曰:“孙綝引兵围了内苑。”亮大怒,指全后骂曰:“汝父兄误我大事矣!”乃拔剑欲出。全后与侍中近臣,皆牵其衣而哭,不放亮出。孙綝先将全尚、刘丞等杀讫,然后召文武于朝内,下令曰:“主上荒淫久病,昏乱无道,不可以奉宗庙,今当废之。汝诸文武,敢有不从者,以谋叛论!”众皆畏俱,应曰:“愿从将军之令。”尚书桓彝大怒,从班部中挺然而出,指孙綝大骂曰:“今上乃聪明之主,汝何取出此乱言!吾宁死不从贼臣之命!”綝大怒,自拔剑斩之,即入内指吴主孙亮骂曰:“无道昏君!本当诛戮以谢天下!看先帝之面,废汝为会稽王,吾自选有德者立之!”叱中书郎李崇夺其玺绶,令邓程收之。亮大哭而去。后人有诗叹曰:“乱贼诬伊尹,奸臣冒霍光。可怜聪明主,不得莅朝堂。” @@ -2082,7 +2082,7 @@ 却说邓艾催督先锋郑伦来袭山后。伦刚转过山角,忽然一声炮响,鼓角喧天,伏兵杀出:为首大将。乃廖化也。二人未及答话,两马交处,被廖化一刀,斩郑伦于马下。邓艾大惊,急勒兵退时,张翼引一军杀到。两下夹攻,魏兵大败。艾舍命突出,身被四箭。奔到谓南寨时,司马望亦到。二人商议退兵之策。望曰:“近日蜀主刘禅,宠幸中贵黄皓,日夜以酒色为乐。可用反间计召回姜维,此危可解。”艾问众谋士曰:“谁可入蜀交通黄皓?”言未毕,一人应声曰:“某愿往。”艾视之,乃襄阳党均也。艾大喜,即令党均赍金珠宝物,径到成都结连黄皓,布散流言,说姜维怨望天子,不久投魏。于是成都人人所说皆同。黄皓奏知后主,即遣人星夜宣姜维入朝。却说姜维连日搦战,邓艾坚守不出。维心中甚疑。忽使命至。诏维入朝。维不知何事,只得班师回朝。邓艾、司马望知姜维中计,遂拔渭南之兵,随后掩杀。正是:乐毅伐齐遭间阻,岳飞破敌被谗回。 未知胜负如何,且看下文分解。 (本章完) -第114章 曹髦驱车死南阙 姜维弃粮胜魏兵 +第114章 曹髦驱车死南阙 姜维弃粮胜魏兵   却说姜维传令退兵,廖化曰:“将在外,君命有所不受。今虽有诏,未可动也。”张翼曰:“蜀人为大将军连年动兵,皆有怨望;不如乘此得胜之时,收回人马,以安民心,再作良图。”维曰:“善。”遂令各军依法而退。命廖化、张翼断后,以防魏兵追袭。却说邓艾引兵追赶,只见前面蜀兵旗帜整齐,人马徐徐而退。艾叹曰:“姜维深得武侯之法也!”因此不敢追赶,勒军回祁山寨去了。且说姜维至成都,入见后主,问召回之故。后主曰:“朕为卿在边庭,久不还师,恐劳军士,故诏卿回朝,别无他意。”维曰:“臣已得祁山之寨,正欲收功,不期半途而废。此必中邓艾反间之计矣。”后主默然不语。姜维又奏曰:“臣誓讨贼,以报国恩。陛下休听小人之言,致生疑虑。”后主良久乃曰:“朕不疑卿;卿且回汉中,俟魏国有变,再伐之可也。”姜维叹息出朝,自投汉中去讫。 却说党均回到祁山寨中,报知此事。邓艾与司马望曰:“君臣不和,必有内变。”就令党均入洛阳,报知司马昭。昭大喜,便有图蜀之心,乃问中护军贾充曰:“吾今伐蜀,如何?”充曰:“未可伐也。天子方疑主公,若一旦轻出,内难必作矣。旧年黄龙两见于宁陵井中,群臣表贺,以为祥瑞;天子曰:‘非祥瑞也。龙者君象,乃上不在天,下不在田,屈于井中,是幽困之兆也。’遂作《潜龙诗》一首。诗中之意,明明道着主公。其诗曰:‘伤哉龙受困,不能跃深渊。上不飞天汉,下不见于田。蟠居于井底,鳅鳝舞其前。藏牙伏爪甲,嗟我亦同然!’”司马昭闻之大怒,谓贾充曰:“此人欲效曹芳也!若不早图,彼必害我。”充曰:“某愿为主公早晚图之。”时魏甘露五年夏四月,司马昭带剑上殿,髦起迎之。群臣皆奏曰:“大将军功德巍巍,合为晋公,加九锡。”髦低头不答。 昭厉声曰:“吾父子兄弟三人有大功于魏,今为晋公,得毋不宜耶?”髦乃应曰:“敢不如命?”昭曰:“《潜龙》之诗,视吾等如鳅鳝,是何礼也?”髦不能答。昭冷笑下殿,众官凛然。髦归后宫,召侍中王沈、尚书王经、散骑常侍王业三人,入内计议。髦泣曰:“司马昭将怀篡逆,人所共知!朕不能坐受废辱,卿等可助朕讨之!”王经奏曰:“不可。昔鲁昭公不忍季氏,败走失国;今重权已归司马氏久矣,内外公卿,不顾顺逆之理,阿附奸贼,非一人也。且陛下宿卫寡弱,无用命之人。陛下若不隐忍,祸莫大焉。且宜缓图,不可造次。”髦曰:“是可忍也,孰不可忍也!朕意已决,便死何惧!”言讫,即入告太后。王沈、王业谓王经曰:“事已急矣。我等不可自取灭族之祸,当往司马公府下出首,以免一死。”经大怒曰:“主忧臣辱,主辱臣死,敢怀二心乎?”王沈、王业见经不从,径自往报司马昭去了。少顷,魏主曹髦出内,令护卫焦伯,聚集殿中宿卫苍头官僮三百余人,鼓噪而出。髦仗剑升辇,叱左右径出南阙。王经伏于辇前,大哭而谏曰:“今陛下领数百人伐昭,是驱羊而入虎口耳,空死无益。臣非惜命,实见事不可行也!”髦曰:“吾军已行,卿无阻当。”遂望云龙门而来。 @@ -2096,7 +2096,7 @@ 瓘叱左右令放火,尽烧粮草车辆。一霎时,火光突起,烈火烧空。灌大叫曰:“事已急矣!汝等宜死战!”乃提兵望西杀出。背后姜维三路追赶。维只道王瓘舍命撞回魏国,不想反杀入汉中而去。瓘因兵少,只恐追兵赶上,遂将栈道并各关隘尽皆烧毁。姜维恐汉中有失,遂不追邓艾,提兵连夜抄小路来追杀王瓘。瓘被四面蜀兵攻击,投黑龙江而死。余兵尽被姜维坑之。维虽然胜了邓艾,却折了许多粮车,又毁了栈道,乃引兵还汉中。邓艾引部下败兵,逃回祁山寨内,上表请罪,自贬其职。司马昭见艾数有大功,不忍贬之,复加厚赐。艾将原赐财物,尽分给被害将士之家。昭恐蜀兵又出,遂添兵五万,与艾守御。姜维连夜修了栈道,又议出师。正是:连修栈道兵连出,不伐中原死不休。 未知胜负如何,且看下文分解。 (本章完) -第115章 诏班师后主信谗 托屯田姜维避祸 +第115章 诏班师后主信谗 托屯田姜维避祸   却说蜀汉景耀五年,冬十月,大将军姜维,差人连夜修了栈道,整顿军粮兵器,又于汉中水路调拨船只。俱已完备,上表奏后主曰:“臣累出战,虽未成大功,已挫动魏人心胆。今养兵日久,不战则懒,懒则致病。况今军思效死,将思用命。臣如不胜,当受死罪。”后主览表,犹豫未决。谯周出班奏曰:“臣夜观天文,见西蜀分野,将星暗而不明。今大将军又欲出师,此行甚是不利。陛下可降诏止之。”后主曰:“且看此行若何。果然有失,却当阻之。”谯周再三苦谏不从,乃归家叹息不已,遂推病不出。 却说姜维临兴兵,乃问廖化曰:“吾今出师,誓欲恢复中原,当先取何处?”化曰:“连年征伐,军民不宁;兼魏有邓艾,足智多谋,非等闲之辈:将军强欲行难为之事,此化所以未敢专也。”维勃然大怒曰:“昔丞相六出祁山,亦为国也。吾今八次伐魏,岂为一己之私哉?今当先取洮阳。如有逆吾者必斩!”遂留廖化守汉中,自同诸将提兵三十万,径取洮阳而来。早有川口人报入祁山寨中。时邓艾正与司马望谈兵,闻知此信,遂令人哨探。回报蜀兵尽从洮阳而出。司马望曰:“姜维多计,莫非虚取洮阳而实来取祁山乎?”邓艾曰:“今姜维实出洮阳也。”望曰:“公何以知之?”艾曰:“向者姜维累出吾有粮之地,今洮阳无粮,维必料吾只守祁山,不守洮阳,故径取洮阳;如得此城,屯粮积草,结连羌人,以图久计耳。”望曰:“若此,如之奈何?”艾曰:“可尽撤此处之兵,分为两路去救洮阳。离洮阳二十五里,有侯河小城,乃洮阳咽喉之地。公引一军伏于洮阳,偃旗息鼓,大开四门,如此如此而行;我却引一军伏侯河,必获大胜也。”筹画已定,各各依计而行。只留偏将师纂守祁山寨。 却说姜维令夏侯霸为前部,先引一军径取洮阳。霸提兵前进,将近洮阳,望见城上并无一杆旌旗,四门大开。霸心下疑惑,未敢入城,回顾诸将曰:“莫非诈乎?”诸将曰:“眼见得是空城,只有些小百姓,听知大将军兵到,尽弃城而走了。”霸未信,自纵马于城南视之,只见城后老小无数,皆望西北而逃。霸大喜曰:“果空城也。”遂当先杀入,余众随后而进。方到瓮城边,忽然一声炮响,城上鼓角齐鸣,旌旗遍竖,拽起吊桥。霸大惊曰:“误中计矣!”慌欲退时,城上矢石如雨。可怜夏侯霸同五百军,皆死于城下。后人有诗叹曰:“大胆姜维妙算长,谁知邓艾暗提防。可怜投汉夏侯霸,顷刻城边箭下亡。 @@ -2112,7 +2112,7 @@ 却说钟会受了镇西将军之印,起兵伐蜀。会恐机谋或泄,却以伐吴为名,令青、兖、豫、荆、扬等五处各造大船;又遣唐咨于登、莱等州傍海之处,拘集海船。司马昭不知其意,遂召钟会问之曰:“子从旱路收川,何用造船耶?”会曰:“蜀若闻我兵大进,必求救于东吴也。故先布声势,作伐吴之状,吴必不敢妄动。一年之内,蜀已破,船已成,而伐吴,岂不顺乎?”昭大喜,选日出师。时魏景元四年秋七月初三日,钟会出师。司马昭送之于城外十里方回。西曹掾邵悌密谓司马昭曰:“今主公遣钟会领十万兵伐蜀,愚料会志大心高,不可使独掌大权。”昭笑曰:“吾岂不知之?”悌曰:“主公既知,何不使人同领其职?”昭言无数语,使邵悌疑心顿释。正是:方当士马驱驰日,早识将军跋扈心。 未知其言若何,且看下文分解。 (本章完) -第116章 钟会分兵汉中道 武侯显圣定军山 +第116章 钟会分兵汉中道 武侯显圣定军山   却说司马昭谓西曹掾邵悌曰:“朝臣皆言蜀未可伐,是其心怯;若使强战,必败之道也。今钟会独建伐蜀之策,是其心不怯;心不怯,则破蜀必矣。蜀既破,则蜀人心胆已裂;败军之将,不可以言勇;亡国之大夫,不可以图存。会即有异志,蜀人安能助之乎?至若魏人得胜思归,必不从会而反,更不足虑耳。此言乃吾与汝知之,切不可泄漏。”邵悌拜服。 却说钟会下寨已毕,升帐大集诸将听令。时有监军卫瓘,护军胡烈,大将田续、庞会、田章、爰青、丘建、夏侯咸、王买、皇甫闿、句安等八十余员。会曰:“必须一大将为先锋,逢山开路,遇水叠桥。谁敢当之?”一人应声曰:“某愿往。”会视之,乃虎将许褚之子许仪也。众皆曰:“非此人不可为先锋。”会唤许仪曰:“汝乃虎体猿班之将。父子有名;今众将亦皆保汝。汝可挂先锋印,领五千马军、一千步军,径取汉中。兵分三路:汝领中路,出斜谷;左军出骆谷;右军出子午谷。此皆崎岖山险之地,当今军填平道路,修理桥梁,凿山破石,勿使阻碍。如违必按军法。”许仪受命,领兵而进。钟会随后提十万余众,星夜起程。 却说邓艾在陇西,既受伐蜀之诏,一面令司马望往遏羌人,又遣雍州刺史诸葛绪,天水太守王颀,陇西太守牵弘,金城太守杨欣,各调本部兵前来听令。比及军马云集,邓艾夜作一梦:梦见登高山,望汉中,忽于脚下迸出一泉,水势上涌。须臾惊觉,浑身汗流;遂坐而待旦,乃召护卫爰邵问之。邵素明《周易》,艾备言其梦,邵答曰:“《易》云:山上有水曰蹇。蹇卦者:‘利西南,不利东北。’孔子云:‘蹇利西南,往有功也;不利东北,其道穷也。’将军此行,必然克蜀;但可惜蹇滞不能还。”艾闻言,愀然不乐。忽钟会檄文至,约艾起兵,于汉中取齐。艾遂遣雍州刺史诸葛绪,引兵一万五千,先断姜维归路;次遣天水太守王颀,引兵一万五千,从左攻沓中;陇西太守牵弘,引一万五千人,从右攻沓中;又遣金城太守杨欣,引一万五千人,于甘松邀姜维之后。艾自引兵三万,往来接应。却说钟会出师之时,有百官送出城外,旌旗蔽日,铠甲凝霜,人强马壮,威风凛然。人皆称羡,惟有相国参军刘寔,微笑不语。太尉王祥见寔冷笑,就马上握其手而问曰:“钟、邓二人,此去可平蜀乎?”寔曰:“破蜀必矣。但恐皆不得还都耳。”王祥问其故,刘寔但笑而不答。祥遂不复问。 @@ -2127,7 +2127,7 @@ 姜维入北道,约行三十里,料知魏兵起行,乃勒回兵,后队作前队,径到桥头,果然魏兵大队已去,只有些小兵把桥,被维一阵杀散,尽烧其寨栅。诸葛绪听知桥头火起,复引兵回,姜维兵已过半日了,因此不敢追赶。却说姜维引兵过了桥头,正行之间,前面一军来到,乃左将军张翼、右将军廖化也。维问之,翼曰:“黄皓听信师巫之言,不肯发兵。翼闻汉中已危,自起兵来,时阳安关已被钟会所取。今闻将军受困,特来接应。”遂合兵一处,前赴白水关。化曰:“今四面受敌,粮道不通,不如退守剑阁,再作良图。”维疑虑未决。忽报钟会、邓艾分兵十余路杀来。维欲与翼、化分兵迎之。化曰:“白水地狭路多,非争战之所,不如且退去救剑阁可也;若剑阁一失,是绝路矣。”维从之,遂引兵来投剑阁。将近关前,忽然鼓角齐鸣,喊声大起,旌旗遍竖,一枝军把住关口。正是:汉中险峻已无有,剑阁风波又忽生。 未知何处之兵,且看下文分解。 (本章完) -第117章 邓士载偷度阴平 诸葛瞻战死绵竹 +第117章 邓士载偷度阴平 诸葛瞻战死绵竹   却说辅国大将军董厥,闻魏兵十余路入境,乃引二万兵守住剑阁;当日望尘头大起,疑是魏兵,急引军把住关口。董厥自临军前视之,乃姜维、廖化、张翼也。厥大喜,接入关上,礼毕,哭诉后主黄皓之事。维曰:“公勿忧虑。若有维在,必不容魏来吞蜀也。且守剑阁,徐图退敌之计。”厥曰:“此关虽然可守,争奈成都无人;倘为敌人所袭,大势瓦解矣。”维曰:“成都山险地峻,非可易取,不必忧也。”正言间,忽报诸葛绪领兵杀至关下,维大怒,急引五千兵杀下关来,直撞入魏阵中,左冲右突,杀得诸葛绪大败而走,退数十里下寨,魏军死者无数。蜀兵抢了许多马匹器械,维收兵回关。 却说钟会离剑阁二十里下寨,诸葛绪自来伏罪。会怒曰:“吾令汝守把阴平桥头,以断姜维归路,如何失了!今又不得吾令,擅自进兵,以致此败!”绪曰:“维诡计多端,诈取雍州;绪恐雍州有失,引兵去救,维乘机走脱;绪因赶至关下,不想又为所败。”会大怒,叱令斩之。监军卫瓘曰:“绪虽有罪,乃邓征西所督之人;不争将军杀之,恐伤和气。”会曰:“吾奉天子明诏、晋公钧命,特来伐蜀。便是邓艾有罪,亦当斩之!”众皆力劝。会乃将诸葛绪用槛车载赴洛阳,任晋公发落;随将绪所领之兵,收在部下调遣。 有人报与邓艾。艾大怒曰:“吾与汝官品一般,吾久镇边疆,于国多劳,汝安敢妄自尊大耶!”子邓忠劝曰:“小不忍则乱大谋,父亲若与他不睦,必误国家大事。望且容忍之。”艾从其言。然毕竟心中怀怒,乃引十数骑来见钟会。会闻艾至,便问左右:“艾引多少军来?”左右答曰:“只有十数骑。”会乃令帐上帐下列武士数百人。 @@ -2145,7 +2145,7 @@ 却说诸葛瞻见救兵不至,谓众将曰:“久守非良图。”遂留子尚与尚书张遵守城,瞻自披挂上马,引三军大开三门杀出。邓艾见兵出,便撤兵退。瞻奋力追杀,忽然一声炮响,四面兵合,把瞻困在垓心。瞻引兵左冲右突,杀死数百人。艾令众军放箭射之,蜀兵四散。瞻中箭落马,乃大呼曰:“吾力竭矣,当以一死报国!”遂拔剑自刎而死。其子诸葛尚在城上,见父死于军中,勃然大怒,遂披挂上马。张遵谏曰:“小将军勿得轻出。”尚叹曰:“吾父子祖孙,荷国厚恩,今父既死于敌,我何用生为!”遂策马杀出,死于阵中。后人有诗赞瞻、尚父子曰:“不是忠臣独少谋,苍天有意绝炎刘。当年诸葛留嘉胤,节义真堪继武侯。”邓艾怜其忠,将父子合葬。乘虚攻打绵竹。张遵、黄崇、李球三人,各引一军杀出。蜀兵寡,魏兵众,三人亦皆战死。艾因此得了绵竹。劳军已毕,遂来取成都。正是:试观后主临危日,无异刘璋受逼时。 未知成都如何守御,且看下文分解。 (本章完) -第118章 哭祖庙一王死孝 入西川二士争功 +第118章 哭祖庙一王死孝 入西川二士争功   却说后主在成都,闻邓艾取了绵竹,诸葛瞻父子已亡,大惊,急召文武商议。近臣奏曰:“城外百姓,扶老携幼,哭声大震,各逃生命。”后主惊惶无措。忽哨马报到,说魏兵将近城下。多官议曰:“兵微将寡,难以迎敌;不如早弃成都,奔南中七郡。其地险峻,可以自守,就借蛮兵,再来克复未迟。”光禄大夫谯周曰:“不可。南蛮久反之人,平昔无惠;今若投之,必遭大祸。”多官又奏曰:“蜀、吴既同盟,今事急矣,可以投之。”周又谏曰:“自古以来,无寄他国为天子者。臣料魏能吞吴,吴不能吞魏。若称臣于吴,是一辱也;若吴被魏所吞,陛下再称臣于魏,是两番之辱矣。不如不投吴而降魏。魏必裂土以封陛下,则上能自守宗庙,下可以保安黎民。愿陛下思之。”后主未决,退入宫中。次日,众议纷然。谯周见事急,复上疏诤之。后主从谯周之言,正欲出降;忽屏风后转出一人,厉声而骂周曰:“偷生腐儒,岂可妄议社稷大事!自古安有降天子哉!”后主视之,乃第五子北地王刘谌也。后主生七子:长子刘璿,次子刘瑶,三子刘琮,四子刘瓒,五子即北地王刘谌,六子刘恂,七子刘璩。七子中惟谌自幼聪明,英敏过人,余皆儒善。 后主谓谌曰:“今大臣皆议当降,汝独仗血气之勇,欲令满城流血耶?”谌曰:“昔先帝在日,谯周未尝于预国政;今妄议大事,辄起乱言,甚非理也。臣切料成都之兵,尚有数万;姜维全师,皆在剑阁,若知魏兵犯阙,必来救应:内外攻击,可获大功。岂可听腐儒之言,轻废先帝之基业乎?”后主叱之曰:“汝小儿岂识天时!”谌叩头哭曰:“若势穷力极,祸败将及,便当父子君臣背城一战,同死社稷,以见先帝可也。奈何降乎!”后主不听。谌放声大哭曰:“先帝非容易创立基业,今一旦弃之,吾宁死不辱也!”后主令近臣推出宫门,遂令谯周作降书,遣私署侍中张绍、驸马都尉邓良同谯周赍玉玺来雒城请降。时邓艾每日令数百铁骑来成都哨探。当日见立了降旗,艾大喜。不一时,张绍等至,艾令人迎入。三人拜伏于阶下,呈上降款玉玺。艾拆降书视之,大喜,受下玉玺,重待张绍、谯周、邓良等。艾作回书,付三人赍回成都,以安人心。三人拜辞邓艾,径还成都,入见后主,呈上回书,细言邓艾相待之善。 后主拆封视之,大喜,即遣太仆蒋显赍敕令姜维早降;遣尚书郎李虎,送文簿与艾:共户二十八万,男女九十四万,带甲将士十万二千,官吏四万,仓粮四十余万,金银各二千斤,锦绮彩绢各二十万匹。余物在库,不及具数。择十二月初一日,君臣出降。北地王刘谌闻知,怒气冲天,乃带剑入宫。其妻崔夫人问曰:“大王今日颜色异常,何也?”谌曰:“魏兵将近,父皇已纳降款,明日君巨出降,社稷从此殄灭。吾欲先死以见先帝于地下,不屈膝于他人也!”崔夫人曰:“贤哉!贤哉!得其死矣!妾请先死,王死未迟。”谌曰:“汝何死耶?”崔夫人曰:“王死父,妾死夫:其义同也。夫亡妻死,何必问焉!”言讫,触柱而死。 @@ -2158,7 +2158,7 @@ 司马昭见了邓艾表章,大怒,即遣人到钟会军前,令会收艾;又遣贾充引三万兵入斜谷,昭乃同魏主曹奂御驾亲征。西曹掾邵悌谏曰:“钟会之兵,多艾六倍,当今会收艾足矣,何必明公自行耶?”昭笑曰:“汝忘了旧日之言耶?汝曾道会后必反。吾今此行,非为艾,实为会耳。”悌笑曰“某恐明公忘之,故以相问。今既有此意,切宜秘之,不可泄漏。”昭然其言,遂提大兵起程。时贾充亦疑钟会有变,密告司马昭。昭曰:“如遣汝,亦疑汝耶?吾到长安,自有明白。”早有细作报知钟会,说昭已至长安。会慌请姜维商议收艾之策。正是:才看西蜀收降将,又见长安动大兵。 不知姜维以何策破艾,且看下文分解。 (本章完) -第119章 假投降巧计成虚话 再受禅依样画葫芦 +第119章 假投降巧计成虚话 再受禅依样画葫芦   却说钟会请姜维计议收邓艾之策。维曰:“可先令监军卫瓘收艾。艾若杀瓘,反情实矣。将军却起兵讨之,可也。”会大喜,遂令卫瓘引数十人入成都,收邓艾父子。瓘手下人止之曰:“此是钟司徒令邓征西杀将军,以正反情也。切不可行。”瓘曰:“吾自有计。”遂先发檄文二三十道。其檄曰:“奉诏收艾,其余各无所问。若早来归,爵赏如先,敢有不出者,灭三族。”随备槛车两乘,星夜望成都而来。 比及鸡鸣,艾部将见檄文者,皆来投拜于卫瓘马前。时邓艾在府中未起。瓘引数十人突入大呼曰:“奉诏收邓艾父子!”艾大惊,滚下床来。瓘叱武士缚于车上。其子邓忠出问,亦被捉下,缚于车上。府中将吏大惊,欲待动手抢夺,早望见尘头大起,哨马报说钟司徒大兵到了。众各四散奔走。钟会与姜维下马入府,见邓艾父子已被缚,会以鞭挞邓艾之首而骂曰:“养犊小儿,何敢如此!”姜维亦骂曰:“匹夫行险徼幸,亦有今日耶!”艾亦大骂。会将艾父子送赴洛阳。会入成都,尽得邓艾军马,威声大震。乃谓姜维曰:“吾今日方趁平生之愿矣!”维曰:“昔韩信不听蒯通之说,而有未央宫之祸;大夫种不从范蠡于五湖,卒伏剑而死:斯二子者,其功名岂不赫然哉,徒以利害未明,而见机之不早也。今公大勋已就,威震其主,何不泛舟绝迹,登峨嵋之岭,而从赤松子游乎?”会笑曰:“君言差矣。吾年未四旬,方思进取,岂能便效此退闲之事?”维曰:“若不退闲,当早图良策。此则明公智力所能,无烦老夫之言矣。”会抚掌大笑曰:“伯约知吾心也。”二人自此每日商议大事。维密与后主书曰:“望陛下忍数日之辱,维将使社稷危而复安,日月幽而复明。必不使汉室终灭也。” 却说钟会正与姜维谋反,忽报司马昭有书到。会接书。书中言:“吾恐司徒收艾不下,自屯兵于长安;相见在近,以此先报。”会大惊曰:“吾兵多艾数倍,若但要我擒艾,晋公知吾独能办之。今日自引兵来,是疑我也!”遂与姜维计议。维曰:“君疑臣则臣必死,岂不见邓艾乎?”会曰:“吾意决矣!事成则得天下,不成则退西蜀,亦不失作刘备也。”维曰:“近闻郭太后新亡,可诈称太后有遗诏,教讨司马昭,以正弑君之罪。据明公之才,中原可席卷而定。”会曰:“伯约当作先锋。成事之后,同享富贵。”维曰:“愿效犬马微劳,但恐诸将不服耳。”会曰:“来日元宵佳节,于故宫大张灯火,请诸将饮宴。如不从者尽杀之。”维暗喜。次日,会、维二人请诸将饮宴。数巡后,会执杯大哭。诸将惊问其故,会曰:“郭太后临崩有遗诏在此,为司马昭南阙弑君,大逆无道,早晚将篡魏,命吾讨之。汝等各自佥名,共成此事。”众皆大惊,面面相觑。会拔剑出鞘曰:“违令者斩!”众皆恐惧,只得相从。画字已毕,会乃困诸将于宫中,严兵禁守。维曰:“我见诸将不服,请坑之。”会曰:“吾已令宫中掘一坑,置大棒数千;如不从者,打死坑之。” @@ -2176,7 +2176,7 @@ 晋帝司马炎,追谥司马懿为宣帝,伯父司马师为景帝,父司马昭为文帝,立七庙以光祖宗。那七庙?汉征西将军司马钧,钧生豫章太守司马量,量生颍川太守司马隽,隽生京兆尹司马防,防生宣帝司马懿,懿生景帝司马师、文帝司马昭:是为七庙也。大事已定,每日设朝计议伐吴之策。正是:汉家城郭已非旧,吴国江山将复更。 未知怎生伐吴,且看下文分解。 (本章完) -第120章 荐杜预老将献新谋 降孙皓三分归一统 +第120章 荐杜预老将献新谋 降孙皓三分归一统   却说吴主孙休,闻司马炎已篡魏,知其必将伐吴,忧虑成疾,卧床不起,乃召丞相濮阳兴入宫中,令太子孙(上雨下单)出拜。吴主把兴臂、手指(上雨下单)而卒。兴出,与群臣商议,欲立太子孙(上雨下单)为君。左典军万彧曰:“(上雨下单)幼不能专政,不若取乌程侯孙皓立之。”左将军张布亦曰:“皓才识明断,堪为帝王。”丞相濮阳兴不能决,入奏朱太后。太后曰:“吾寡妇人耳,安知社稷之事?卿等斟酌立之可也。”兴遂迎皓为君。 皓字元宗,大帝孙权太子孙和之子也。当年七月,即皇帝位,改元为元兴元年,封太子孙(上雨下单)为豫章王,追谥父和为文皇帝,尊母何氏为太后,加丁奉为右大司马。次年改为甘露元年。皓凶暴日甚,酷溺酒色,宠幸中常侍岑昏。濮阳兴、张布谏之,皓怒,斩二人,灭其三族。由是廷臣缄口,不敢再谏。又改宝鼎元年,以陆凯、万彧为左右丞相。时皓居武昌,扬州百姓溯流供给,甚苦之;又奢侈无度,公私匮乏。陆凯上疏谏曰:“今无灾而民命尽,无为而国财空,臣窃痛之。昔汉室既衰,三家鼎立;今曹、刘失道,皆为晋有:此目前之明验也。臣愚但为陛下惜国家耳。武昌土地险瘠,非王者之都。且童谣云:宁饮建业水,不食武昌鱼;宁还建业死,不止武昌居!此足明民心与天意也。今国无一年之蓄,有露根之渐;官吏为苛扰,莫之或恤。大帝时,后宫女不满百;景帝以来,乃有千数:此耗财之甚者也。又左右皆非其人,群党相挟,害忠隐贤,此皆蠹政病民者也。愿陛下省百役,罢苛扰,简出宫女,清选百官,则天悦民附而国安矣。” 疏奏,皓不悦。又大兴土木,作昭明宫,令文武各官入山采木;又召术士尚广,令筮蓍问取天下之事。尚对曰:“陛下筮得吉兆:庚子岁,青盖当入洛阳。”皓大喜,谓中书丞华覈曰:“先帝纳卿之言,分头命将,沿江一带,屯数百营,命老将丁奉总之。朕欲兼并汉土,以为蜀主复仇,当取何地为先?”覈谏曰:“今成都不守,社稷倾崩,司马炎必有吞吴之心。陛下宜修德以安吴民,乃为上计。若强动兵甲,正犹披麻救火,必致自焚也。愿陛下察之。”皓大怒曰:“朕欲乘时恢复旧业,汝出此不利之言!若不看汝旧臣之面,斩首号令!”叱武士推出殿门。华覈出朝叹曰:“可惜锦绣江山,不久属于他人矣!”遂隐居不出。于是皓令镇东将军陆抗部兵屯江口,以图襄阳。早有消息报入洛阳,近臣奏知晋主司马炎。 diff --git a/assets/books/theWealthOfNations/theWealthOfNations.txt b/assets/books/theWealthOfNations/theWealthOfNations.txt index 90b96a0..496195f 100644 --- a/assets/books/theWealthOfNations/theWealthOfNations.txt +++ b/assets/books/theWealthOfNations/theWealthOfNations.txt @@ -1,4 +1,4 @@ -ÐòÂۼ°ȫÊéÉè¼Æ +ÐòÂۼ°ȫÊéÉè¼Æ ¡¡¡¡һ¹ú¹úÃñÿÄêµÄÀͶ¯£¬±¾À´¾ÍÊǹ©¸øËûÃÇÿÄêÏû·ѵÄһÇÐÉú»î±ØÐèƷºͱãÀûƷµÄԴȪ¡£¹¹³ÉÕâÖֱØÐèƷºͱãÀûƷµģ¬»òÊDZ¾¹úÀͶ¯µÄֱ½ӲúÎ»òÊÇÓÃÕâÀà²úÎï´ÓÍâ¹ú¹º½øÀ´µÄÎïƷ¡£ ¡¡¡¡ÕâÀà²úÎï»òÓÃÕâÀà²úÎï´ÓÍâ¹ú¹º½øÀ´µÄÎïƷ£¬¶ÔÏû·ÑÕßÈËÊý£¬»òÊÇÓÐ×ŴóµıÈÀý£¬»òÊÇÓÐ×ÅСµıÈÀý£¬ËùÒÔһ¹ú¹úÃñËùÐèҪµÄһÇбØÐèƷºͱãÀûƷ¹©¸øÇé¿öµĺûµ£¬ÊÓÕâһ±ÈÀýµĴóС¶ø¶¨¡£ ¡¡¡¡µ«ÎÞÂ۾ÍÄÄһ¹ú¹úÃñ˵£¬Õâһ±ÈÀý¶¼ҪÊÜÏÂÊöÁ½ÖÖÇé¿öµÄ֧Å䣺µÚһ£¬һ°ãµØ˵£¬Õâһ¹ú¹úÃñÔËÓÃÀͶ¯£¬ÊÇÔõÑùÊìÁ·£¬ÔõÑù¼¼Çɣ¬ÔõÑùÓÐÅжÏÁ¦£»µڶþ£¬´ÓÊÂÓÐÓÃÀͶ¯µÄÈËÊýºͲ»´ÓÊÂÓÐÓÃÀͶ¯µÄÈËÊý£¬¾¿³Éʲô±ÈÀý¡£²»ÂÛһ¹úÍÁÈÀ¡¢ÆøºòºÍÃæ»ýÊÇÔõÑù£¬ËüµĹúÃñÿÄ깩¸øµĺûµ£¬±ØȻȡ¾öÓÚÕâÁ½ÖÖÇé¿ö¡£ @@ -11,10 +11,10 @@ -µÚһƪ¡¡ÂÛÀͶ¯Éú²úÁ¦Ôö½øµÄԭÒò£¬ +µÚһƪ¡¡ÂÛÀͶ¯Éú²úÁ¦Ôö½øµÄԭÒò£¬ ²¢ÂÛÀͶ¯Éú²úÎï×ÔȻ¶øȻµطÖÅ䏸¸÷½׼¶ÈËÃñµÄ˳Ðò -µÚһÕ Â۷ֹ¤ +µÚһÕ Â۷ֹ¤ ¡¡¡¡ÀͶ¯Éú²úÁ¦ÉÏ×î´óµÄÔö½ø£¬ÒԼ°ÔËÓÃÀͶ¯ʱËù±íÏֵĸü´óµÄÊìÁ·¡¢¼¼ÇɺÍÅжÏÁ¦£¬Ëƺõ¶¼ÊǷֹ¤µĽá¹û¡£ ¡¡¡¡Ϊʹ¶ÁÕßÒ×ÓÚÀí½âÉç»áһ°ãҵÎñ·ֹ¤Ëù²úÉúµĽá¹û£¬ÎÒÏÖÔÚÀ´ÌÖÂ۸ö±ðÖÆÔìҵ·ֹ¤״¿ö¡£һ°ãÈËÈÏΪ£¬·ֹ¤×îÍêȫµÄÖÆÔìҵ£¬ÄËÊÇһЩ¼«²»ÖØҪµÄÖÆÔìҵ¡£²»ÖØҪÖÆÔìҵµķֹ¤£¬ʵ¼ÊÉϲ¢²»±ÈÖØҪÖÆÔìҵµķֹ¤¸üΪÖÜÃܡ£µ«Êǣ¬ĿµÄÔÚÓڹ©¸øÉÙÊýÈËСÁ¿ÐèҪµIJ»ÖØҪÖÆÔìҵ£¬Ëù¹ÍÓõÄÀͶ¯ÕßÈËÊý£¬±ØȻ²»¶࣬¶ø´Óʸ÷²¿Ãʤ×÷µĹ¤Èˣ¬ÍùÍù¿ɼ¯ºÏÔÚͬһ¹¤³§Äڣ¬ʹ¹۲ìÕßÄÜһÀÀÎÞÒš£·´֮£¬ÄÇЩ´óÖÆÔìҵ£¬Ҫ¹©¸ø´ó¶àÊýÈ˵ĴóÁ¿ÐèҪ£¬ËùÒԣ¬¸÷¹¤×÷²¿ÃŶ¼¹ÍÓÐÐíÐí¶à¶àÀͶ¯Õߣ¬Ҫ°ÑÕâÐíÐí¶à¶àÀͶ¯Õ߼¯ºÏÔÚһ¸ö³§Äڣ¬ÊƲ»¿ÉÄܡ£ÎÒÃÇҪͬʱ¿´¼ûһ¸ö²¿ÃÅÒÔÉϵŤÈˣ¬Ҳ²»¿ÉÄܡ£ÏóÕâÖִóÖÆÔìҵµĹ¤×÷£¬¾¡¹Üʵ¼ÊÉϱÈСÖÆÔìҵ·ֳɶàµöàµIJ¿·֣¬µ«ÒòΪÕâÖֻ®·ֲ»ÄÜÏóСÖÆÔìҵµĻ®·ÖÄÇôÃ÷Ïԣ¬ËùÒԺÜÉÙÈËעÒ⵽¡£ ¡¡¡¡¿ÛÕëÖÆÔìҵÊǼ«΢СµÄÁˣ¬µ«Ëüµķֹ¤ÍùÍù»½ÆðÈËÃǵÄעÒ⡣ËùÒԣ¬ÎҰÑËüÒýÀ´×÷ΪÀý×ӡ£һ¸öÀͶ¯Õߣ¬Èç¹û¶ÔÓÚÕâְҵ£¨·ֹ¤µĽá¹û£¬ʹ¿ÛÕëµÄÖÆÔì³ÉΪһÖÖרÃÅְҵ£©ûÓÐÊܹýÏ൱ѵÁ·£¬Óֲ»֪ÔõÑùʹÓÃÕâְҵÉϵĻúе£¨ʹÕâÖֻúеÓз¢Ã÷µĿÉÄܵģ¬¿ÖÅÂҲÊǷֹ¤µĽá¹û£©£¬ÄÇĩ×Ýʹ½ßÁ¦¹¤×÷£¬ҲÐíһÌìҲÖÆÔ첻³öһö¿ÛÕ룬Ҫ×ö¶þʮö£¬µ±ȻÊǾö²»¿ÉÄÜÁˡ£µ«°´ÕÕÏÖÔھ­Ӫµķ½·¨£¬²»µ«ÕâÖÖ×÷ҵȫ²¿ÒѾ­³ÉΪרÃÅְҵ£¬¶øÇÒÕâÖÖְҵ·ֳÉÈô¸ɲ¿Ãţ¬ÆäÖÐÓдó¶àÊýҲͬÑù³ÉΪרÃÅְҵ¡£һ¸öÈ˳éÌúÏߣ¬һ¸öÈËÀ­ֱ£¬һ¸öÈËÇнأ¬һ¸öÈËÏ÷¼âÏߵÄһ¶ˣ¬һ¸öÈËĥÁíһ¶ˣ¬ÒԱãװÉÏԲͷ¡£Ҫ×öԲͷ£¬¾ÍÐèҪÓжþÈýÖֲ»ͬµIJÙ×÷¡£װԲͷ£¬Ϳ°×ɫ£¬ÄËÖÁ°üװ£¬¶¼ÊÇרÃŵÄְҵ¡£ÕâÑù£¬¿ÛÕëµÄÖÆÔì·ÖΪʮ°ËÖֲÙ×÷¡£ÓÐЩ¹¤³§£¬Õâʮ°ËÖֲÙ×÷£¬·ÖÓÉʮ°˸öרÃŹ¤È˵£ÈΡ£¹ÌȻ£¬ÓÐʱһÈËҲ¼æÈζþÈýÚ£ÎҼû¹ýһ¸öÕâÖÖС¹¤³§£¬ֻ¹ÍÓÃʮ¸ö¹¤Èˣ¬Òò´ËÔÚÕâһ¸ö¹¤³§ÖУ¬Óм¸¸ö¹¤È˵£ÈζþÈýÖֲÙ×÷¡£ÏóÕâÑùһ¸öС¹¤³§µĹ¤Èˣ¬ËäºÜÇîÀ§£¬ËûÃǵıØҪ»úеÉ豸£¬Ëäºܼòª£¬µ«ËûÃÇÈç¹ûÇÚÃãŬÁ¦£¬һÈÕҲÄܳÉÕëʮ¶þ°õ¡£´Óÿ°õÖеÈÕëÓÐËÄǧö¼ƣ¬Õâʮ¸ö¹¤ÈËÿÈվͿɳÉÕëËÄÍò°Ëǧö£¬¼´һÈËһÈտɳÉÕëËÄǧ°˰Ùö¡£Èç¹ûËûÃǸ÷×ԶÀÁ¢¹¤×÷£¬²»רϰһÖÖÌØÊâҵÎñ£¬ÄÇĩ£¬ËûÃDz»ÂÛÊÇ˭£¬¾ø¶Բ»ÄÜһÈÕÖÆÔì¶þʮöÕ룬˵²»¶¨һÌìÁ¬һöÕëҲÖÆÔ첻³öÀ´¡£ËûÃDz»µ«²»ÄÜÖƳö½ñÈÕÓÉÊʵ±·ֹ¤ºÏ×÷¶øÖƳɵÄÊýÁ¿µĶþ°ÙËÄʮ·Ö֮һ£¬¾ÍÁ¬ÕâÊýÁ¿µÄËÄǧ°˰ٷÖ֮һ£¬¿ÖÅÂҲÖÆÔ첻³öÀ´¡£ @@ -29,7 +29,7 @@ -µڶþÕ Â۷ֹ¤µÄԭÓÉ +µڶþÕ Â۷ֹ¤µÄԭÓÉ ¡¡¡¡Òý³öÉÏÊöÐí¶àÀûÒæµķֹ¤£¬ԭ²»ÊÇÈËÀàÖǻ۵Ľá¹û£¬¾¡¹ÜÈËÀàÖǻÛԤ¼ûµ½·ֹ¤»á²úÉúÆձ鸻ԣ²¢ÏëÀûÓÃËüÀ´ʵÏÖÆձ鸻ԣ¡£ËüÊDz»ÒÔÕâ¹ã´óЧÓÃΪĿ±êµÄһÖÖÈËÀàÇãÏòËù»ºÂý¶øÖð½¥Ôì³ɵĽá¹û£¬ÕâÖÖÇãÏò¾ÍÊǻ¥ͨÓÐÎޣ¬ÎïÎサ»»£¬»¥ÏཻÒס£ ¡¡¡¡ÊöÖÖÇãÏò£¬ÊDz»ÊÇһÖֲ»Äܽøһ²½·ÖÎöµı¾ȻµÄÐÔÄܣ¬»òÕ߸üȷÇеØ˵ÊDz»ÊÇÀíÐԺÍÑÔÓïÄÜÁ¦µıØȻ½á¹û£¬ÕⲻÊôÓÚÎÒÃÇÏÖÔÚÑо¿µķ¶Χ¡£ÕâÖÖÇãÏò£¬ΪÈËÀàËù¹²ÓУ¬ÒàΪÈËÀàËùÌØÓУ¬ÔÚÆäËû¸÷Öֶ¯ÎïÖÐÊÇÕҲ»µ½µġ£ÆäËû¸÷Öֶ¯ÎËƺõ¶¼²»֪µÀÕâÖֻòÆäËûÈκÎһÖÖЭԼ¡£Á½ֻÁÔȮͬÖðһÍã¬ÓÐʱҲÏóÊÇһÖÖЭͬ¶¯×÷¡£ËüÃǰÑÍÃÖðÏò¶ÔÊֵķ½Ï򣬻òÔڶÔÊְÑÍÃÖðµ½ËüÄDZßʱ£¬¼ÓÒÔÀ¹½ء£²»¹ý¡£ÕâÖÖЭͬ¶¯×÷£¬ֻÊÇÔÚijһÌض¨ʱ¿̣¬ËüÃǵÄÓûÍû¶ÔÓÚͬһ¶ÔÏóµÄżȻµÄһÖ£¬¶ø²¢²»ÊÇÆõԼµĽá¹û¡£ÎÒÃǴÓδ¼û¹ý¼×ÒÒÁ½Ȯ¹«ƽÉóÉ÷µؽ»»»¹Çͷ¡£Ҳ´Óδ¼û¹ýһÖֶ¯ÎÒÔ×ËÊƻò×ÔȻºôÉù£¬ÏòÆäËû¶¯ÎïʾÒâ˵£ºÕâΪÎÒÓУ¬ÄÇΪÄãÓУ¬ÎÒԸÒâÒԴËÒױˡ£һ¸ö¶¯ÎÈç¹ûÏëÓÉһ¸öÈ˻òÆäËû¶¯ÎïȡµÃijÎ³ý²©µÃÊÚÓëÕߵ϶ÐÄÍ⣬²»ÄÜÓбðÖÖ˵·þÊֶΡ£СȮҪµÃʳ£¬¾ÍÏòĸȮ°ٰãÏ×Ã컼ҹ·ҪµÃʳ£¬¾Í×÷³öÖÖÖֽ¿̬£¬À´»½Æðʳ×ÀÉÏÖ÷È˵ÄעÒ⡣ÎÒÃÇÈËÀ࣬¶ÔÓÚͬ°û£¬ÓÐʱҲ²ÉȡÕâÖÖÊֶΡ£Èç¹ûËûûÓбðµÄÊʵ±·½·¨£¬½Ðͬ°ûÂú×ãËûµÄÒâԸ£¬Ëû»áÒÔÖÖÖֱ°ÁӰ¢ÚĵÄÐÐΪ£¬²©ȡ¶Է½µĺñÒ⡣²»¹ýÕâÖְ취£¬ֻÄÜżһΪ֮£¬ÏëӦÓõ½һÇг¡ºϣ¬ȴΪʱ¼äËù²»Ðí¡£һ¸öÈ˾¡±ÏÉú֮Á¦£¬ÒàÄѲ©µü¸¸öÈ˵ĺøУ¬¶øËûÔÚÎÄÃ÷Éç»áÖУ¬ËæʱÓÐȡµöàÊýÈ˵ÄЭ×÷ºÍԮÖúµıØҪ¡£±ðµĶ¯Îһ´ﵽ׳ÄêÆڣ¬¼¸ºõȫ¶¼Äܹ»¶ÀÁ¢£¬×ÔȻ״̬Ï£¬²»ÐèҪÆäËû¶¯ÎïµÄԮÖú¡£µ«ÈËÀ༸ºõËæʱËæµض¼ÐèҪͬ°ûµÄЭÖú£¬ҪÏë½ö½öÒÀÀµËûÈ˵Ķ÷»ݣ¬ÄÇÊÇһ¶¨²»Ðеġ£ËûÈç¹ûÄܹ»´̼¤ËûÃǵÄÀû¼ºÐģ¬ʹÓÐÀûÓÚËû£¬²¢¸æËßËûÃǣ¬¸øËû×÷Ê£¬ÊǶÔËûÃÇ×ԼºÓÐÀûµģ¬ËûҪ´ﵽĿµľÍÈÝÒ׵öàÁˡ£²»ÂÛÊÇ˭£¬Èç¹ûËûҪÓëÅÔÈË×÷ÂòÂô£¬ËûÊ×ÏȾÍҪÕâÑùÌáÒ顣Çë¸øÎÒÒÔÎÒËùҪµĶ«Î÷°ɣ¬ͬʱ£¬ÄãҲ¿ÉÒԻñµÃÄãËùҪµĶ«Î÷£ºÕâ¾仰Êǽ»Ò׵ÄͨÒ塣ÎÒÃÇËùÐèҪµÄÏ໥°ï棬´󲿷ÖÊÇÒÀÕÕÕâ¸ö·½·¨ȡµõġ£ÎÒÃÇÿÌìËùÐèµÄʳÁϺÍÒûÁϣ¬²»Êdzö×ÔÍÀ»§¡¢Äð¾ƼһòÀÓÃæʦµĶ÷»ݣ¬¶øÊdzöÓÚËûÃÇ×ÔÀûµĴòË㡣ÎÒÃDz»˵»½ÆðËûÃÇÀûËûÐĵϰ£¬¶ø˵»½ÆðËûÃÇÀû¼ºÐĵϰ¡£ÎÒÃDz»˵×ԼºÓÐÐèҪ£¬¶ø˵¶ÔËûÃÇÓÐÀû¡£Éç»áÉϣ¬³ýÆòؤÍ⣬ûÓÐһ¸öÈËԸÒâȫȻ¿¿±ðÈ˵Ķ÷»ݹý»¶øÇң¬¾ÍÁ¬Æòؤ£¬Ҳ²»ÄÜһζÒÀÀµ±ðÈˡ£³ÏȻ£¬ÆòؤÉú»î×ÊÁϵĹ©¸ø£¬ÖÁ²¿³ö×ÔÉÆÈ˵Ĵȱ¯¡£ËäȻÕâÖֵÀÒå¹é¸ùµ½µ׸øÆòؤÌṩÁËËûËùÐèҪµÄһÇж«Î÷£¬µ«ûÓУ¬Ҳ²»¿ÉÄܣ¬ËæʱËæ¿̸øËûÌṩËûËùÐèҪµĶ«Î÷¡£ËûµĴ󲿷ÖÁÙʱÐèҪºÍÆäËûÈËһÑù£¬ҲÊÇͨ¹ýÆõԼ¡¢½»»»ºÍÂòÂô¶øµõ½¹©¸øµġ£Ëû°Ñһ¸öÈ˸øËûµĽðǮ£¬ÄÃȥ¹ºÂòʳÎ°ÑÁíһ¸öÈ˸øËûµľÉÒ£¬ÄÃȥ½»»»¸üºÏÉíµľÉÒ£¬»򽻻»һЩʳÁϺͼÄË޵ĵط½£»»òÕߣ¬ÏȰѾÉÒ»»³ɻõ±ң¬ÔÙÓûõ±ҹºÂò×ԼºÐèҪµÄʳƷ¡¢Ò·þºÍסËù¡£ ¡¡¡¡ÓÉÓÚÎÒÃÇËùÐèҪµÄÏ໥°ï棬´󲿷ÖÊÇͨ¹ýÆõԼ¡¢½»»»ºÍÂòÂôȡµõģ¬ËùÒԵ±³õ²úÉú·ֹ¤µÄҲÕýÊÇÈËÀàҪÇó»¥Ïཻ»»Õâ¸öÇãÏò¡£ÀýÈ磬ÔÚá÷ÁԻòÓÎÄÁÃñ×åÖУ¬ÓиöÉÆÓÚÖÆÔ칭ʸµÄÈˣ¬ËûÍùÍùÒÔ×ԼºÖƳɵĹ­ʸ£¬ÓëËûÈ˽»»»¼ÒÐó»òÊÞÈ⣬½á¹ûËû·¢¾õ£¬ÓëÆäÇ××Ե½ҰÍⲶÁԣ¬µ¹²»ÈçÓëÁÔÈ˽»»»£¬ÒòΪ½»»»ËùµÃȴ±Ƚ϶ࡣΪËû×ÔÉíµÄÀû°»´òË㣬ËûֻºÃÒÔÖÆÔ칭ʸΪÖ÷ҪҵÎñ£¬ÓÚÊÇËû±ã³ÉΪһÖÖÎäÆ÷ÖÆÔìÕߡ£ÁíÓÐһ¸öÈˣ¬Òò³¤Óڽ¨ÔìСé·¿»òÒƶ¯·¿ÎݵĿò¼ܺÍÎݶ¥£¬ÍùÍù±»ÈËÇëȥÔìÎݣ¬µüÒÐóÊÞÈâΪ³꣬ÓÚÊÇËûÖÕÓڷ¢¾õ£¬ÍêȫÏ×ÉíÓÚÕâһ¹¤×÷¶Ô×ԼºÓÐÀû£¬Òò¶ø¾ͳÉΪһ¸ö·¿Îݽ¨ÖþÕߡ£ͬÑù£¬µÚÈý¸öÈ˳ÉΪÌú½³»òͭ½³£¬µÚËĸöÈ˳ÉΪÏõƤÕ߻òÖƸïÕߣ¬Ƥ¸ïÊÇ먦ËûÈËÀàµÄÖ÷ҪÒÂÁϡ£ÕâÑùһÀ´£¬ÈËÈ˶¼һ¶¨Äܹ»°Ñ×ԼºÏû·Ѳ»Á˵Ä×ԼºÀͶ¯Éú²úÎïµÄʣÓಿ·֣¬»»µÃ×ԼºËùÐèҪµıðÈËÀͶ¯Éú²úÎïµÄʣÓಿ·֡£Õâ¾͹ÄÀø´ó¼Ҹ÷×ÔίÉíÓÚһÖÖÌض¨ҵÎñ£¬ʹËûÃÇÔڹÈ×ԵÄҵÎñÉϣ¬ĥÁ¶ºͷ¢»Ӹ÷×ԵÄÌ츳×ÊÖʻò²ÅÄܡ£ @@ -38,7 +38,7 @@ -µÚÈýÕ¡¡Â۷ֹ¤ÊÜÊг¡·¶ΧµÄÏÞÖÆ +µÚÈýÕ¡¡Â۷ֹ¤ÊÜÊг¡·¶ΧµÄÏÞÖÆ ¡¡¡¡·ֹ¤ÆðÒòÓڽ»»»ÄÜÁ¦£¬·ֹ¤µij̶ȣ¬Òò´Ë×ÜҪÊܽ»»»ÄÜÁ¦´óСµÄÏÞÖƣ¬»»ÑÔ֮£¬ҪÊÜÊг¡¹ãÏÁµÄÏÞÖơ£Êг¡ҪÊǹýС£¬ÄǾͲ»ÄܹÄÀøÈËÃÇÖÕÉúרÎñһҵ¡£ÒòΪÔÚÕâÖÖ״̬Ï£¬ËûÃDz»ÄÜÓÃ×ԼºÏû·Ѳ»Á˵Ä×ԼºÀͶ¯Éú²úÎïµÄʣÓಿ·֣¬ËæÒ⻻µÃ×ԼºÐèҪµıðÈËÀͶ¯Éú²úÎïµÄʣÓಿ·֡£ ¡¡¡¡ÓÐЩҵÎñ£¬ÄÇÅÂÊÇ×îÆÕͨµÄҵÎñ£¬ҲֻÄÜÔڴó¶¼Êо­Ӫ¡£ÀýÈç°áÔ˹¤Èˣ¬¾ÍֻÄÜÔڴó¶¼ÊÐÉú»С´åÂä¹̲»´ýÑԣ»¼´ÆÕͨÐæÊУ¬ÒàÏӹýС£¬²»ÄܸøËûÒԲ»¶ϵŤ×÷¡£ɢ²¼ÔڻÄÁ¹µÄËոñÀ¼¸ߵØһ´øµÄÈ˼£ϡÉٵÄСÏç´åµÄũ·򣬲»ÂÛÊÇ˭£¬Ҳ²»Äܲ»Ϊ×ԼºµļÒÊô¼æ³äÍÀ»§¡¢ÀÓÃæʦÄËÖÁÄð¾ÆÈˡ£ÔÚÄÇÖֵط½£¬ҪÔڶþʮÁ¨ÄÚÕҵ½¶þ¸öÌú½³¡¢ľ½³»òÄàˮ½³£¬Ҳ²»ÈÝÒס£ÀëÕâ°๤½³ÖÁÉÙÓа˾ÅÁ¨֮ßbµÄÁãÐÇɢ¾ÓÈ˼ң¬ֻºÃÇ××Զ¯ÊÖ×÷Ðí¶àСÊÂÇ飻ÔÚÈ˿ÚÖڶàµĵط½£¬ÄÇЩСÊÂÇéһ¶¨»á¹ÍÇëרҵ¹¤È˰ïæ¡£ũ´幤È˼¸ºõµ½´¦¶¼ÊÇһ¸öÈ˼æӪ¼¸ÖÖÐÔÖʺÜÀàËÆÒò¶øʹÓÃͬһ²ÄÁϵÄÐÐҵ¡£ũ´åľ½³ҪÖÆÔìһÇÐľÖƵÄÎïƷ£»ũ´åÌú½³ҪÖÆ×÷һÇÐÌúÖƵÄÎïƷ¡£ũ´åľ½³²»½öÊÇľ½³£¬ͬʱÓÖÊÇϸ¹¤ľ½³£¬¼Ҿßʦ¡¢µñ¿Ìʦ¡¢³µÂÖÖÆÔìÕߡ¢¸ûÀçÖÆÔìÕߣ¬ÄËÖÁ¶þÂÖËÄÂÖÔ˻õ³µÖÆÔìÕߡ£ľ½³µĹ¤×÷Èç´˷±Ôӣ¬Ìú½³µĹ¤×÷»¹¸ü·±Ôӡ£ÔÚËոñÀ¼¸ߵØÄÇÑùƧԶÄڵأ¬ÎÞÂÛÈçºΣ¬×Üά³ֲ»ÁËһ¸öרÃÅÔìÌú¶¤µĹ¤Èˡ£ÒòΪËû¼´ʹһÈÕֻÄÜÖƶ¤һǧö£¬һÄêֻÀͶ¯Èý°ÙÈգ¬ҲÿÄêÄÜÖƶ¤ÈýʮÍòö¡£µ«ÔÚÄÇÀһÄêҲÏú²»ÁËËûһÈյÄÖÆÔì¶¾ÍÊÇ˵Ïú²»ÁËһǧö¡£ ¡¡¡¡ˮÔ˿ªÍØÁ˱ȽÔËËù¿ªÍصĹã´óµöàµÄÊг¡£¬ËùÒԴÓÀ´¸÷Öֲúҵµķֹ¤¸ÄÁ¼£¬×ÔȻ¶øȻµض¼¿ªʼÓÚÑغ£ÑغÓһ´ø¡£ÕâÖָÄÁ¼ÍùÍù¾­¹ýÐí¾ÃÒԺó²ÅÂýÂýÆռ°µ½Äڵء£ÏÖÔڣ¬ÒÔÓùÕ߶þÈËÂí°Ëƥ£¬¼ݹã·øËÄÂÖÔ˻õ³µһÁ¾£¬ÔØÖØԼËĶֻõÎÍù·µÂ׶غͰ®¶¡±¤¼䣬¼ÆÐèÁùÐÇÆÚÈճ̡£Ȼ¶ø£¬ÓÉÁùÈ˻ò°ËÈ˼Ýʻ´¬һËң¬ÔØÖضþ°ٶֻõÎÍù·µÂ׶غÍÀû˹¼䣬ҲֻÐèͬÑùÈճ̡£ËùÒÔÐèһ°ÙÈˣ¬ËİÙƥÂíºÍÎåʮÁ¾ËÄÂÖÔ˻õ³µ°áÔ˵ĻõÎ¿ɽèˮÔË֮±㣬ÓÉÁùÈ˻ò°ËÈ˰áÔˡ£¶øÇң¬°Ѷþ°ٶֻõÎïÓÉÂ׶ØÔËÍù°®¶¡±¤£¬ÒÀ×îµÍ½Ô˷ѼÆË㣬ÒàÐ踺µ£һ°ÙÈËÈý¸öÐÇÆڵÄÉú»î·ѺÍËİÙƥÂíÎåʮÁ¾ËÄÂÖÔ˻õ³µµÄά³ַѣ¬ÒԼ°ºÍά³ַѼ¸ºõÏàµȵÄÏûºġ£ÈôÓÉˮÔˣ¬ËùӦ¸ºµ£µģ¬³äÆäÁ¿Ҳ²»¹ýÊÇÁùÈËÖÁ°ËÈ˵ÄÉú»î·ѣ¬ÔØÖضþ°ٶֻõ´¬µÄÏûºķѣ¬ºͽϴóµı£Ïշѣ¬¼´ˮÔ˱£ÏշÑÓë½Ô˱£ÏշÑ֮¼äµIJî¶ËùÒԣ¬¼ÙÈôÔÚÕâÁ½¶¼Êм䣬³ý½ÔËÍ⣬ûÓÐÆäËû½»ͨ·½·¨£¬ÄÇĩ³ýÁËÄÇЩÖØÁ¿²»´ó¶ø¼۸ñºܸߵĻõÎï¶øÍ⣬±ãûÓÐʲôÉÌƷÄÜÓÉһµØÔËÖÁÁíһµØÁˡ£ÕâÑù£¬Á½µؼäµÄÉÌҵ£¬¾ÍֻÓÐÏֽñµÄһС²¿·֣¬¶øÕâÁ½µØÏ໥¼ä¶Բúҵ·¢չÌṩµĴ̼¤£¬ҲֻÓÐÏֽñµÄһС²¿·֡£¼ÙʹÊÀ½çÉÏֻÓнÔˣ¬Ôò¸÷ƧԶµØÇø¼äµÄÉÌҵ£¬һ¶¨»áÎ޷¨½øÐС£ÓÐʲô»õÎ¸ºµ£µÃÆðÓÉÂ׶ØÖÁ¼Ӷû¸÷´ðµÄ½ÉÏÔ˷ÑÄأ¬¼´ʹÓÐÕâÖֻõÎÓÖÓÐʲôÊäËͷ½·¨ÄÜʹ»õÎﰲȻͨ¹ý½éÔÚÁ½µؼäµÄÐí¶àҰÂùÃñ×åµÄÁìÍÁÄأ¬Ȼ¶ø£¬ÏֽñÕâÁ½¸ö¶¼ÊУ¬Ï໥½øÐдó¹æģµÄóÒף¬Ï໥ÌṩÊг¡£¬²¢¶Ա˴˵IJúҵ·¢չ£¬Ï໥¸øÓëºܴóµĹÄÀø¡£ @@ -50,7 +50,7 @@ -µÚËÄÕ¡¡Âۻõ±ҵÄÆðԴ¼°ÆäЧÓà +µÚËÄÕ¡¡Âۻõ±ҵÄÆðԴ¼°ÆäЧÓà ¡¡¡¡·ֹ¤һ¾­ÍêȫȷÁ¢£¬һ¸öÈË×ԼºÀͶ¯µÄÉú²úÎ±ãֻÄÜÂú×ã×ԼºÓûÍûµļ«С²¿·֡£ËûµĴ󲿷ÖÓûÍû£¬ÐëÓÃ×ԼºÏû·Ѳ»Á˵ÄʣÓàÀͶ¯Éú²úÎ½»»»×ԼºËùÐèҪµıðÈËÀͶ¯Éú²úÎïµÄʣÓಿ·ÖÀ´Âú×㡣ÓÚÊǣ¬һÇÐÈ˶¼ҪÒÀÀµ½»»»¶øÉú»»òÕß˵£¬ÔÚһ¶¨³̶ÈÉϣ¬һÇÐÈ˶¼³ÉΪÉÌÈˣ¬¶øÉç»᱾Éí£¬ÑϸñµØ˵£¬Ҳ³ÉΪÉÌҵÉç»ᡣ ¡¡¡¡µ«Ôڸտªʼ·ֹ¤µÄʱºò£¬ÕâÖֽ»»»Á¦µÄ×÷Óã¬ÍùÍù¼«²»ÁéÃô¡£¼ÙÉè¼׳ÖÓÐijÖÖÉÌƷ£¬×ԼºÏû·Ѳ»Áˣ¬¶øÒÒËù³ÖÓеÄÕâÖÖÎïƷ£¬ȴ²»¹»×ԼºÏû·ѡ£Õâʱ£¬¼׵±ȻÀÖÓڳöÂô£¬Òҵ±ȻÀÖÓڹºÂò¼×ÊÖÖÐʣÓàÎïƷµÄһ²¿·֣¬µ«ÈôÒÒÊÖÖУ¬²¢δ³ÖÓм×ĿÏÂϣÇóµÄÎïƷ£¬ËûÃÇÁ½Õ߼䵼»Òף¬ÈÔȻ²»ÄÜʵÏ֡£±ÈÈ磬ÍÀ»§°Ñ×ԼºÏû·Ѳ»Á˵ÄÈ⣬·ÅÔڵêÄڣ¬Äð¾ƼҺÍÀÓÃæʦ£¬¹ÌȻ¶¼ԸÒ⹺Âò×ԼºËùÐèҪµÄһ·ݣ¬µ«Õâʱ£¬¼ÙÉèËûÃdzýÁ˸÷×ԵÄÖÆÔìƷÍ⣬ûÓбðÖֿɹ©½»Ò׵ÄÎïƷ£¬¶øÍÀ»§ÏÖʱÐèҪµÄÂó¾ƺÍÃæ°ü£¬ÒѾ­µõ½Á˹©¸ø£¬ÄÇĩ£¬ËûÃDZ˴Ë֮¼䣬ûÓнøÐн»Ò׵ĿÉÄܡ£ÍÀ»§²»ÄÜ×÷Äð¾ƼҺÍÀÓÃæʦµÄÉÌÈˣ¬¶øÄð¾ƼҺÍÀÓÃæʦҲ²»ÄÜ×÷ÍÀ»§µĹ˿͡£ÕâÑù£¬ËûÃǾͲ»Äܻ¥Ïà°ïÖú¡£Ȼ¶ø£¬×Էֹ¤ȷÁ¢ÒÔÀ´£¬¸÷ʱ´ú¸÷Éç»áÖУ¬ÓÐ˼ÂǵÄÈˣ¬ΪÁ˱ÜÃâÕâÖֲ»±㣬³ý×ԼºÀͶ¯Éú²úÎïÍ⣬ËæʱÉí±ߴøÓÐһ¶¨ÊýÁ¿µÄijÖÖÎïƷ£¬ÕâÖÖÎïƷ£¬ÔÚËûÏëÀ´£¬ÄÃȥºÍÈκÎÈ˵ÄÉú²úÎサ»»£¬¶¼²»»á¼û¾ܾø¡£ ¡¡¡¡ΪÕâĿµĶø±»ÈËÃÇÏȺóÏ뵽²¢ÓùýµÄÎïƷ¿ÉÓÐÖÖÖ֡£δ¿ª»¯Éç»ᣬ¾Ý˵ÔøÒÔÉüÐó×÷ΪÉÌҵÉϵÄͨÓÃý½顣ÉüÐóÎÞÒÉÊǼ«²»±ãµÄý½飬µ«ÎÒÃÇȴ·¢ÏÖÁˣ¬¹ŴúÍùÍùÒÔÉüÐóͷÊý×÷Ϊ½»»»µÄÆÀ¼۱ê׼£¬Ò༴ÓÃÉüÐ󽻻»¸÷ÖÖÎïƷ¡£ºÉÂíÔø˵£ºµϰÂÃ׵µÄîø¼ף¬½öֵţ¾Åͷ£¬¶ø¸ñÂ޿¨˹µÄîø¼ף¬ȴֵţһ°Ùͷ¡£¾Ý˵£¬°¢±ÈÎ÷ÄáÑÇÒÔÑÎΪÉÌҵ±任µÄý½飻ӡ¶ÈÑغ£ijЩµط½£¬ÒÔijÖֱ´¿ÇΪý½飻¸¥¼ªÄáÑÇÓÃÑ̲ݣ»Ŧ·ÒÀ¼ÓøÉÓ㶡£»ÎҹúÎ÷ӡ¶ÈֳÃñµØÓÃɰÌǣ»ÆäËûÈô¸ɹú¼ÒÔòÓÃÊÞƤ»ò÷·Ƥ¡£¾ÝÎÒËùÎţ¬ֱµ½½ñÈգ¬ËոñÀ¼»¹ÓиöÏç´壬ÓÃÌú¶¤×÷ý½飬¹ºÂòÂó¾ƺÍÃæ°ü¡£ @@ -71,7 +71,7 @@ -µÚÎåÕ¡¡ÂÛÉÌƷµÄÕæʵ¼۸ñÓëÃûÒå¼۸ñ»òÆäÀͶ¯¼۸ñÓë»õ±Ҽ۸ñ +µÚÎåÕ¡¡ÂÛÉÌƷµÄÕæʵ¼۸ñÓëÃûÒå¼۸ñ»òÆäÀͶ¯¼۸ñÓë»õ±Ҽ۸ñ ¡¡¡¡һ¸öÈËÊÇƶÊǸ»£¬¾Ϳ´ËûÄÜÔÚʲô³̶ÈÉÏÏíÊÜÈËÉúµıØÐèƷ¡¢±ãÀûƷºÍÓéÀÖƷ¡£µ«×Էֹ¤ÍêȫȷÁ¢ÒÔÀ´£¬¸÷ÈËËùÐèҪµÄÎïƷ£¬½öÓм«С²¿·ÖÑö¸øÓÚ×ԼºÀͶ¯£¬×î´󲿷ÖȴÐëÑö¸øÓÚËûÈËÀͶ¯¡£ËùÒԣ¬ËûÊÇƶÊǸ»£¬Ҫ¿´ËûÄܹ»֧Åä¶àÉÙÀͶ¯£¬»»ÑÔ֮£¬Ҫ¿´ËûÄܹ»¹ºÂò¶àÉÙÀͶ¯¡£һ¸öÈËռÓÐij»õÎµ«²»Ը×ԼºÏû·ѣ¬¶øԸÓÃÒԽ»»»ËûÎ¶ÔËû˵À´£¬Õâ»õÎïµļÛֵ£¬µÈÓÚʹËûÄܹºÂò»òÄÜ֧ÅäµÄÀͶ¯Á¿¡£Òò´ˣ¬ÀͶ¯ÊǺâÁ¿һÇÐÉÌƷ½»»»¼ÛֵµÄÕæʵ³߶ȡ£ ¡¡¡¡ÈκÎһ¸öÎïƷµÄÕæʵ¼۸񣬼´ҪȡµÃÕâÎïƷʵ¼ÊÉÏËù¸¶³öµĴú¼ۣ¬ÄËÊǻñµÃËüµÄÐÁ¿àºÍÂ鷳¡£¶ÔÓÚÒѵôËÎﵫԸÓÃֻ½»»»ËûÎïµÄÈËÀ´˵£¬ËüµÄÕæÕý¼Ûֵ£¬µÈÓÚÒòռÓÐËü¶øÄÜ×ԼºʡÃⲢת¼ӵ½±ðÈËÉíÉÏȥµÄÐÁ¿àºÍÂ鷳¡£ÒԻõ±һò»õÎﹺÂòÎïƷ£¬¾ÍÊÇÓÃÀͶ¯¹ºÂò£¬ÕýÈçÎÒÃÇÓÃ×ԼºµÄÀͶ¯ȡµÃһÑù¡£´˵Ȼõ±һò»õÎʹÎÒÃÇÄܹ»Ãâ³ýÏ൱µÄÀͶ¯¡£ËüÃǺ¬ÓÐһ¶¨ÀͶ¯Á¿µļÛֵ£¬ÎÒÃÇÓÃÒԽ»»»ÆäËûµ±ʱ±»ÈÏΪÓÐͬÁ¿ÀͶ¯¼ÛֵµÄÎïƷ¡£ÀͶ¯ÊǵÚһÐԼ۸ñ£¬ÊÇ×î³õÓÃÒԹºÂòһÇлõÎïµĴú¼ۡ£ÊÀ¼äһÇвƸ»£¬ԭÀ´¶¼ÊÇÓÃÀͶ¯¹ºÂò¶ø²»ÊÇÓýðÒø¹ºÂòµġ£ËùÒԣ¬¶ÔÓÚռÓвƸ»²¢ԸÓÃÒԽ»»»һЩвúƷµÄÈËÀ´˵£¬ËüµļÛֵ£¬ǡǡµÈÓÚËüʹËûÃÇÄܹ»¹ºÂò»ò֧ÅäµÄÀͶ¯Á¿¡£ ¡¡¡¡»ô²¼˹˵£º²Ƹ»¾ÍÊÇȨÁ¦¡£µ«»ñµûò³м̴ó×ڲƲúµÄÈˣ¬δ±ؾͻñµûò³мÌÁËÃñÕþÉϻò¾üÕþÉϵÄÕþÖÎȨÁ¦¡£ËûµIJƲú£¬ҲÐí¿ÉÒÔÌṩËûһÖֻñµÃÕþȨµÄÊֶΣ¬µ«µ¥ÓвƲúδ±ؾÍÄܸøËûÕþȨ¡£²Ʋú¶ÔËûֱ½ÓÌṩµÄȨÁ¦£¬ÊǹºÂòÁ¦£¬ÊǶÔÓڵ±ʱÊг¡Éϸ÷ÖÖÀͶ¯»ò¸÷ÖÖÀͶ¯Éú²úÎïµÄ֧ÅäȨ¡£ËûµIJƲúµĴóСÓëÕâÖÖ֧ÅäȨµĴóСǡ³ɱÈÀý£¬»»ÑÔ֮£¬²ƲúµĴóС£¬ÓëËûËùÄܹºÂò»òËùÄÜ֧ÅäµÄËûÈËÀͶ¯Á¿»òËûÈËÀͶ¯Éú²úÎïÊýÁ¿µĴóСǡ³ɱÈÀý¡£һÖÖÎïƷµĽ»»»¼Ûֵ£¬±ØȻǡµÈÓÚÕâÎïƷ¶ÔÆäËùÓÐÕßËùÌṩµÄÀͶ¯֧ÅäȨ¡£ @@ -117,7 +117,7 @@ -µÚÁùÕ ÂÛÉÌƷ¼۸ñµÄ×é³ɲ¿·Ö +µÚÁùÕ ÂÛÉÌƷ¼۸ñµÄ×é³ɲ¿·Ö ¡¡¡¡ÔÚ×ʱ¾ÀۻýºÍÍÁµØ˽ÓÐÉÐδ·¢ÉúÒÔǰµijõÆÚҰÂùÉç»ᣬ»ñȡ¸÷ÖÖÎïƷËùÐèҪµÄÀͶ¯Á¿֮¼äµıÈÀý£¬ËƺõÊǸ÷ÖÖÎïƷÏ໥½»»»µÄΨһ±ê׼¡£ÀýÈ磬һ°ãµØ˵£¬á÷ÁÔÃñ×岶ɱº£ÀêһͷËùÐèҪµÄÀͶ¯£¬Èô¶þ±¶Óڲ¶ɱ¹һͷËùÐèҪµÄÀͶ¯£¬ÄÇĩ£¬º£Àêһͷµ±Ȼ»»¹¶þͷ¡£ËùÒԣ¬һ°ãµØ˵£¬¶þÈÕÀͶ¯µÄÉú²úÎïµļÛֵ¶þ±¶ÓÚһÈÕÀͶ¯µÄÉú²úÎÁ½µãÖÓÀͶ¯µÄÉú²úÎïµļÛֵ¶þ±¶ÓÚһµãÖÓÀͶ¯µÄÉú²úÎÕâÊǺÜ×ÔȻµġ£ ¡¡¡¡Èç¹ûһÖÖÀͶ¯±ÈÁíһÖÖÀͶ¯¸üΪ¼è¿࣬¶ÔÓÚÕâ½ϴóµļè¿࣬×ÔȻҪ¼ÓÒԿ¼Âǡ£һµãÖӼè¿à³̶ȽϸߵÄÀͶ¯µÄÉú²úÎÍùÍù¿ɽ»»»Á½µãÖּè¿à³̶Ƚϵ͵ÄÀͶ¯µÄÉú²úÎ ¡¡¡¡Èç¹ûijÖÖÀͶ¯ÐèҪ·Ƿ²µļ¼ÇɺÍÖÇÄܣ¬ÄÇĩΪ×ðÖؾßÓÐÕâÖּ¼ÄܵÄÈˣ¬¶ÔÓÚËûµÄÉú²úÎï×ÔȻҪ¸øÓë½ϸߵļÛֵ£¬¼´³¬¹ýËûÀͶ¯ʱ¼äËùӦµõļÛֵ¡£ÕâÖּ¼ÄܵĻñµã¬³£Ð뾭¹ý¶àÄê¿àÁ·£¬¶ÔÓм¼ÄܵÄÈ˵ÄÉú²úÎï¸øÓè½ϸߵļÛֵ£¬ֻ²»¹ýÊǶԻñµü¼ÄÜËùÐè·ÑȥµÄÀͶ¯Óëʱ¼䣬¸øÒԺÏÀíµı¨³ꡣ½ø²½Éç»ᣬ¶ÔÌرð¼è¿àµĹ¤×÷ºÍÌرðÊìÁ·µÄÀͶ¯£¬һ°㶼ÔÚÀͶ¯¹¤×ÊÉϼÓÒԿ¼Âǡ£ÔڳõÆÚÃÉÃÁÉç»ᣬ¿ÉÄÜҲ×÷¹ýÕâÖֿ¼Âǡ£ @@ -145,7 +145,7 @@ -µÚÆßÕ¡¡ÂÛÉÌƷµÄ×ÔȻ¼۸ñÓëÊг¡¼۸ñ +µÚÆßÕ¡¡ÂÛÉÌƷµÄ×ÔȻ¼۸ñÓëÊг¡¼۸ñ ¡¡¡¡ÔÚÿһ¸öÉç»ἰÆäÁڽüµØÇø£¬¸÷ÖÖÓÃ;µÄÀͶ¯µĹ¤×ÊÒԼ°¸÷ÖÖÓÃ;µÄ×ʱ¾µÄÀûÈ󣬶¼ÓÐһÖÖÆÕͨÂʻòƽ¾ùÂʡ£ÕâÆÕͨÂʣ¬ÏóÎÒÔںóÃæËù˵ÄÇÑù£¬×ÔȻ²¿·ÖÊÜÉç»áµÄһ°ãÇé¿ö£¬¼´ƶ¸»¡¢½ø²½Í˲½»òͣÖÍ״¿öµÄ֧Å䣬²¿·ÖÊܸ÷ÖÖÓÃ;µÄÌØÊâÐÔÖʵÄ֧Å䡣ͬÑù£¬ÔÚÿһ¸öÉç»ἰÆäÁڽüµØÇø£¬µØ×âҲÓÐһ¸öÆÕͨÂʻòƽ¾ùÂʡ£ÕâÆÕͨÂʣ¬ÏóÎÒÔںóÃæËù˵ÄÇÑù£¬ҲÊDz¿·ÖÊÜÍÁµØËùÔڵصÄÉç»ἰÆäÁڽüµØÇøµÄһ°ãÇé¿öµÄ֧Å䣬²¿·ÖÊÜÍÁµصÄÌìȻ·ÊÎÖÓëÈ˹¤¸ÄÁ¼µÄ֧Å䡣 ¡¡¡¡ÕâЩÆÕͨÂʻòƽ¾ùÂʣ¬¿ɳÆΪÄǵط½ÄÇʱºòͨÐеŤ×Ê×ÔȻÂʡ¢ÀûÈó×ÔȻÂʻòµØ×æ×ÔȻÂʡ£һÖÖÉÌƷ¼۸ñ£¬Èç¹û²»¶಻ÉÙǡǡµÈÓÚÉú²ú¡¢ÖÆÔìÕâÉÌƷÄËÖÁÔËËÍÕâÉÌƷµ½Êг¡ËùʹÓõİ´×ÔȻÂÊ֧¸¶µĵØ×⡢¹¤×ʺÍÀûÈó£¬ÕâÉÌƷ¾ͿÉÒÔ˵Êǰ´ËüµÄ×ÔȻ¼۸ñµļ۸ñ³öÊ۵ġ£ ¡¡¡¡ÉÌƷÕâÑù³öÂôµļ۸ñ£¬ǡǡÏ൱ÓÚÆä¼Ûֵ£¬»òÕß˵£¬ǡǡÏ൱ÓڳöÊÛÕâÉÌƷµÄÈËʵ¼ÊÉÏËù»¨µķÑÓá£ÆÕͨËùνÉÌƷԭʼ·ÑÓã¬ËäûÓаüº¬Ôٷ·ÂôÕâÉÌƷµÄÀûÈ󣬵«ÈôÔٷ·ÂôÕ߰´Õղ»Äܵõ½µ±µØһ°ãÀûÈóÂʵļ۸ñ°ÑÕâÉÌƷÂôµô£¬ÄÇËûÏÔȻ¾ͻáÔâÊÜËðʧ¡£ÒòΪ£¬ËûÈô°Ñ×ʱ¾ͶÔÚÆäËû·½Ã棬¾ͿÉÒԵõ½ÄDZÊÀûÈ󡣿öÇң¬ËûµÄÀûÈó¾ÍÊÇËûµÄÊÕÈ룬Ҳ¾ÍÊÇËûÉú»î×ÊÁϵÄÕýµ±×ÊԴ¡£ËûÔÚÖÆÔìÉÌƷ¡¢°ÑËüËÍÍùÊг¡ȥµĹý³ÌÖУ¬Ҫµ渶ÀͶ¯ÕߵŤ×ʻòÉú»î×ÊÁϣ¬ҲҪµ渶Ëû×ÔÉíµÄÉú»î×ÊÁϡ£Ëû×ÔÉíµÄÉú»î×ÊÁϣ¬´óÌåÉÏ˵ÓëËû¿ÉÒԳöÂôÉÌƷָÍûµÄÀûÈóÏ൱¡£Òò´ˣ¬ÉÌƷµijöÂôÈô²»ÄܸøËûÒÔÀûÈó£¬ÄǾ͵ÈÓÚ˵£¬ËûûÓдÓÕâÉÌƷµijöÂôȡ»ØÆäʵ¼ʷÑÓᣠ@@ -184,7 +184,7 @@ -µڰËÕ¡¡ÂÛÀͶ¯¹¤×ÊÀͶ¯Éú²úÎﹹ³ÉÀͶ¯µÄ×ÔȻ±¨³ê»ò×ÔȻ¹¤×ʡ£ +µڰËÕ¡¡ÂÛÀͶ¯¹¤×ÊÀͶ¯Éú²úÎﹹ³ÉÀͶ¯µÄ×ÔȻ±¨³ê»ò×ÔȻ¹¤×ʡ£ ¡¡¡¡ÔÚÍÁµØÉÐδ˽Óжø×ʱ¾ÉÐδÀۻýµÄԭʼÉç»á״̬Ï£¬ÀͶ¯µÄȫ²¿Éú²úÎïÊôÓÚÀͶ¯Õߣ¬¼ÈÎ޵ØÖ÷ҲÎ޹ÍÖ÷À´ͬËû·ÖÏí¡£ ¡¡¡¡ÕâÖÖ״̬Èç¹û¼ÌÐøÏÂȥ£¬ÀͶ¯¹¤×ʽ«Ëæ×ŷֹ¤ËùÒýÆðµÄÀͶ¯Éú²úÁ¦µÄÔö´ó¶øÔö¼ÓÆðÀ´¡£µ«һÇÐÎïƷȴ½«Èս¥µÍÁ®£¬ÒòΪÉú²úËüÃÇËùÐèҪµÄÀͶ¯Á¿±äСÁˡ£ÔÚÕâÖÖ״̬Ï£¬µÈÁ¿ÀͶ¯ËùÉú²úµĸ÷ÖÖÉÌƷ×ÔȻ¿ÉÒԻ¥Ïཻ»»£¬ËùÒԣ¬Ҫ¹ºÂò¸÷ÖÖÉÌƷ£¬ֻÐè½ÏÉÙÊýÁ¿µÄÀͶ¯Éú²úÎ ¡¡¡¡¿ÉÊÇһÇÐÎïƷ£¬¾¡¹Üʵ¼ÊÉϱäµõÍÁ®£¬µ«±íÃæÉÏȴÓÐЩÎïƷµرÈÒÔǰ°º¹󣬻»¾仰˵£¬¿ɽ»»»½϶àÊýÁ¿µÄÆäËû»õÎ¼ٶ¨´ó¶àÊý²úҵµÄÀͶ¯Éú²úÁ¦Ôö¼Óʮ±¶£¬¼´ÏֽñһÌìÀͶ¯µÄÉú²úÁ¿ʮ±¶ÓÚÒÔǰһÌìµÄÀͶ¯£¬¶øijһÖֲúҵµÄÀͶ¯Éú²úÁ¦ȴֻÔö¼Óһ±¶£¬¼´Ôì²úҵÏֽñһÌìÀͶ¯µÄÉú²úÁ¿ֻ¶þ±¶ÓÚÒÔǰһÌìµÄÀͶ¯¡£ÔÚÕⳡºϣ¬Õâ´ó¶àÊý²úҵһÌìÀͶ¯Éú²úÎÈç¹ûÓëÄDzúҵһÌìÀͶ¯Éú²úÎサ»»£¬ÄÇĩǰÕßÒÔԭ¹¤×÷Á¿µÄʮ±¶£¬²»¹ý¹ºÈëºóÕßԭ¹¤×÷Á¿µĶþ±¶¡£Òò´ˣ¬ºóÕߵÄһ¶¨·ÖÁ¿£¬ÀýÈçһ°õ£¬¾ÍËƺõ±ÈÒÔǰ¹óÁËÎ屶¡£µ«ÆäʵȴÊDZÈÒÔǰµÍÁ®Á˶þ·Ö֮һ¡£¹ºÂòÕâһ°õ»õÎïËùÐèµÄÆäËû»õÎïÁ¿ËäÎ屶ÓÚÒÔǰ£¬µ«Éú²ú»ò¹ºÂòÕâһ°õ»õÎïËùÐèµÄÀͶ¯Á¿ȴ²»¹ýµÈÓÚÒÔǰµĶþ·Ö֮һ¡£ËùÒԣ¬Ïֽñ»ñµôËÎï±ÈÒÔǰÈÝÒ×ÁËÁ½±¶¡£ @@ -243,7 +243,7 @@ -µھÅÕ¡¡ÂÛ×ʱ¾ÀûÈó +µھÅÕ¡¡ÂÛ×ʱ¾ÀûÈó ¡¡¡¡×ʱ¾ÀûÈóµÄÔö¼õ£¬ÓëÀͶ¯¹¤×ʵÄÔö¼õ£¬ͬÑùȡ¾öÓÚÉç»á²Ƹ»µÄÔö¼õ¡£µ«²Ƹ»״̬¶ÔÁ½ÕߵÄӰÏìȴ´ó²»Ïàͬ¡£ ¡¡¡¡×ʱ¾µÄÔö¼ӣ¬Ìá¸ßÁ˹¤×ʣ¬Òò¶øÇãÏòÓڼõµÍÀûÈó¡£ÔÚͬһÐÐҵÖУ¬ÈçÓÐÐí¶฻ÉÌͶÏÂÁË×ʱ¾£¬ËûÃǵÄÏ໥¾ºÕù£¬×ÔȻÇãÏòÓڼõµÍÕâһÐÐҵµÄÀûÈó£»ͬһÉç»á¸÷ÖÖÐÐҵµÄ×ʱ¾£¬Èç¹ûȫ¶¼ͬÑùÔö¼ÓÁˣ¬ÄÇĩͬÑùµľºÕù±ضÔËùÓÐÐÐҵ²úÉúͬÑùµĽá¹û¡£ ¡¡¡¡ǰÃæÒѾ­˵¹ý£¬¼´ʹҪȷ¶¨ijһÌض¨µط½ºÍijһÌض¨ʱ¼äµÄÀͶ¯µÄƽ¾ù¹¤×ʣ¬Ҳ²»ÈÝÒס£¶øÇң¬ËùÄÜȷ¶¨µģ¬ֻ²»¹ýÊÇ×îÆÕͨµĹ¤×ʡ£µ«¾Í×ʱ¾ÀûÈó˵£¬¾ÍÁ¬×îÆÕͨµÄÀûÈó£¬ÎÒÃÇҲºÜÉÙÄܹ»ȷ¶¨¡£ÀûÈó¼«Òױ䶯£¬¾­ӪijÌض¨ÐÐҵµÄÈˣ¬δ±ض¼Äܹ»˵³öËûµÄÿÄêƽ¾ùÀûÈóÊǶàÉ١£ËûµÄÀûÈ󣬲»µ«ҪÊÜËûËù¾­ӪµÄÄÇЩÉÌƷ¼۸ñµı䶯µÄӰÏ죬¶øÇÒҪÊÜËûµľºÕùÕߺ͹˿ÍÔËÆøµĺûµ¡¢ÉÌƷÔں£½ÔËÊäÉÏÉõ»òÔڶÑջÄÚËù¿ÉÄÜÔâÓöµÄÐíÐí¶à¶àÒâÍâʹʵÄӰÏ졣ËùÒԣ¬ÀûÈóÂʲ»½öÄêÄê±䶯£¬ÈÕÈձ䶯£¬ÉõÖÁʱʱ¿̶̿¼Ôڱ䶯¡£Ҫȷ¶¨һ¸ö´ó¹úÄڸ÷ÐÐҵƽ¾ùÀûÈ󣬱ØȻ¸ü¼ÓÀ§Äѣ»ÖÁÓÚҪÏ൱׼ȷµØȷ¶¨ÒÔǰ»òÏֽñµÄÀûÈó£¬ÄDZض¨ÊÇÍêȫ²»¿ÉÄܵÄÁˡ£ @@ -271,7 +271,7 @@ -µÚʮÕ¡¡Â۹¤×ÊÓëÀûÈóËæÀͶ¯Óë×ʱ¾ÓÃ;µIJ»ͬ¶ø²»ͬ +µÚʮÕ¡¡Â۹¤×ÊÓëÀûÈóËæÀͶ¯Óë×ʱ¾ÓÃ;µIJ»ͬ¶ø²»ͬ ¡¡¡¡²»ͬµÄÀͶ¯ºÍ×ʱ¾ÓÃ;µÄÀûº¦£¬×ܵÄ˵À´£¬ÔÚͬһµط½Äڣ¬±ØȻÍêȫÏàµȣ¬»򲻶ÏÇ÷ÓÚÏàµȡ£ÔÚͬһµط½Äڣ¬¼ÙÈôijһÓÃ;£¬Ã÷ÏԵرÈÆäËûÓÃ;¸üÓÐÀû»ò¸ü²»Àû£¬¾ͻáÓÐÐí¶àÈËÀëȥ±Ƚϲ»ÀûµÄÓÃ;£¬¶ø¼·½ø±ȽÏÓÐÀûµÄÓÃ;¡£ÕâÑù£¬ÕâÖÖÓÃ;µÄÀûÒ棬²»¾ñãÔٺÍÆäËû¸÷ÖÖÓÃ;Ïàµȡ£ÖÁÉ٣¬Ôڸ÷ÊÂÎﶼÌýÈÎÆä×ÔȻ·¢չµÄÉç»ᣬ¼´ÔÚһÇж¼ÌýÆä×ÔÓɣ¬¸÷¸öÈ˶¼ÄÜ×ÔÓÉѡÔñ×ԼºÈÏΪÊʵ±µÄְҵ£¬²¢ÄÜËæʱ×ÔÓɸÄҵµÄÉç»ᣬÇé¿öȷÊÇÈç´ˡ£¸÷È˵ÄÀûº¦¹Øϵ±ØȻ»á´ÙʹËûѰÇóÓÐÀûµÄÓÃ;£¬±ܿª²»ÀûµÄÓÃ;¡£ ¡¡¡¡³ÏȻ£¬ŷÖ޸÷µصĻõ±ҹ¤×ʼ°»õ±ÒÀûÈ󣬶¼ËæÀͶ¯ºÍ×ʱ¾ÓÃ;µIJ»ͬ¶ø´ó²»Ïàͬ£¬µ«ÕâÖֲ»Ïàͬ£¬²¿·ÖÆðÒòÓڸ÷ÖÖÓÃ;±¾ÉíÇé¿ö£¬ÕâЩÇé¿ö£¬ʵ¼ÊÉϣ¬ÖÁÉÙÔÚһ°ãÈËÏëÏóÉϣ¬¶ÔijЩְҵµÄ΢±¡»õ±ҵÃÀûÓÐËù²¹³¥£¬¶ø¶ÔÁíһЩְҵµÄÓźñ»õ±ҵÃÀûÓÐËùµÖÏú£»²¿·ÖÒòΪŷÖ޸÷¹úµÄÕþ²߶¼²»ÈÃÊÂÎïÍêȫ×ÔÓɵط¢չ¡£ ¡¡¡¡ΪҪ·ֱðÌÖÂÛÄÇЩÇé¿ö¼°ÄÇÖÖÕþ²ߣ¬ÎҰѱ¾Õ·Ö×÷Á½½ڡ£ @@ -394,7 +394,7 @@ -µÚʮһÕ¡¡Â۵Ø×â +µÚʮһÕ¡¡Â۵Ø×â ¡¡¡¡×÷ΪʹÓÃÍÁµصĴú¼۵ĵØ×⣬×ÔȻÊÇ×âµØÈ˰´ÕÕÍÁµØʵ¼ÊÇé״Ëù֧¸øµÄ×î¸߼۸ñ¡£Ôھö¶¨×âԼÌõ¼þʱ£¬µØÖ÷¶¼É跨ʹ×âµØÈËËùµõÄÍÁµØÉú²úÎï·ݶ½ö×㲹³¥ËûÓÃÒÔÌṩÖÖ×ӡ¢֧¸¶¹¤×ʡ¢¹ºÖúÍά³ָûÐóÓëÆäËûũ¾ߵÄũҵ×ʱ¾£¬²¢Ìṩµ±µØũҵ×ʱ¾µÄÆÕͨÀûÈó¡£ÕâһÊý¶ÏÔȻÊÇ×âµØÈËÔڲ»¿÷±¾µÄÌõ¼þÏÂËùԸÒâ½ÓÊܵÄ×îС·ݶ¶øµØÖ÷¾ö²»»á¶àÁô¸øËû¡£Éú²úÎïÖзָø×âµØÈ˵ÄÄÇһ²¿·֣¬ҪÊǶàÓÚÕâһÊý¶»»ÑÔ֮£¬Éú²úÎïÖзָø×âµØÈËÄÇһ²¿·ֵļ۸ñ£¬ҪÊǶàÓÚÕâһÊý¶îµļ۸񣬵ØÖ÷×ÔȻҪÉ跨°ѳ¬¹ý¶îÁôΪ¼ºÓУ¬×÷ΪµØ×⡣Òò´ˣ¬µØ×âÏÔȻÊÇ×âµØÈ˰´ÕÕÍÁµØʵ¼ÊÇé¿öËùÄܽÉÄɵÄ×î¸߶³ÏȻ£¬ÓÐʱÓÉÓڴæÐĿí´󣬸ü¾­³£ÊÇÓÉÓÚÎÞ֪£¬µØÖ÷½ÓÊܱÈÕâһÊý¶îÂԵ͵ĵØ×⣻ͬÑù£¬ÓÐʱҲÓÉÓÚÎÞ֪£¨µ«±ȽÏÉټû£©£¬×âµØÈ˽ÉÄɱÈÕâһÊý¶îÂԸߵĵØ×⣬¼´¸ÊԸ³ÐÊܱȵ±µØũҵ×ʱ¾ÆÕͨÀûÈóÂԵ͵ÄÀûÈ󡣵«ÕâһÊý¶ÈԿÉÊÓΪÍÁµصÄ×ÔȻµØ×⣬¶øËùν×ÔȻµØ×⣬µ±ȻÊǴ󲿷ֳö×âÍÁµØӦµõĵØ×⡣ ¡¡¡¡ҲÐíÓÐÈËÈÏΪ£¬ÍÁµصĵØ×⣬²»ÍâÊǵØÖ÷ÓÃÀ´¸ÄÁ¼ÍÁµصÄ×ʱ¾µĺÏÀíÀûÈó»òÀûϢ¡£ÎÞÒɵأ¬ÓÐЩʱºò£¬Çé¿ö¿Éֻ˵ÔÚһ¶¨³̶ÈÉÏÊÇÕâÑù£¬µ«²»¿ÉÒÔ˵Ôںܴó³̶ÈÉÏÊÇÕâÑù¡£¶ÔÓÚδ¾­¸ÄÁ¼µÄÍÁµأ¬µØÖ÷ҲҪÇóµØ×⣬¶øËùν¸ÄÁ¼·ÑÓõÄÀûϢ»òÀûÈó£¬һ°ãֻÊÇÕâԭÓеØ×âµĸ½¼Ӷ¶øÇҸÄÁ¼ÍÁµأ¬δ±ض¼ÓɵØÖ÷³ö×ʱ¾£¬ÓÐʱÊÇÓÉ×âµØÈ˳ö×ʱ¾¡£²»¹ý£¬ÔÚÐø¶©×âԼʱ£¬µØÖ÷ͨ³£ҪÇóÔö¼ӵØ×⣬ºÃÏó¸ÄÁ¼ÊÇÓÉËû³ö×ʱ¾¸ãµġ£ ¡¡¡¡ÓÐʱ£¬µØÖ÷¶ÔÓÚÍêȫ²»ÄÜÓÉÈËÁ¦¸ÄÁ¼µÄ×ÔȻÎҲˣÇóµØ×⡣ÀýÈ磬¿˶ûÆÕÊÇһÖֺ£²ݡ£ÕâÖֺ£²Ýһ¾­ȼÉգ¬¼´¿ɳÉΪÖÆÔ첣Á§ºͷÊÔíÒԼ°ÆäËûÓÃ;ËùÐèҪµļïÑΡ£²»Áе߼¸¸öµط½£¬ÓÈÆäÊÇËոñÀ¼£¬¶¼Éú²úÕâÖֺ£²ݡ£ËüÉúÓڸ߳±ÄܴﵽµÄÑÒʯÉϣ¬ÕâЩÑÒʯÿÈձ»º£³±ÑÍûÁ½´Σ¬ËùÒԣ¬ÉúÔÚÕâЩÑÒʯÉϵĺ£²ݣ¬¾ø²»ÊÇͨ¹ýÈËÁ¦¶øÔö¶àµġ£µ«Êǣ¬¶ÔÓÚÒÔÉú²úÕâÖֺ£²ݵĺ£°¶Ϊ½çµÄËùÓеأ¬µØÖ÷ҲҪÇóµØ×⣬ÏóËûÃǶԹÈÌïҪÇóµØ×âһÑù¡£ @@ -405,7 +405,7 @@ ¡¡¡¡ËùÒÔӦµ±עÒ⣬µØ×â³ÉΪÉÌƷ¼۸񹹳ɲ¿·ֵķ½ʽÊǺ͹¤×ÊÓëÀûÈó²»ͬµġ£¹¤×ʺÍÀûÈóµĸߵͣ¬ÊǼ۸ñ¸ߵ͵ÄԭÒ򣬶øµØ×âµĸߵͣ¬ȴÊǼ۸ñ¸ߵ͵Ľá¹û¡£ÉÌƷµļ۸ñµÄÓиßÓеÍÊÇÒòΪÕâһÉÌƷÉÏÊÐËùÐë֧¸¶µĹ¤×ÊÓëÀûÈóÓиßÓе͡£µ«ÕâÉÌƷÄÜÌṩ¸ߵØ×⣬ÄÜÌṩµ͵Ø×⣬»ò²»ÄÜÌṩµØ×⣬ȴÊÇÒòΪÕâÉÌƷ¼۸ñÓиßÓеͣ¬»»ÑÔ֮£¬ÒòΪÕâÉÌƷ¼۸ñ£¬ÊǴó´󳬹ý»òÉÔÉԳ¬¹ý×㹻֧¸¶¹¤·Ѽ°ÀûÈóµÄÊý¶»òÊǽö¹»֧¸¶¹¤×ʼ°ÀûÈó¡£ ¡¡¡¡ÎҰѱ¾Õ·ÖΪÒÔÏÂÈý½ڣ¬רÃÅÌÖÂۣºµÚһ£¬×ÜÄÜÌṩµØ×âµÄÍÁµØÉú²úÎµڶþ£¬ÓÐʱÄÜÌṩÓÐʱ²»ÄÜÌṩµØ×âµÄÍÁµØÉú²úÎµÚÈý£¬ÕâÁ½ÖÖԭÉú²úÎ±˴˻¥Ïà±ȽϻòºÍÖÆÔìƷ±Ƚϣ¬Ôڲ»ͬ¸ÄÁ¼½׶Σ¬Ëù×ÔȻ²úÉúµÄÏà¶ԼÛֵÉϵı䶯¡£ -µÚһ½Ú ÂÛ×ÜÄÜÌṩµØ×âµÄÍÁµØÉú²úÎï +µÚһ½Ú ÂÛ×ÜÄÜÌṩµØ×âµÄÍÁµØÉú²úÎï ¡¡¡¡ÏóһÇÐÆäËû¶¯ÎïһÑù£¬ÈËÀàµÄÔöֳ£¬×ÔȻ»áºÍÆäÉú»î×ÊÁÏÏà³ơ£ËùÒԣ¬¶ÔÓÚʳÎ×ÜÊǻò¶à»òÉٵØÓÐÐèҪ¡£ʳÎï×ÜÄܹºÂò»ò֧Åä»ò¶à»òÉٵÄÀͶ¯Á¿£¬¶øԸΪ»ñµÃʳÎï¶ø´ÓÊÂÀÍ×÷µÄÈˣ¬×ÜÊǿÉÒÔÕҵõ½µġ£³ÏȻ£¬¶ÔÀͶ¯֧¸ø¸߹¤×ʵĽá¹û£¬ʳÎïÄܹºµõÄÀͶ¯Á¿ËäÓ봦ÀíµÃ×¼ÃʱËùÄÜά³ֵÄÀͶ¯Á¿δ±ØÏàµȣ¬µ«ʳÎï×ÜÄܰ´ÕÕÁڽüһ´øÀͶ¯ÕߵÄÆÕͨÉú»î±ê׼ά³Öһ¶¨ÊýÁ¿µÄÀͶ¯¡£ ¡¡¡¡µ«Êǣ¬¾ͼ¸ºõÈκÎλÖõÄÍÁµØ˵£¬ÆäËù²úʳÎ³ý×㹻ά³ÖËüÉÏÊÐËùÐèµÄÀͶ¯Í⣬»¹ÓÐʣÓࡣ¶øÕâʣÓ࣬Óֲ»½ö½ö×㹻²¹³¥¹ÍÓÃÀͶ¯Ëùµ渶µÄ×ʱ¾¼°ÆäÀûÈ󣬻¹ÁôÓÐ×÷ΪµØÖ÷µØ×âµÄÓà¶ ¡¡¡¡ŲÍþ¼°ËոñÀ¼µĻÄÁ¹¿õҰ£¬²úÓÐһÖÖÄÁ²ݡ£ÒÔÕâÄÁ²ÝËÇÑøÉüÐó£¬ËùµõÄÈé֭Ó뷱ֳ³öÀ´µÄÉüÐ󣬳ýÁË×㹻ά³ÖÄÁÐóËùÐèҪµÄһÇÐÀͶ¯£¬²¢֧¸øÄÁÐóÕ߻òÐóȺËùÓÐÈ˵ÄÆÕͨÀûÈóÍ⣬»¹ÓÐС¶îʣÓ࣬×÷ΪµØÖ÷µĵØ×⡣ÄÁ³¡µØ×⣬Ëæ×ÅÄÁ³¡Ìõ¼þµÄÓÅÁ¼³̶ȶøÔö¼ӡ£ÓÅÁ¼ÍÁµأ¬²»µ«±ÈͬÃæ»ýµÄÁӵÈÍÁµأ¬ÄÜά³ָü¶àµÄÉüÐ󣬶øÇÒÓÉÓÚÉüÐ󼯾ÛÓڽÏСµØÇø£¬ËÇÑøÉϺÍÊջñÉϣ¬ÐèҪ½ÏÉٵÄÀͶ¯¡£ÕâÑù£¬µØÖ÷¾ʹÓÉú²úÎïÊýÁ¿µÄÔö¼ÓÒԼ°ά³ַÑÓõļõÉÙÕâÁ½·½Ãæµõ½ÀûÒ档 @@ -448,7 +448,7 @@ ¡¡¡¡ÎÒÌý˵£¬À¼¿ªÏÄijЩµط½ÈÏΪ£¬ÀͶ¯ÈËÃñ³ÔÑàÂóÃæ°ü£¬±ȳÔСÂóÃæ°ü£¬¶Ç×Ӹü±¥¡£¶øÔÚËոñÀ¼£¬ÎÒҲÌýµ½ͬÑùµĻ°¡£ÎҶÔÓڴËÖִ«Îţ¬×ܾõÓеãÒÉÎʡ£³ÔÑàÂóÃæ°üµÄËոñÀ¼ÆÕͨÈËÃñ£¬һ°ãµØ˵£¬²»Ïó³ÔСÂóÃæ°üµÄͬһ½׼¶Ӣ¸ñÀ¼ÈËÃñÄÇôǿ׳£¬ÄÇôÇåÐ㣻ËûÃǼȲ»ÏóӢ¸ñÀ¼ÈËÄÇôÆ𾢵ع¤×÷£¬Ҳ²»ÏóӢ¸ñÀ¼ÈËÄÇô½¡¿µ¡£ÓÉÓÚÔÚÕâÁ½µØÉÏÁ÷ÈËÖмäûÓÐÕâÖֲîÒ죬¾­ÑéËƺõ¸æËßÎÒÃǣ¬ËոñÀ¼ÆÕͨÈËÃñµÄʳÎûÓÐӢ¸ñÀ¼ÆÕͨÈËÃñµÄʳÎïÄÇôÊʺÏÓÚÈËÀàµÄÌåÖʡ£µ«¾ÍÂíÁåÊí˵£¬ÇéÐÎȴÍêȫÁ½Ñù¡£Â׶صĽη򡢽ŷòºÍú̿Ìô·ò£¬ÒԼ°ÄÇЩ¿¿ÂôÒùΪÉúµIJ»ÐҸ¾Ů£¨ҲÐíÊÇӢ¹úÁìÍÁÖÐ×îǿ׳ÄÐ×ӺÍ×îÃÀÀöŮ×ӣ©£¬¾Ý˵£¬ÕâЩÈ˵Ĵ󲿷֣¬À´×Ôһ°ãֻÂíÁåÊíΪʳÎïµİ®¶ûÀ¼×îϼ¶ÈËÃñ¡£ÂíÁåÊíÌṩ×îÃ÷ȷµÄ֤¾ݣ¬֤Ã÷Ëüº¬ÓÐӪÑøËأ¬¶øÇÒÌرðÊʺÏÓÚÈËÀàµÄÌåÖʡ£ ¡¡¡¡ÂíÁåÊíºÜÄѱ£´æһÄ꣬¶øÇҲ»¿ÉÄÜÏó¹ÈÎïÄÇÑùÖü²ضþÈýÄꡣ²»ÄÜÔڸ¯ÀÃÒÔǰÂô³öµĿ־壬ʹÈ˲»ÏëÔÔÖÖÂíÁåÊí£¬¶øÔÚÈκδó¹ú£¬ÂíÁåÊí²»ÏóÃæ°üÄÇÑù£¬³ÉΪ¸÷½׼¶ÈËÃñµÄÖ÷ˣֲÎïÐÔÁ¸ʳ£¬ÕâҲÐíÊÇһ¸öÖ÷ҪԭÒò¡£ -µڶþ½ÚÂÛÓÐʱÌṩÓÐʱ²»ÌṩµØ×âµÄÍÁµØÉú²úÎï +µڶþ½ÚÂÛÓÐʱÌṩÓÐʱ²»ÌṩµØ×âµÄÍÁµØÉú²úÎï ¡¡¡¡Ôڸ÷ÖÖÍÁµØÉú²úÎïÖУ¬ËƺõֻÓÐÈËÀàʳÎïÊDZØȻÌṩµØ×âµģ»ÆäËûÉú²úÎËæ×Ų»ͬÇé¿ö£¬ÓÐʱÌṩµØ×⣬ÓÐʱ²»ÌṩµØ×⡣ ¡¡¡¡ÈËÀà×îÐèҪµĶ«Î÷£¬³ýÁËʳÎ¾ÍÊÇÒ·þ¼°סլ¡£ ¡¡¡¡ÔÚԭʼ×ÔȻ״̬Ï£¬ÍÁµØÔÚÒ·þ¼°סլ²ÄÁϷ½ÃæËùÄܹ©¸øµÄÈËÊý£¬±ÈÔÚʳÎ﷽ÃæËùÄܹ©¸øµÄÈËÊý¶àµöࡣµ«Ôڽø²½״̬Ï£¬ÍÁµØÔÚǰһ·½ÃæËùÄܹ©¸øµÄÈËÊý£¬ÓÐʱȴ±ÈÔںóһ·½ÃæËùÄܹ©¸øµÄÈËÊýÉ٣¬ÖÁÉ٣¬¾ÍÈËÃÇÐèҪÒ·þסլ²ÄÁϺÍԸÒâ֧¸¶´ú¼ÛÕâ¶þ·½Ãæ˵£¬ÊÇÈç´ˡ£ËùÒԣ¬ÔÚԭʼ×ÔȻ״̬Ï£¬Ò·þºÍסլ²ÄÁÏ×ÜÊǹýʣ£¬Òò¶øûÓжàÉټÛֵ£¬Éõ»òÍêȫûÓмÛֵ¡£Ôڽø²½״̬Ï£¬´˵ȲÄÁÏÍùÍùȱ·¦£¬Æä¼ÛֵÓÚÊÇÔö´ó¡£ÔÚǰһ³¡ºϣ¬´󲿷ÖÒÂס²ÄÁϣ¬ÓÉÓÚÎÞÓñ»Åׯú£¬¶øʹÓò¿·ֵļ۸񣬿ÉÒÔ˵ֻµÈÓڸÄÔìÕâЩ²ÄÁÏʹÆäÊÊÓÚÈËÓÃËù»¨µÄÀͶ¯Óë·ÑÓá£Òò´ˣ¬¶ÔÓڵØÖ÷£¬×Բ»ÄÜÌṩµØ×⡣Ôںóһ³¡ºϣ¬ÕâЩ²ÄÁÏȫ±»ʹÓ㬶øÇÒÍùÍùÇó¹ýÓڹ©¡£ÓÚÊǣ¬¶ÔÓڴ˵ȲÄÁϵÄÈκβ¿·֣¬×ÜÓÐÈËԸÒâÒԳ¬¹ýÆä²úÖƺÍÉÏÊеķÑÓõļ۸ñÀ´¹ºÂò¡£ËùÒԣ¬´˵ȲÄÁϵļ۸񣬶ԵØÖ÷×ܿÉÌṩÈô¸ɵØ×⡣ @@ -484,7 +484,7 @@ ¡¡¡¡¹ó½ðÊô»ò±¦ʯ×î·ḻµĿóɽ£¬¶Ô×ÓÊÀ½ç²Ƹ»£¬²»ÄÜÓжà´óµÄÔö¼ӡ£ÒòΪÕâÀà²úƷµļÛֵ£¬Ö÷ҪÀ´×ÔÆäϡÉ١£ҪÊÇÕâÀà²úƷ¶àÁˣ¬Æä¼Ûֵ±ØȻÏÂÂ䣬Õâʱ£¬½ðÒø²;ߣ¬¼°ÆäËûÒ·þ¼ҾߵÄÉݻªװÊÎÎ¾ÍÄÜÒԽÏǰÉٵÄÀͶ¯Á¿»òÉÌƷÁ¿ÂòÈ롣Õâ¾ÍÊÇÊÀ½çÄܵÃ×ԽðÒø±¦ʯ֮·ḻµÄΨһÀûÒ档 ¡¡¡¡¾ÍÍÁµزƲú˵£¬Çé¿öȴ²»Èç´ˡ£ÍÁµصÄÉú²úÎPµØ×âÕâÁ½ÕߵļÛֵ£¬²»ºÍÆäÏà¶Բú³öÁ¦³ɱÈÀý£¬¶øºÍÆä¾ø¶Բú³öÁ¦³ɱÈÀý¡£Éú²úһ¶¨·ÖÁ¿ÒÂʳסµÄÍÁµأ¬×ÜÄܹ©¸øһ¶¨ÈËÊýµÄÒÂʳס£¬¶øÇң¬²»ÂÛËûÖ÷ÏíÓеıÈÂÊÈçºΣ¬Ëû×ÜÄÜÒò´Ë֧ÅäÏ൱µÄÀͶ¯£¬ºÍ֧ÅäÕâÀͶ¯Ëù¸øËûÌṩµÄÉÌƷ¡£×îƶñ¤ÍÁµصļÛֵ£¬²¢²»Òò½üÁÚÓÐ×î·ÊÎÖÍÁµضø¼õÉ١£·´֮£¬Æä¼Ûֵȴ³£Òò´˶øÔö¼ӡ£·ÊÎÖÍÁµØËùÑø»îµÄÖڶàµÄÈ˿ڣ¬¸øƶñ¤ÍÁµصÄÐí¶àÉú²úÎïÌṩÁËÊг¡£¬¶øƶñ¤ÍÁµصÄÉú²úÎÔÚÄÜÒÔ×Լº²úÎïά³Ö×ԼºµÄÈËÃñÖУ¬ԭÊÇÕҲ»µ½Êг¡µġ£ ¡¡¡¡ʲô¶«Î÷Ôö¼ÓÁËÉú²úʳÎïµÄÍÁµصIJú³öÁ¦£¬Ëü¾Ͳ»½öÔö¼ÓÁ˱»¸ÄÁ¼ÍÁµصļÛֵ£¬¶øÇÒҲ¸øÐí¶àÆäËûÍÁµصÄÉú²úÎﴴÔìÁËеÄÐèÇ󣬴ӶøʹÕâЩÍÁµصļÛֵҲÔö¼ÓÁˡ£ÓÉÓÚÍÁµصĸÄÁ¼£¬Ðí¶àÈ˶¼ÓÐ×ԼºÏû·Ѳ»Á˵ÄʣÓàʳÎÒò¶ø¶Թó½ðÊôºͱ¦ʯÓÐÁËÐèÇ󣬶ÔÓÚÒ·þ¡¢סլ¡¢¼ҾߺÍÉ豸·½ÃæÆäËûһÇбãÀûƷºÍװÊÎƷ£¬ҲÓÐÁËÐèÇó¡£ʳÎﲻ½ö³ÉΪÊÀ½çÉϲƸ»µÄÖ÷Ҫ²¿·֣¬¶øÇÒʹÐí¶àÆäËû¸÷Öֲƻõ¾ßÓÐÖ÷Ҫ¼Ûֵµģ¬ÄËÊÇʳÎïµķḻ¡£µ±¹ŰͺÍʥ¶àÃ÷¸÷¸ձ»Î÷°àÑÀÈ˷¢ÏÖʱ£¬ÄDZߵÄÇî¿à¾ÓÃ񣬳£ÒÔС½ð¿é×÷ΪͷÊκͷþÊΡ£ËûÃǶÔÕâЩ½ð¿éµÄÆÀ¼ۣ¬ËƺõºÍÎÒÃǶÔÄÇЩ±Èһ°ãÂÔÃÀµÄС¶ìÂÑʯµÄÆÀ¼ÛÏàͬ£¬¾ÍÊÇ˵£¬ֵµÃʰȡ£¬µ«ÓÐÈËҪʱ£¬ȴ²»ֵµþܾø¡£ËûÃǶÔп͵Úһ´ÎÇëÔù½ð¿飬Î޲»Á¢¼´ÔùÓ룬Ëƺõ²¢²»ÈÏΪÔùËÍÁËпͷdz£Õä¹óµÄÀñÎËûÃǿ´µ½Î÷°àÑÀÈËÄÇôÈÈÇеØÏë»ñµýð¿飬¸е½¾ªÑȡ£ËûÃÇûÓÐÏ뵽ÊÀ½çÉϾ¹ÓÐÕâÑùµĹú¼ң¬ËüµÄÐí¶àÈËÃ񣬶ÔÓÚËûÃÇÀÏÊÇȱ·¦µÄʳÎïÓÐÄÇô´óµÄʣÓàÁ¿£¬ԸÒâÒÔ×㹻¹©Ñøȫ¼Һü¸ÄêµĴóÁ¿ʳÎÀ´½»»»СÁ¿»ᷢÁÁµÄÍæÒâ¶ù¡£Èç¹ûËûÃÇÄܹ»Àí½â´ËÖÐÀíÓɣ¬Î÷°àÑÀÈ˵ĻƽðÈȣ¬¾Ͳ»»áʹËûÃǾªÒìÁˡ£ -µÚÈý½ÚÂÛ×ÜÄÜÌṩµØ×âµÄÉú²úÎïÓëÓÐʱÌṩÓÐʱ²»ÌṩµØ×âµÄÉú²úÎï +µÚÈý½ÚÂÛ×ÜÄÜÌṩµØ×âµÄÉú²úÎïÓëÓÐʱÌṩÓÐʱ²»ÌṩµØ×âµÄÉú²úÎï ¡¡¡¡Õâ¶þÕ߼Ûֵ±ÈÀýµı䶯 ¡¡¡¡ ¸ÄÁ¼º͸û×÷ÈÕÒæÔö´ó£¬Á¸ʳÈÕÒæ·ḻ£¬Õâ±ØȻ»áÔö¼ӶÔһÇÐÄܹ©ʵÓü°װÊÎÓõķÇʳÎïµÄÍÁµØÉú²úÎïµÄÐèÇó¡£ËùÒԣ¬ÔڸÄÁ¼½øչ¹ý³ÌÖУ¬¿ÉԤÆÚÕâÁ½ÖÖÉú²úÎïµÄÏà¶ԼÛֵֻÓÐһÖֱ䶯¡£¾ÍÊÇ˵£¬ºÍ×ÜÄÜÌṩµØ×âµÄÉú²úÎïµļÛֵÏà±ȣ¬ÓÐʱÌṩµØ×âÓÐʱ²»ÌṩµØ×âµÄÉú²úÎïµļÛֵ²»¶ϵØÔö³¤¡£Ëæ×ż¼ÊõºͲúҵµķ¢չ£¬Ò·þ¾Óס²ÄÁϡ¢µØÖÐÓÐÓû¯ʯºͿóÎÒÔÖÁ¹ó½ðÊôºͱ¦ʯµÄÐèÇóÌ⽥Ôö¼ӡ£ËüÃÇËùÄܻ»µõÄʳÎïÖð½¥Ôö¶࣬»»ÑÔ֮£¬Æä¼۸ñÖð½¥Ôö¸ߡ£Òò´ˣ¬ÒÔÉÏËù˵ÊǴ󲿷ÖÊÂÎïÔڴó¶àÊý³¡ºϵÄÇé¿ö£¬ҪÊÇûÓÐÌØÊâʹÊʹÕâЩÎïƷÖÐijЩÎïƷµĹ©¸øÔö¼ӵôó´󳬹ýÆäÐèÇóµĻ°£¬ÄǾÍÊÇÕâЩÎïƷÔÚһÇг¡ºϵÄÇé¿ö¡£ @@ -495,9 +495,9 @@ ¡¡¡¡Áíһ·½Ã棬¼ÙÈôÕâ½ðÊôµĹ©¸øºÍÆäÐèÇ󼸺õ°´ͬһ±ÈÀýÔö¼ӣ¬ÄÇĩÕâ½ðÊô¾ÍÄܼÌÐø¹ºÂò»򽻻»¼¸ºõÏàͬÊýÁ¿µĹÈÎ¾¡¹ÜÓÐÁËһÇиÄÁ¼£¬¹ÈÎïȴ¼ÌÐø±£³Ö׿¸ºõÏàͬµÄƽ¾ù»õ±Ҽ۸ñ¡£ ¡¡¡¡ÕâÈýÕßËƺõ°üÀ¨ÁËÔڸÄÁ¼½ø³ÌÖÐËùÄܷ¢ÉúµÄÊÂÇéµÄһÇпÉÄܵÄ×éºϡ£Èç¹ûÎÒÃÇÒԷ¨¹úºÍӢ¹ú·¢ÉúµÄÊÂʵÀ´×÷Åжϣ¬ÄÇĩÔڹýȥËÄÊÀ¼ÍÖУ¬ÕâÈýÖֲ»ͬµÄ×éºÏËƺõ¶¼ÔÚŷÖÞÊг¡ÉϷ¢Éú¹ý£¬¶ø·¢ÉúµÄ˳ÐòºÍÎÒÕâÀïËù˵µĴóԼÏàͬ¡£ -˳±ã̸̸ǰËÄÊÀ¼ÍÒø¼۵ı䶯 +˳±ã̸̸ǰËÄÊÀ¼ÍÒø¼۵ı䶯 -µÚһÆÚ +µÚһÆÚ ¡¡¡¡ÔÚ1350Ä꼰ǰ´ËÊýÄê¼䣬Ӣ¸ñÀ¼СÂóһ¿äÌصÄƽ¾ù¼۸񣬴óԼ¶¼±»¹À¼ÆΪ²»µÍÓÚÌպâÒøËİ»˹£¬ÌպâÒøËİ»˹ԼºÏÏÖÁîӢ±ҶþʮÏÈÁÒԺó£¬ËƺõÖ𽥵ÍÂ䵽¶þ°»˹£¬ԼºÏÏֽñӢ±ÒʮÏÈÁÎÒÃǾõµã¬Õâһ¿äÌØʮÏÈÁîµļ۸ñ£¬ÊÇʮÁùÊÀ¼ͳõҶ¹À¶¨µÄСÂó¼۸ñ£¬ֱµ½1570Ä꣬»¹ΪÕâô¶ࡣ ¡¡¡¡1305Ä꣬¼´°®µ»ªÈýÊÀµڶþʮÎåÄ꣬Öƶ¨ÁËËùνÀͶ¯·¨¹档Õⷨ¹æÔÚǰÑÔÖдó´ó·ÇÄÑӶ¹¤µĺá°ԣ¬˵ËûÃDz»ӦҪÇó¹ÍÖ÷Ôö¼ӹ¤×ʡ£ËùÒԣ¬Õⷨ¹æ¹涨£ºһÇÐӶ¹¤¼°ÀͶ¯Õߣ¬´˺óӦÂú×ãÓڰ®µ»ªÈýÊÀµڶþʮÄ꼰ǰ´ËËÄÄêͨ³£ÁìµõŤ×ʼ°Å䏸£¨Å䏸һ´ʣ¬µ±ʱº¬ÓÐÒ·þ¼°ʳÁÏÕâ¶þÕߣ©£¬Òò´ËËûÃÇËùµõÄÅ䏸СÂó£¬ÎÞÂۺεأ¬ֻÒÔÿÆÑʽ¶úʮ±ãʿ¼ÆË㣬¶øÇң¬ÕâÅ䏸£¬ÒÔСÂó»ò»õ±ҽ»¸¶£¬ÓÖÐëÌý¹ÍÖ÷ѡÔñ¡£ÿÆÑʽ¶úʮ±ãʿ£¬Êǰ®µ»ªÈýÊÀµڶþʮÎåÄ꼫ÆÕͨµÄСÂó¼۸ñ£¬ÒòΪËüÐèҪÓÉÌØÊⷨ»áÀ´ÆÈʹӶ¹¤½ÓÊܣ¬ÒԴúÌæͨ³£µÄÅ䏸¿ÚÁ¸£¬¶øÕâ¼۸ñ£¬Ҳ±»ÈÏΪÊÇǰ´ËʮÄ꼴·¨ÁîËùָµİ®µ»ªÈýÊÀµÚʮÁùÄêµĵÍÁ®¼۸񡣵«°®µ»ªÈýÊÀµÚʮÁùÄ꣬ʮ±ãʿº¬ÓдóԼÌպâÒø°밻˹£¬´óԼµÈÓÚÏÖÁîӢ±Ұë¿ËÀɡ£ËùÒԣ¬Ó뵱ʱ»õ±ÒÁùÏÈÁî°˱ãʿÏ൱¡¢ÓÖÓë½ñÈջõ±Ҷþʮ¹âÁîÏ൱µÄÌպâÒøËİ»˹£¬±ض¨Ôڵ±ʱ±»ÈÏΪÊÇСÂóһ¿äÌؼ´°ËÆÑʽ¶úµÄÆÕͨ¼۸ñ¡£ ¡¡¡¡¹ØÓڱ»ÈÏΪÊǵ±ʱ¹ÈÎïµÄÆÕͨ¼۸ñ£¬ÕⷨÁîËùÌṩµÄ֤Ã÷£¬ÎÞÒɵرÈÀúʷ¼Ҽ°ÆäËûÖøÊö¼ҼǼµÄijЩÄê¶ȵĹȼۺõö࣬ÒòΪËûÃÇËù¼ǣ¬²àÖØÒ쳣¸߰º»òÒ쳣µÍÁ®µļ۸ñ£¬ËùÒÔÏëÒÀ´ËÅжϵ±ʱµÄÆÕͨ¼۸ñ£¬ʵ²»ÈÝÒס£¼Ó֮£¬ÎÒÃǻ¹ÓбðÖÖÀíÓɿÉÏàÐţ¬ʮËÄÊÀ¼ͳõ¼°ÒÔǰÊýÄêСÂóµÄÆÕͨ¼۸񣬲»ÏÂÓÚÿ¿äÌØËİ»˹£¬¶øÆäËû¸÷ÖֹÈÎï¼۸ñ£¬ҲÒÀ´ËΪ׼¡£ @@ -538,14 +538,14 @@ ¡¡¡¡ÔÚһЩºܸ»ԣµÄÉÌҵ¹ú£¬ÈçºÉÀ¼¼°ÈÈÄÇÑǵØÇø£¬Æä¹ÈÎï¼۸ñµĸßÓë´ó¶¼ÊйÈÎï¼۸ñµĸßÊôÓÚͬһԭÒò¡£ËüÃDz»ÄÜÉú²ú×㹻ά³ÖÆä¾ÓÃñµĹÈÎËüÃǸ»Óڼ¼Êõ¹¤È˺ÍÖÆÔ칤È˵ÄÇÚÃãÓëÊìÁ·£¬¸»Óڼò»¯ÀͶ¯ºͽÚʡÀͶ¯µĸ÷ÖֻúÆ÷£¬¸»ÓÚÔËÊ䴬²°£¬¶øÇҸ»ÓÚÆäËûһÇÐÔËÊ乤¾ߺÍÉÌҵÊֶΡ£Ȼ¶ø£¬ËüÃÇȱ·¦¹ÈÎËüÃÇËùÐèҪµĹÈÎï±ØÐë´ÓңԶ¹ú¼ÒÊäÈ룬ËùÒÔÆä¼۸ñ£¬Ð븽¼Ó×ÔÕâЩ¹ú¼ÒÔËÀ´µķÑÓᣰѰ×ÒøÔËÍù°¢ķ˹Ìص¤£¬ËùÐèҪµÄÀͶ¯Á¿²¢²»±ÈÔËÍùµ«ÔóÉ٣¬µ«°ѹÈÎïÔËÍù°¢ķ˹Ìص¤£¬ȴÐèҪ¶àµöàµÄÀͶ¯Á¿¡£×Ü֮£¬°×ÒøµÄÕæʵ³ɱ¾£¬ÔÚÁ½µرض¨¼¸ºõÏàͬ£¬¹ÈÎïµÄÕæʵ³ɱ¾£¬ÔÚÁ½µØȴ´óÏàÐüÊ⡣ÏÖÔڼٶ¨ºÉÀ¼»òÈÈÄÇÑǾÓÃñÊýĿÕվɣ¬¶øËüÃǵÄÕæʵ¸»ԣ³̶ȼõµÍÁˣ¬´ÓңԶ¹ú¼ÒÊäÈë¹ÈÎïµÄÄÜÁ¦Ҳ¼õµÍÁˣ¬ÄÇĩ£¬°éËæ×ÅÕâÖÖ˥Í˶øÀ´µıØȻÊÇÒøÁ¿µļõÉ٣¬ÒøÁ¿µļõÉٻòÕßÊÇ˥Í˵ÄԭÒ򣬻òÕßÊÇ˥Í˵Ľá¹û£¬µ«¹ÈÎïµļ۸񣬲»µ«²»»áËæÒøÁ¿µļõÉٶøÏ½µ£¬·´¶ø»áÉÏÉýµ½¼¢Äêµļ۸񡣵±ÎÒÃÇȱÉٱØÐèƷʱ¼õÃDZض¨·ÅÆúһÇв»±ØҪÎïƷ¡£²»±ØҪÎïƷµļÛֵ£¬ÔÚƶÇîÀ§¿àʱÆÚϽµ£¬ÕýÈçËüÔڸ»ԣ·±ÈÙʱÆÚÉÏÉýÄÇÑù¡£±ØÐèƷµÄÇé¿öÓë´˲»ͬ¡£±ØÐèƷµÄÕæʵ¼۸񣬼´ËüÃÇÄÜ֧Åä»ò¹ºÂòµÄÀͶ¯Á¿£¬ÔÚƶÇîÀ§¿àʱÆÚÉÏÉý£¬Ôڸ»ԣ·±ÈÙʱÆÚϽµ¡£¸»ԣ·±ÈÙʱÆڣ¬×ÜÊÇÎï×ʷdz£·ḻµÄʱÆڣ¬·ñÔò¾Ͳ»ÄÜ˵ÊǸ»ԣ·±ÈÙʱÆڡ£¹ÈÎïÊDZØÐèƷ£¬¶ø°×ÒøֻÊDz»±ØҪÎïƷ¡£ ¡¡¡¡Òò´ˣ¬ÔÚʮËÄÊÀ¼ÍÖÐҶµ½ʮÁùÊÀ¼ÍÖÐҶÕâ¶ÎʱÆÚÄڣ¬ÓÉÓڲƸ»Ôö½øº͸ÄÁ¼·¢չ¶øÒýÆðµĹó½ðÊôÊýÁ¿µÄÔö´󣬲»ÂÛÆäÔö´ó³̶ÈÈçºΣ¬Ëü¶Բ»Áе߻òŷÖÞÆäËûÈκιú¼ң¬¶¼²»¿ÉÄܷ¢Éú¼õÉٹó½ðÊô¼ÛֵµÄÇãÏò¡£ËùÒԣ¬ËѼ¯Íùʱ¹ÈÎï¼۸ñµÄ×÷¼ң¬ҪÊǸù¾ݶԹÈÎï»òÆäËûÎïƷ¼۸ñµĹ۲죬ûÓÐÀíÓÉÍƶÏÕâ¸öʱÆÚÀï°×ÒøµļÛֵ¼õµÍÁˣ¬ÄÇĩËûÃǾ͸üûÓÐÀíÓɣ¬¸ù¾ÝÏëÏóÖвƸ»µÄÔö½øº͸ÄÁ¼µķ¢չÀ´ÍƶÏÕâÆڼä°×Òø¼Ûֵµļõµ͡£ -¡¡¡¡µڶþÆÚ +¡¡¡¡µڶþÆÚ ¡¡¡¡²»¹ܸ÷ѧÕ߶ÔÓڵÚһÆÚÒø¼۱䶯µÄÒâ¼û£¬ÊÇÄÇô²»Ïàͬ£¬ËûÃǶÔÓڵڶþÆÚÒø¼۱䶯µÄÒâ¼û£¬ȴÏàͬ¡£ ¡¡¡¡ ÔڴÓ1570Äê×óÓҵ½1640Äê×óÓÒÕâ´óԼÆßʮÄêµÄʱÆÚÀ°×Òø¼Ûֵº͹ÈÎï¼ÛֵµıÈÀý£¬°´ÍêȫÏ෴µķ½Ïò±䶯¡£ÕâÆڼ䣬ÒøµÄÕæʵ¼ÛֵϽµÁˣ¬»»ÑÔ֮£¬ËüËùÄܻ»µõÄÀͶ¯Á¿£¬±ȴÓǰÉ٣»¹ÈÎïµÄÃûÒå¼۸ñÉÏÉýÁˣ¬´ÓǰÊۼÛÊÇÿ¿äÌضþ°»˹Òø£¬ԼºϽñ±ÒʮÏȽñ£¬ÕâʱÊۼÛÊÇÿ¿äÌØÁùÅÌ˹»ò°˰»˹Òø£¬ԼºϽñ±ÒÈýʮÏÈÁî»òËÄʮÏÈÁ ¡¡¡¡ÃÀÖ޷áÈĿóɽµķ¢Ï֣¬ËƺõÊÇÕâʱÆÚÒø¶ԹÈÎïµıȼۼõµ͵ÄΨһԭÒ򡣶ÔÓڴËÖֱ䶯£¬´ó¼Ҷ¼×÷ͬÑùµÄ˵Ã÷£¬¹ØÓÚÒøµıȼÛϽµÕâһÊÂʵ¼°ÆäԭÒ򣬴Óδ·¢ÉúÕùִ¡£ÔÚÕâһʱÆڣ¬´󲿷ÖŷÖÞÔڲúҵº͸ÄÁ¼Éϣ¬¶¼¿´×Žøչ£¬¶ø¶ÔÒøµÄÐèÇó£¬Òò´˱ØȻÔö¼ӡ£µ«Êǣ¬¹©¸øµÄÔö¼ӣ¬´ó´󳬹ýÁËÐèÇóµÄÔö¼ӣ¬ËùÒԣ¬Òø¼۴ó´óµÍÂ䡣Ӧµ±עÒ⣬ÃÀÖÞÒø¿óµķ¢Ï֣¬¶ÔӢ¸ñÀ¼µÄÎï¼ۣ¬ËÆδÔøÓÐÏÔÖøӰÏ죬ֱµ½1570Äê´Ӻ󣬲ÅÓÐӰÏ졣¾¡¹ܲ¨ÍÐÎ÷Òø¿óÒѷ¢Ïֶþʮ¶àÄêÁˣ¬µ«¶ÔӢ¸ñÀ¼Îï¼ۻ¹ÎÞӰÏ졣 ¡¡¡¡¸ù¾ÝÒÁ¶ÙѧԺµļǼ£¬´Ó1595Ä굽1620Ä겢°üÀ¨1595ÄêºÍ1620ÄêÔÚÄڣ¬ÎÂɯÊг¡Éϣ¬×îºÃСÂóһ¿äÌػò¾ÅÆÑʽ¶úµÄƽ¾ù¼۸ñΪ¶þ°÷һÏÈÁîÁùÓÖʮÈý·Ö֮¾űãʿ£¬´ÓÕâ½ð¶îÂÔȥÁãÊý£¬Ôټõȥȫ¶îµľŷÖ֮һ£¬¼´¼õȥËÄÏÈÁîÆßÓÖÈý·Ö֮һ±ãʿ£¬ÄÇĩһ¿äÌػò°ËÆÑʽ¶úµļ۸ñΪһ°÷ʮÁùÏÈÁîʮÓÖÈý·Ö֮¶þ±ãʿ¡£´ÓÕâ½ð¶îͬÑùÂÔȥÁãÊý£¬ÔÙÓÉÓàϵĽð¶¼õ³ý¾ŷÖ֮һ³ÉËÄÏÈÁîһÓ־ŷÖ֮һ±ãʿ£¬¼´×îºÃСÂóÓëÖеÈСÂóÕâ¶þÕ߼۸ñ֮²ÄÇĩÖеÈСÂó¼۸ñ£¬ԼΪһ°õʮ¶þÏÈÁî°ËÓ־ŷÖ֮Èý±ãʿ£¬Լºϱ¨Áù°»˹ÓÖһ°»˹µÄÈý·Ö֮һ¡£ ¡¡¡¡Ó־Ýͬһ¼Ç¼£¬´Ó1621Ä굽1636Ä꣬ÔÚͬһÊг¡Éϣ¬ͬһºâÁ¿µÄ×îºÃСÂóµÄƽ¾ù¼۸ñ£¬ԼΪ¶þ°÷ʮÏÈÁ´ÓÕâ½ð¶ÉÏÊö¿۳ý£¬ÄÇĩһ¿äÌػò°ËÆÑʽ¶úÖеÈСÂóµÄƽ¾ù¼۸ñΪһ°÷ʮ¾ÅÏÈÁîÁù±ãʿ£¬ԼºÏÒøÆßÓÖÈý·Ö֮һ°»˹¡£ -¡¡¡¡µÚÈýÆÚ +¡¡¡¡µÚÈýÆÚ ¡¡¡¡ÃÀÖ޿óɽ·¢ÏÖËùÕÐÖµÄÒø¼۵ÍÂ䣬Ëƺõµ½1630ÄêÓë1640Äê֮¼ä»òÔÚ1636Äê×óÓң¬ÒѸæֹͣ£¬¶øÓë¹ȼ۱Ƚϣ¬Òø¼۵ĵÍÂäÄÇʱºòËƺõÓйý֮¶øÎ޲»¼°¡£µ½ÁËÏÖÊÀ¼ͣ¬Òø¼۶àÉÙÇ÷ÓÚÉÏÉý£¬ÕâÉÏÉýµÄÇ÷Êƣ¬»òÐíÔÚǰÊÀ¼ʹÓǰ¼´Òѿªʼ¡£ ¡¡¡¡¾ÝÉÏÊö¼Ç¼£¬´Ó1637Ä굽17OOÄ꣬¼´ǰÊÀ¼Í×îºóÁùʮËÄÄê¼䣬ÎÂɯÊг¡Éϣ¬ÓɾÅÆÑʽ¶ú×é³ɵÄһ¿äÌØ×îºÃСÂó£¬ƽ¾ù¼۸ñËÆΪ¶þ°÷ʮһÏÈÁîÈý·Ö֮һ±ãʿ¡£Õâƽ¾ù¼۸񣬱ÈʮÁùÄêǰµÄƽ¾ù¼۸񣬽ö¸ßһÏÈÁîÈý·Ö֮һ±ãʿ¡£µ«ÔÚÕâÁùʮÄê¼䣬·¢ÉúÁËÁ½¸öʼþ£¬ÒÔÖµ±ʱ¹ÈÎïµÄȱ·¦£¬ԶԶ³¬¹ýÊճÉÇé¿öËùÔì³ɵij̶ȡ£µ¥µ¥ÕâÁ½¸öʼþ£¬¾͹»˵Ã÷¹ÈÎï¼۸ñÕâʱÉÔÉ԰º¹óµÄԭÒ򣬶øÎÞÐëÉèÏëÒø¼ÛÓнøһ²½µÄϵø¡£ ¡¡¡¡µÚһ¸öʼþÊÇÄÚÂҡ£ÄÚÂÒ×躦¸û×÷£¬·Á°­ÉÌҵ¡£Æä½á¹û£¬¹ÈÎï¼۸ñµÄÌڹó´ó´󳬹ýÁ˵±ʱÊճÉÇé¿öËùÔì³ɵij̶ȡ£ÄÚÂҵÄÕâ¸öӰÏ죬Æռ°µ½²»ÁеßһÇÐÊг¡£¬¶ø¹ÈÎïÐëÑö¸øÓÚƧԶµط½µÄÂ׶ØÊг¡ËùÊÜӰÏìÓȾޡ£ËùÒԣ¬¾ÝÉÏÊö¼Ç¼£¬ÎÂɯÊг¡Éϣ¬ÓɾÅÆÑʽ¶ú×é³ɵÄ×îºÃСÂóһ¿äÌأ¬¼۸ñÔÚ1648ÄêΪËİ÷ÎåÏÈÁ´ÎÄêΪËİ÷¡£ÕâÁ½Äê¹ÈÎïµļ۸񣬳¬¹ý¶þ°÷ʮÏÈÁ1637ÄêǰʮÁùÄêµÄƽ¾ù¼۸񣩣¬¼ƴïÈý°÷ÎåÏÈÁҪÊǰÑËüÔÚǰÒԼÍ×îºóÁùʮËÄÄêÖÐ̯·֣¬ÄǾͺܹ»˵Ã÷µ±ʱ¹ȼÛΪʲôÉÔÉÔÌڹ󡣴ËÁ½Äê¶ȵļ۸ñ£¬ËäÊô×î¸߼۸񣬵«ÄÚÂÒÒýÆðµĸ߼۸ñ£¬ÎÞÒɲ»ֻÊÇÕâЩ¡£ @@ -585,7 +585,7 @@ ¡¡¡¡ÿÄêÓɿóɽÌṩÊг¡µÄͭÌúÁ¿£¬¾ø·ǽðÒøËù¿ɱȽϡ£µ«ÎÒÃǾö²»ÄÜÒò´˾ÍÏëÏó£¬ÕâЩ¼ú½ðÊô¹©¸øµÄÔö´ó£¬Óг¬¹ý¹²ÐèÇóµÄÇãÏ򣬻òÕß˵£¬ÓÐʹÆä¼۸ñÖð½¥Ç÷ÓڵÍÁ®µÄÇãÏò¡£ÄÇĩ£¬ÎÒÃÇΪʲôÏëÏó¹ó½ðÊôÓÐÕâÇãÏòÄأ¬²»´í£¬¼ú½ðÊô±Ƚϼá¹̣¬µ«ÓÃÓڱȽÏÈÝÒ×ĥËðµÄÓÃ;£¬¶øÇÒÒòÆä¼Ûֵ½ÏÇᣬÈËÃǶÔÆ䱣´æҲ²»Ïó¶Թó½ðÊôÄÇôÁôÐġ£µ«Êǣ¬¹ó½ðÊô²¢²»һ¶¨±ȼú½ðÊô¸üÄܾô档¹ó½ðÊôÒೣÔڸ÷·½ÃæËðʧ¡¢Ïûĥºͺķѡ£ ¡¡¡¡һÇнðÊô¼۸ñ£¬Ë䶼ÓлºÂýµÄÖ𽥵ı䶯£¬µ«ÓëÆäËûÍÁµØԭÉú²úÎï±Ƚϣ¬ÔòÖðÄêµı䶯£¬ȷÊDZȽÏС¡£¶ø¹ó½ðÊô¼۸ñÓë¼ú½ðÊô¼۸ñ±Ƚϣ¬ÔòͻȻ±䶯µĿÉÄÜÐԻ¹ҪС¡£ԭÀ´£¬½ðÊô¼۸ñ²»Òױ䶯µÄԭÒ򣬾ÍÔÚÓÚËüµÄÄ;ÃÐԡ£ȥÄêÉÏÊеĹÈÎÔڽñÄêÄêÖս«ȫ²¿»򼸺õȫ²¿Ïû·Ѹɾ»£¬µ«¶þÈý°ÙÄêǰÓɿóɽ²ÉȡµÄÌú£¬¿ÉÄÜһ²¿·ÖÏÖÔڻ¹ÔÚʹÓ㬶þÈýǧÄêǰÓɿóɽ²ÉȡµĽð£¬Ҳ¿ÉÄÜÓÐһ²¿·ÖÏÖÔڻ¹ÔÚʹÓ᣸÷Äê¶ȱ»Ïû·ѵĹÈÎïÁ¿£¬Óë¸÷ÄêÉú²úµĹÈÎïÁ¿£¬³£³£±£³ÖÏ൱µıÈÀý¡£µ«¼×Äê¶ÈÓëÒÒÄê¶ÈËùʹÓõÄÌúÁ¿¼äµıÈÀý£¬¼¸ºõ²»´ó»áÊÜÕâÁ½Äê¶ÈÌú¿ó²ú³ö¶îżȻ²îÒìµÄӰÏ졣ËùʹÓõĽðÁ¿¼äµıÈÀý£¬¸ü²»»áÊܽð¿ó³ö²ú¶î±䶯µÄӰÏ졣ËùÒԣ¬´󲿷ֽðÊô¿óɽÖðÄêµÄÉú²ú¶Ëä±ȴ󲿷ֹÈÌïÖðÄêµÄÉú²ú¶ҲÐíÓиü´óµı䶯£¬µ«Éú²ú¶îµı䶯£¬¶ÔÕâÁ½Öֲ»ͬÉú²úÎï¼۸ñµÄӰÏ죬ÊDz»һÑùµġ£ -¡¡¡¡ ½ðÒø¼Ûֵ±ÈÀýµı䶯 +¡¡¡¡ ½ðÒø¼Ûֵ±ÈÀýµı䶯 ¡¡¡¡ÃÀÖ޿óɽ·¢ÏÖÒÔǰ£¬ŷÖ޸÷Ôì±ҳ§¹涨´¿½ð¶Դ¿ÒøµļÛֵ±ÈÀý£¬Ϊһ±ÈʮֻÖÁһ±Èʮ¶þ¡£¼´һ°»˹´¿½ð±»ÈÏΪֵʮ°»˹ÄËÖÁʮ¶þ°»˹µĴ¿Òø¡£µ½ǰÊÀ¼ÍÖÐҶ£¬Æä±ÈÀý¸ıäΪһ±ÈʮËÄÄËÖÁһ±ÈʮÎ壬¼´һ°»˹´¿½ð±»ÈÏΪֵʮËİ»˹ÄËÖÁʮÎ尻˹µĴ¿Òø¡£ÕâÑù£¬½ðµÄÃûÒå¼ÛֵÔö´óÁˣ¬»»ÑÔ֮£¬½ðËùÄܽ»»»µÄÒøÁ¿¼ӶàÁˡ£½ðÒøÁ½½ðÊôµÄÕæʵ¼Ûֵ£¬»»ÑÔ֮£¬ËüÃÇËùÄܹºµõÄÀͶ¯Á¿£¬ËäһͬÏÂÂ䣬µ«Òø±ȽðÂäµøüµ͡£ÃÀÖ޽ð¿óÒø¿óµķáÈij̶ȣ¬±ÈÒÔǰÈκÎÒѷ¢Ïֿóɽ¶¼´󣬵«Òø¿óµķáÈij̶ȣ¬±Ƚð¿óËƺõ¸ü´ó¡£ ¡¡¡¡ÿÄêÓÉŷÖÞÔËÍùӡ¶ȵÄÒøÁ¿ºܴó£¬ʹµÃӢ¹úһ²¿·ÖֳÃñµصÄÒø¼ۺͽð¶ԱȽ¥Ç÷µÍÂ䡣¼Ӷû¸÷´ðµÄÔì±ҳ§£¬ÓëŷÖÞһÑù£¬ÈÏΪһ°»˹´¿½ðֵʮÎ尻˹´¿Òø¡£¿ÉÊǣ¬ÕâÆÀ¼ۺͽðÔÚÃϼÓÀ­Êг¡ÉϵļÛֵÏà±ȣ¬Ëƾõ̫¸ߡ£Öйú½ðÒø֮±ȣ¬ÒÀȻΪһ¶Ôʮ£¬»òһ¶Ôʮ¶þ£¬Èձ¾¾Ý˵ÊÇһ¶԰ˡ£ ¡¡¡¡¾ÝÂó¸ù˹ÊϵļÆË㣬ÿÄêÊäÈëŷÖ޵ĽðÒøÊýÁ¿֮¼äµıÈÀý£¬½«½üһ¶Զþʮ¶þ£¬¼´½ðÊäÈëһ°»˹£¬ÒøÊäÈë¶þʮ¶þ°»˹¡£¿ÉÊǣ¬ÒøÊäÈëŷÖ޺ó£¬ÓÖÓÐһ²¿·ÖתÔ˶«ӡ¶ȣ¬½á¹û£¬ÁôÔÚŷÖ޵ĽðÒøÊýÁ¿֮¼äµıÈÀý£¬ËûÒÔΪ£¬ԼÓëÆä¼Ûֵ±ÈÀýÏàͬ£¬¼´һ¶ÔʮËĻòʮÎ塣ËûËƺõÒÔΪ£¬ÕâÁ½½ðÊô¼Ûֵ¼äµıÈÀý£¬±ØȻÓëÆäÊýÁ¿¼äµıÈÀýһÖ¡£ËùÒԣ¬ÔÚËûÏëÀ´£¬Èç¹û²¨ÓÐÕâô¶àÒøÊä³ö£¬ÔòËüÃǼÛֵµıÈÀý£¬µ±Ϊһ¶Զþʮ¶þ¡£ @@ -600,17 +600,17 @@ ¡¡¡¡²»¹ý£¬ÒÔϵÄʼþ£¬ÊDZØÐëעÒâµġ£²»Â۽ðÒøµı»¼ٶ¨µÄÄêÊäÈëÁ¿ÊǶàÊÇÉ٣¬ÆäÄêÏû·ÑÁ¿ÖչéÓÐһ¸öʱÆڻáÓëÆäÄêÊäÈëÁ¿ÏàһÖ¡£½ðÒøµÄ×ÜÁ¿Óú¶࣬ÆäÏû·ÑÒà±ØÔö´ó£¬ÓÐʱ»¹±È×ÜÁ¿Ôö¼ӵöàµöࡣ×ÜÁ¿Ôö¶࣬Æä¼Ûֵ±ØÒò¶ø¼õÉ١£ÓÚÊÇÓÃ;Ôö¶࣬ÈËÃÇʹÓÃʱҲ²»ÄÇôÉ÷Öذ®»¤£¬½á¹û£¬½ðÒøµÄÏû·ÑÁ¿±ØÒԱÈÆä×ÜÁ¿µÄÔö¼Ӹü´óµıÈÀýÔö´ó¡£ËùÒԣ¬¾­¹ýһ¶¨ʱÆں󣬽ðÒøµÄÿÄêÏû·ÑÁ¿£¬ÔÚÊäÈ벻¼ÌÐøÔö¼ӵÄÌõ¼þÏ£¬һ¶¨»áÓëÆäÿÄêÊäÈëÁ¿Ç÷ÓÚһÖ¡£¿ÉÊǣ¬½ñÈյÄÊäÈ룬ÒÀ¾ÉÔڼÌÐøÔö¼ӡ£ ¡¡¡¡Èç¹ûʹ½ðÒøÿÄêÏû·ÑÁ¿´ﵽÓëÿÄêÊäÈëÁ¿ÏàµÈÒԺó£¬ÿÄêÊäÈëÖ𽥼õÉ٣¬ÄÇĩ£¬ÿÄêÏû·ÑÁ¿ҲÐíÓÐһ¶Îʱ¼ä»ᳬ¹ýÿÄêÊäÈëÁ¿¡£ÓÚÊǣ¬½ðÒøµÄ×ÜÁ¿¿ÉÄÜÖ𽥲»֪²»¾õµؼõÉ٣¬½ðÒøµļÛֵÖ𽥲»֪²»¾õµØÉÏÉý£¬һֱµ½ÿÄêÊäÈëÁ¿²»Ôö²»¼õ֮ʱΪֹ¡£Õâʱº򣬽ðÒøÿÄêÏû·ÑÁ¿£¬½«Ö𽥲»֪²»¾õµØÊÊӦÿÄêÊäÈëÁ¿ËùÄÜ֧³ֵÄÊý¶ -¡¡¡¡ »³ÒÉÒø¼ÛÈÔÔڼÌÐøµøÂäµĸù¾Ý +¡¡¡¡ »³ÒÉÒø¼ÛÈÔÔڼÌÐøµøÂäµĸù¾Ý ¡¡¡¡ŷÖ޲Ƹ»ÈÕÒæÔö¼ӣ¬ÒԼ°ÈÏΪÓÉÓڹó½ðÊôÁ¿×ÔËæ²Ƹ»Ôö¼ӶøÔö¼ӣ¬¹ó½ðÊô¼ÛֵÒò´Ë×ÔËæ¹ó½ðÊôÊýÁ¿Ôö¼Ӷø¼õÉÙÕâ¸öË׼û£¬¿ÉÄÜʹÐí¶àÈËÏàÐţ¬ŷÖÞÊг¡ÉϽðÒø¼ÛֵÆù½ñ»¹ÔڵøÂ䡣¶øÐí¶àÍÁµØԭÉú²úÎﻹÔÚÖð½¥ÌڹóÕâ¸öÊÂʵ£¬ҲÐíʹÕâ°àÈËԽ·¢ȷÐÅÕâÖּû½⡣ ¡¡¡¡ÎÒÒÑÔÚǰÃæ˵¹ý£¬һ¹úËæ²Ƹ»Ôö¼ӶøÔö¼ӵĹó½ðÊôÁ¿£¬¾øûÓмõµÍÆä¼ÛֵµÄÇãÏò¡£һÇÐÖÖÀàµÄÉݳÞƷºÍÕ䯿Ʒ£¬µ±Ȼ¶¼Îo¼¯¸»¹ú£¬ÓÉÓÚͬһԭÒ򣬽ðÒøҲ×ÔȻÎo¼¯¸»¹ú¡£ÕⲻÊÇÒòΪÕâЩÎïƷ£¬Ôڸ»¹ú±ÈÔÚƶ¹úµÍÁ®£¬ȴÊÇÒòΪËüÃÇÔڸ»¹ú±ÈÔÚƶ¹ú°º¹󣬼´Ôڸ»¹ú¿ɵøüºõļ۸ñ¡£ÓÅԽµļ۸ñ£¬ÎüÒýÁËÕâЩÎïƷ£¬ÕâÓÅԽÐÔһµ©Ïû¼õ£¬ÕâЩÎïƷ¾Ͳ»»áÏòÕⷽÃæÎo¼¯¡£ ¡¡¡¡³ýÁ˹ÈÎPÆäËûȫ¿¿ÈËÀàÇÚÀͶøÉú²úµĸ÷ÖÖֲÎһÇÐÖÖÀàµÄԭÉú²úÎÈç¼ÒÐ󡢼ÒÇݣ¬Èç¸÷ÖÖÁԻñÎÈçµØÖÐÓÐÓõϝʯºͿóÎïµȣ¬¶¼ËæÉç»á²Ƹ»Ôö³¤ºͼ¼Êõ¸Ľø¶ø×ÔȻÇ÷Óڰº¹ó£¬ÕâҲÊÇÎÒÒѾ­ŬÁ¦˵Ã÷¹ýµġ£Ëùֻ£¬×ÝʹÕâЩÉÌƷÄܻ»µñÈÒÔǰ¶àµİ×Òø£¬ÎÒÃÇÈԲ»ÄÜÒò´˱ã˵£¬Òø¼Ûʵ¼ÊÉÏÒѽÏǰµÍÂ䣬»»ÑÔ֮£¬ÒøֻÄܹºÂò±ÈÒÔǰÉٵÄÀͶ¯Á¿¡£ÄÜÓɴËÒý³öµĽáÂÛֻÊǣ¬ÕâЩÉÌƷµļ۸ñʵ¼ÊÉÏÒѾ­Ìá¸ߣ¬»»ÑÔ֮£¬ÄܹºµñÈÒÔǰ¶àµÄÀͶ¯Á¿¡£Ëæ×ŲƸ»µÄÔö³¤ºͼ¼ÊõµĸĽø£¬ÕâЩÉÌƷ£¬²»µ«ÃûÒå¼۸ñÉÏÉýÁˣ¬ÆäÕæʵ¼۸ñҲÉÏÉýÁˡ£ÃûÒå¼۸ñµÄÉÏÉý£¬²¢·ÇÒø¼ÛÏÂÂ䵼á¹û£¬¶øÊǸÃÉÌƷ×ÔÉí¾ßʵ¼ÛֵÉÏÉýµĽá¹û¡£ ¡¡¡¡ Éç»á½ø²½¶ÔÈýÖÖԭÉú²úÎïµIJ»ͬӰÏì ¡¡¡¡ԭÉú²úÎ¿Éֻ·Ö×÷ÈýÀࡣµÚһÀà²úÎXºõȫȻ²»ÄÜÓÉÈËÀàÀÍÁ¦ʹ֮Ôö¼ӣ»µڶþÀà²úÎïÄÜÊÊӦÐèˣ¶øÔö¼ӣ»µÚÈýÀà²úÎïËäÄÜÓÉÈËÀàÇÚÀͶøÔö¼ӣ¬µ«ÈËÀàÇÚÀ͵ÄʵЧÊÇÓÐÏ޵Ļ򿿲»סµġ£µÚһÀà²úÎïµÄÕæʵ¼۸ñ¿ÉËæ²Ƹ»µÄÔö³¤ºͼ¼ÊõµĸĽø¶øÎÞÏÞÖƵØÉÏÉý¡£µڶþÀà²úÎïµÄÕæʵ¼۸ñ£¬ÓÐʱËä¿ɴó´óÉÏÉý£¬µ«¾ö²»Äܳ¤¾ó¬Խһ¶¨Ï޶ȡ£µÚÈýÀà²úÎïµÄÕæʵ¼۸ñ£¬ÔÚ×ÔȻÇãÏòÉϣ¬ËäÒÀ¸ÄÁ¼³̶ȵÄÔö½ø¶øÔö¸ߣ¬²»¹ýÔÚͬһ¸ÄÁ¼³̶ÈÏ£¬Æä¼۸ñÓÐʱÉõÖÁ·´¶øÏÂÂ䣬ÓÐʱ±£³Öԭ״£¬ÓÐʱ»ò¶à»òÉٵØÉÏÉý£¬Ҫ¿´żȻʱäʹÈËÀàÇÚÀ͵ÄŬÁ¦£¬ÔÚÔö¼Ӵ˵ȲúÎïʱËùÊÕʵЧÈçºζø¶¨¡£ -¡¡¡¡µÚһÀà +¡¡¡¡µÚһÀà ¡¡¡¡ËæÉç»á½ø²½¶ø¼۸ñÌá¸ߵĵÚһÀà²úÎÊǼ¸ºõÍêȫ²»ÄÜÓÉÈËÀàÇÚÀÍÔö¼ӵġ£ËüÃǵIJú¶î¼Ȳ»Äܳ¬¹ý×ÔȻÉú²úµÄһ¶¨·ÖÁ¿£¬ËüÃǵÄÐÔÖÊÓַdz£ÈÝÒ׸¯°ܣ¬ËùÒԣ¬Ïë°Ѹ÷¼¾½ÚÉú²úµÄÕâÀà²úÎȫ²¿Ðî»ýÆðÀ´£¬ÊƲ»¿ÉÄܡ£´󲿷ÖϡÉÙÌØÒìµÄÄñÀàÓãÀ࣬¸÷ÖÖҰÇÝҰÊޣ¬¸÷ÖֺòÄ񣬶¼ÊôÓڴËÀࡣËæ×ŲƸ»µÄÔö½øÒԼ°Ëæ²Ƹ»µÄÔö½ø¶ø·¢ÉúµÄÉݳ޵ÄÔö½ø£¬¶Դ˵ȲúÎïµÄÐèÇó¶à°ë»áÔö¼ӣ¬µ«Æ乩¸øȴ²»ÄÜÓÉÈËÁ¦ʹÆä´óÁ¿Ôö¼ӡ£ËùÒԣ¬ÕâµÈÉÌƷµļ۸񣬾ͿÉË湺ÂòÕ߾ºÕùµIJ»¶ÏÀ©´ó¶øÎÞÏÞÖƵØÉÏÉý¡£ÀýÈçɽð֣¬¼´ʹ³ÉΪʱÉÐƷ£¬¼۸ñÉÏÉýµ½¶þʮ¼¸Äáһֻ£¬ÈËÀàҲ²»ÄÜÓÉÇÚÀͶøʹÊÐÉϵÄɽðÖÔö¼ӵ½´ó´󳬹ýÏÖÓеÄֻÊý¡£¹ÅÂÞÂíÈË×î¡ʢʱ´ú£¬ΪºζÔÕä¹óÓãÀàÄñÀà֧¸¶¼«¸߼۸ñ£¬Õý¿ÉÓÃÕâÀíÓÉÀ´˵Ã÷¡£ÕâÖָ߼ۣ¬ȷ·ǵ±ʱÒø¼۵ÍÂ䵼á¹û£¬¶øÊDz»ÄÜËæÈËÒâÔö¼ӵÄÕâЩϡÓÐÕäƷ±¾Éí¼ÛֵÉÏÉýµĽá¹û¡£ÔÚÂÞÂí¹²º͹úûÂäǰºóÈô¸ÉÄêÄڣ¬ÒøµÄÕæʵ¼Ûֵ±ȽñÈմ󲿷ֵÄŷÖ޶¼¸ߡ£ÂÞÂí¹²º͹ú¶ÔÎ÷Î÷ÀïËù½ÉÄÉʲһ˰µÄСÂó£¬ÿһεÏ˹»òһÅä¿˸¶¼ÛÈýÈû˹ÌØ˹£¬ԼºÏӢ±ÒÁù±ãʿ¡£µ«Õâ¼۸ñ´ó¸ÅҪ±Èƽ¾ùµÄÊм۵ͣ¬Î÷Î÷ÀïũÃñÓÐÒåÎñ°´Õâ¼۸ñ½»ÊÛËûÃǵÄСÂó£¬ËûÃÇÈÏΪÊÇһÖֿÎ˰¡£ËùÒԣ¬ÂÞÂíÈËÈôÐè´ÓÎ÷Î÷ÀïÊäÈëʲһ˰ÒÔÍâµĹÈÎËûÃǾÍÐëÒÀÕÕÆõԼ£¬¶ÔÓڳ¬¹ýÁ¿ÿһÅä¿˸¶¸øËÄÈû˹ÌØ˹£¬ԼºÏӢ±Ұ˱ãʿ¡£Õâ¼۸ñ£¬Ï뼴µ±ʱÈÏΪÊʵ±¶øºÏÀíµļ۸ñ£¬Ҳ¾ÍÊǵ±ʱÊÓΪƽ¾ù»òÆÕͨµÄÆõԼ¼۸񣬻»ËãÆðÀ´£¬ÿ¿äÌØԼֵ¶þʮһÏÈÁӢ¹úСÂ󣬾ÍƷÖʶøÑԣ¬½ÏÎ÷Î÷ÀïСÂóΪÁӣ¬¶ø¾ÍŷÖÞÊг¡ÉÏÊۼ۶øÑԣ¬ͨ³£½ÏÎ÷Î÷ÀïСÂóΪµ͡£µ«ÔÚ×î½ü»ÄǸÄê¶ÈÒÔǰ£¬ÆäÆÕͨÆõԼ¼۸ñ£¬ȴΪÿ¿äÌضþʮ°ËÏÈÁÒò´ˣ¬°ÑÍù¹Åʱ´úµÄÒø¼ۣ¬ÓëÏÖÔڵÄÒø¼ÛÏà±ȣ¬һ¶¨ΪÈý¶ÔËÄ֮·´±ÈÀý£¬¼´µ±ʱ±¨Èý°»˹£¬ÓëÏÖÔÚÒøËİ»˹±Ƚϣ¬ÄܹºµÃͬÁ¿µÄÀͶ¯»òÉÌƷ¡£Àúʷѧ¼ÒÆÕÁÖÄá¼ÇÔأ¬ÈûÒÁ°¢˹ÒÔÁùǧÈû˹ÌØ˹£¨ºÏӢ±ÒÎåʮ°÷£©¹ºһֻ°×ҹݺ£¬Ï׸øŮÍõ°¢¸ñÀûƤÄɣ»°¢Î÷Äᰢ˹¡¤ÈûÄÉÒ԰ËǧÈû˹ÌØ˹£¨ºϽñÈÕӢ±ÒÁùʮÁù°÷ʮÈýÏÈÁîËıãʿ£©¹ººìÓãһβ¡£µ±ÎÒÃǶÁµ½ÕâÖּÇÔØʱ£¬ÕâЩÆæ¹óµļ۸ñ£¬Ë乻ʹÎÒÃǾª¾ø£¬µ«ÕâЩ¼۸ñÒÔÎÒÃǿ´À´£¬Ëƻ¹±Èʵ¼ÛÉÙÈý·Ö֮һ¡£ÕâÁ½¼þ¶«Î÷µÄÕæʵ¼۸񣬻»ÑÔ֮£¬ËüÃÇËùÄܽ»»»µÄÀͶ¯¼°ʳƷÁ¿£¬±ÈÆäÃûÒå¼۸ñÔڽñÈոøÎÒÃDZíʾµÄÊýÁ¿£¬Լ¶àÈý·Ö֮һ¡£Õâ¾ÍÊÇ˵£¬ÈûÒÁ°¢˹Ϊһֻ°×ҹݺ¶ø¸¶³öµÄÀͶ¯ºÍʳƷµÄ֧ÅäȨ£¬µÈÓÚÏֽñÁùʮÁù°÷ʮÈýÏÈÁîËıãʿ²ÅÄܹºµõÄÀͶ¯ºÍʳƷµÄ֧ÅäȨ£»°¢Î÷Äᰢ˹¡¤ÈûÄÉΪһβºìÓã¶ø¸¶³öµÄÀͶ¯¼°ʳƷµÄ֧ÅäȨ£¬µÈÓÚÏֽñ°Ëʮ°˰÷ʮÆßÏÈÁî¾ÅÓÖÈý·Ö֮һ±ãʿ²ŵùºµõÄÀͶ¯ºÍʳƷµÄ֧ÅäȨ¡£ÒýÆðÕâÖֹý·ּ۸ñµÄԭÒò£¬ÓëÆä˵ÊÇÒøÁ¿³ä³⣬ÒÔÖÂÒø¼۵ÍÁ®£¬µ¹²»Èç˵ÊÇÂÞÂíÈ˵ÄʣÓàÀͶ¯ʣÓàʳƷ¹ýÓڷáӯ£¬ÒÔÖÂÕ䯿ƷÕù¹ºÕ߶ࡣµ±ʱÂÞÂíÈËËù³ÖÓеÄÒøÁ¿£¬±ÈͬһÀͶ¯Á¿¼°ʳƷÁ¿µÄ֧ÅäȨÔڽñÈÕËùÄܻñµõÄÒøÁ¿ҪСµöࡣ -¡¡¡¡µڶþÀà +¡¡¡¡µڶþÀà ¡¡¡¡¼۸ñËæÉç»á½ø²½¶øÌڹóµĵڶþÀàԭÉú²úÎÆäÊýÁ¿ÄÜӦÈËÀàÐèҪ¶øÔö¼ӡ£ËüÃǰüÀ¨ÄÇЩÓÐÓõֲ͝Îµ±ÍÁµØδ¿ª±Ùʱ£¬×ÔȻÉú²úÎïºܶ࣬ÒÔÖÂÎ޼Ûֵ¿ÉÑԣ¬µ½Á˸û×÷½ø²½£¬¾Ͳ»µò»ÈÃλ¸øÄÇЩ¸üΪÓÐÀûµıðÖֲúÎÔÚÉç»áÈÕÒæ½ø²½µij¤Æڹý³ÌÖУ¬´ËÀà²úÎïµÄÊýÁ¿ÈÕÒæ¼õÉ٣¬¶øͬʱ£¬ÆäÐèҪȴ¼ÌÐøÔö¼ӡ£ÓÚÊǣ¬ÆäÕæʵ¼Ûֵ£¬»»ÑÔ֮£¬ËüËùÄܹºÈë»ò֧ÅäµÄÕæʵÀͶ¯Á¿£¬Öð½¥Ôö¼ӣ¬ÖնøÔö¼ӵÃÕâô¶࣬ÒÔÖÂÓëËûÖÖÓÉÈËÁ¦ÔÚÍÁÈÀ×î·ÊÎ֡¢¸û×÷×îÍêÉƵÄÍÁµØÉϲú³öµÄÈκÎÎïƷ±Ƚϣ¬Ҳ²»ÏàÉÏÏ¡£µ«Êǣ¬һµ©´ﵽÕâ¸߶ȣ¬¾Ͳ»ÄÜÔÙÔö¸ßÁˡ£Èç¹û¾¹³¬¹ýÕâÏ޶ȣ¬ÄÇÂíÉϾͻáÓиü¶àÍÁµغÍÀͶ¯£¬Óõ½ÕⷽÃæÀ´Éú²ú´˵ÈÎïƷ¡£ ¡¡¡¡ÀýÈ磬ÉüÐó¼۸ñµÄÌڹó³̶ȣ¬Èç¹ûʹÈËÃǾõµã¬¿ª¿ÑÍÁµØÒÔÉú²úÉüÐóÄÁ²ݣ¬ºͿª¿ÑÍÁµØÒÔÉú²úÈËÀàʳÎÓÐͬµÈÀûÒ棬ÄǾͲ»ÄÜÔٽøһ²½ÉÏÕÇÁˣ¬Èç¹û¸üÉÏÕǣ¬ÂíÉϾͻáÓиü¶àµĹÈÌïת»¯ΪÄÁ³¡¡£¸ûµØÀ©´óµĽá¹û£¬һ·½Ã棬ҰÉúÄÁ²ݵÄÊýÁ¿¼õÉÙÁˣ¬ÒÔÖ²»ÒÀÀͶ¯ÅàÐó¶ø×ÔȻÉú³¤µļÒÐóµÄÈâ¼õÉ٣»Áíһ·½Ã棬³ÖÓн»»»¼ÒÐóÈâµĹÈÎï»ò¹ÈÎï´ú¼۵ÄÈËÊýÓÖÔö¼ÓÁˣ¬ÒÔÖ¼ÒÐóÈâµÄÐèÇóÔö¼ӡ£ÓÚÊǣ¬¼ÒÐóÈâ¼۸񣬼Ì֮¡£ÉüÐó¼۸ñ±ØÖð½¥Ìڹó£¬ÖÕʹÈ˾õµã¬ÒÔÍÁÈÀ×î·ÊÎ֡¢¸û×÷×îÍêÉƵÄÍÁµأ¬Éú²úÉüÐóµÄÄÁ²ݣ¬ºÍÉú²úÈËÀàµÄʳÎÓÐͬµÈÀûÒ档µ«һ¶¨Ҫµ½Éç»á½ø²½µĺóÆڣ¬¸û×÷ÊÂҵ²ÅÉáÈç´ËÀ©´ó£¬ʹÉüÐó¼۸ņ̃¸ߵ½ÕâÖ̶ֳȡ£ҪÊǹú¼һ¹Ïòǰ½ø²½£¬ÉüÐó¼۸񲻸ߵ½´˵ȳ̶ȣ¬һ¶¨»á¼ÌÐøÌڹó¡£ÔڽñÈÕŷÖޣ¬¿ÖÅ»¹ÓÐһ²¿·ֵط½ÉüÐó¼۸ñ£¬δÔöµ½Õâ¸ö¼«Ïޡ£¼´ºϲ¢ÒÔǰµÄËոñÀ¼ijµط½£¬ÒàÊôÈç´ˡ£ËոñÀ¼µĵط½£¬ÒËÓÚÐóÄÁµĶ࣬ÒËÓÚÆäËûÓÃ;µÄÉ١£ËùÒԣ¬ÄÇÀïµÄÉüÐó£¬ÈçֻÐÐÏúÓÚÄڵØÊг¡£¬ÔòÉüÐó¼۸񣬿ÖŲ»»á´ﵽÕâÑùµĸߣ¬ÒÔÖ°ÑÍÁµØÉú²úÄÁ²ݳÉΪÓÐÀû¡£ǰÃæ˵¹ý£¬Ӣ¸ñÀ¼µÄÉüÐó¼۸ñ£¬ÔÚÂ׶ظ½½ü£¬ËäËÆÓÚǰÊÀ¼ͳõÆڴﵽÁËÕ⼫Ïޣ¬µ«½ÏƧԶµط½£¬´ó¸źܾÃÒԺó²ŴﵽÕâÏ޶ȡ£ҲÐíÖÁ½ñ»¹ÓÐÉÙÊýµط½£¬ÉÐδ´ﵽÕâÏ޶ȡ£µ«Êǣ¬ÔڵڶþÀàԭÉú²úÎïÖУ¬¼۸ñÊ×ÏÈËæÉç»á½ø²½¶øÉýÖÁ¼«Ï޵ģ¬¿ÖÅÂҪËãÉüÐó¡£ ¡¡¡¡ÔÚÉüÐó¼۸ñÉÐδ´ﵽÕâ¸߶ÈÒÔǰ£¬¾ÍÊÇÊÊÓÚÉî¸ûϸ×÷µÄÍÁµأ¬Ҳ±ØÓд󲿷ֲ»ÄÜÍêȫ¸û×÷¡£ÔÚÍÁµعã´óµĹú¼ң¬³£Óд󲿷Öũµأ¬λÓÚƧԶµط½£¬Æä·ÊÁϲ»Ò×Ñö¸ø¸ɶ¼ÊУ¬Òò´ˣ¬¸û×÷ÓÅÁ¼µÄÍÁµØÆäÊýÁ¿һ¶¨ºÍũµØ×ÔÄÜÉú²úµķÊÁÏÁ¿³ɱÈÀý£»¶øũµØ×Բú·ÊÁÏÁ¿£¬ÓÖһ¶¨ºÍũµØËùά³ֵÄÉüÐóÊý³ɱÈÀý¡£ÍÁµØʩ¼ӷÊÁϣ¬²»Íâ¶þ;£ºÆäһ£¬·ÅÐóÓÚÌÒò¶øµ÷ࣻÆä¶þ£¬ËÇÐóÓھǣ¬³ö·à·ÊÌµ«ÉüÐó¼۸ñÈ粻¹»֧¸¶¸ûµصĵØ×âºÍÀûÈó£¬ũÃñ¾Ͳ»ԸÔÚÍÁµØÉϷÅÄÁÉüÐ󣬸ü²»ԸÉè¾ÇËÇÑøÉüÐó¡£ÒòΪ£¬Éè¾ÇËÇÑøÉüÐóËùÐèÄÁ²ݣ¬ÊÆÐëÑö¸øÓڷÊÎֶøÒѾ­¿ÑÖεÄÍÁµأ¬Èç´ӻÄÎßδÔø¿ÑÖεÄÍÁµØØ×ȡÄÇÀïËùÉúµÄÁãÂäµÄÄÁ²ݣ¬ËùÐèÀͶ¯ºͷÑÓã¬һ¶¨·dz£µĴó¡£ÕâÑù£¬Èç¹ûÉüÐó·ÅÄÁÓÚÒѾ­¿ÑÖεÄÍÁµأ¬Æä¼۸ñÒѲ»¹»³¥¸¶¸õزú²ݵķÑÓã¬ÄÇĩ·¢¾ÇËÇÑø£¬ÄÁ²ݵÄØ×ȡ°áÔˣ¬ҪÔö¼ÓÏ൱µÄÀͶ¯ºͷÑÓã¬Æä¼۸ñ±ض¨¸ü²»¹»³¥¸¶²ú²ݵķÑÓá£ÔÚÕâÖÖÇéÐÎÏ£¬ÏëÉè¾ÇËÇÑø¸û×÷Ëù±ØÐèµÄÉüÐó£¬ÉÐÎÞËùν£¬ÈôҪ¶àÑø£¬¾öÎÞÀûÈó¿ÉÑԡ£µ«Èç¹ûֻËÇÑø¸û×÷Ëù±ØÐèµÄÉüÐó£¬ÔòËùµ÷ÊÁϣ¬¾ö²»¹»¹©¸ø¿ɸûÍÁµصÄȫ²¿£¬ʹÆ䲻¶ϱ£³ÖÁ¼ºÃ״̬¡£·ÊÁϼȲ»¹»¹©¸øȫ²¿ũµأ¬ũÃñ×ÔȻ»á¼ð×îÓÐÀû×î±㵱£¬¼´×î·áÈĶøλÓÚũ¼ÒͥԺ¸½½üµÄÍÁµأ¬½øÐÐʩ·ʣ¬½á¹û£¬ȫ²¿ũµØÖУ¬³£±£³ÖÁ¼ºøû×÷״̬µģ¬¾͵¥ÊÇһ²¿·ÖÍÁµأ¬¶øÆäÓà´󲿷ÖÍÁµأ¬ÔòΩÓÐÈÎÆä»ÄÎߣ¬ÖÁ¶಻¹ýÈÎÆäÉú²úÈô¸Éñ¤ÈõС²ݣ¬Ëƹ¶ÑÓÉÙÐíÑÙÑٴý±еÄÉüÐóµIJÐÉú¡£ËùÑøµÄÉüÐó£¬ÓëÍÁµØÍêȫ¼ÓÈë¸û×÷ËùÐèµÄÊý¶î±Ƚϣ¬ËäÏÓ̫É٣¬µ«ÓëÍÁµØʵ¼ʲú³öµÄÄÁ²ݱȽϣ¬ȴÓÖÍùÍùÏÓÆä¹ý¶ࡣÕâ»ÄÎߵصÄһ²¿·֣¬ÔÚÕâÑù¼ÌÐø·ÅÄÁÁùÆßÄêº󣬿ÉÄܼÓÒԿÑÖΣ¬ҲÐí¿ɲú³öһÁ½¼¾´ÖÁӵÄÑàÂó»òÆäËû´ÖÁӵĹÈÀࡣ¹ý´ËÒÔÍù£¬ÔòµØÁ¦Ïûºľ»¾¡£¬ÓÖÐë»ظ´ÒÔǰµÄÐݸû·ÅÄÁ״̬¡£ÓÚÊǣ¬Óֽø¶ø¿ÑÖÎÆäËû²¿·֣¬ÕâЩпѵأ¬Ҳ²ú³öһÁ½¼¾´ÖÁӹÈÎÒԺóҲµØÁ¦ºĽߣ¬»ظ´Ðݸûԭ״¡£ËոñÀ¼ÔÚδÓëӢ¸ñÀ¼ºϲ¢ÒÔǰ£¬Æäµ͵Øһ´øµÄÍÁµأ¬´ó¶¼ÔÚÕⷽʽϾ­Ӫ¡£µ±ʱÄܹ»²»¶Ͽ¿·ÊÁ϶øά³ÖÁ¼ºÃ״̬µÄÍÁµأ¬³£³£½öռȫũµØÈý·Ö֮һÉõÖÁËķÖ֮һ£¬ÓÐʱ£¬ÉõÇҲ»µ½Îå·Ö֮һ¡¢Áù·Ö֮һ¡£ÆäÓàÍÁµأ¬ÔòȫÎ޷ÊÁϿÉʩ£»²»¹ýÆäÖл¹ÓÐÈô¸ɲ¿·֣¬ϵÒÀÉÏÊö·½ʽ£¬°¤´οÑÖΣ¬°¤´ÎÐݸû¡£ËùÒԣ¬ÔÚËոñÀ¼£¬±¾¿ɸû×÷µÄӦºÃÍÁµأ¬ÒàÒòÒÀÕմËÖַ½ʽ¾­Ӫ£¬ÒÔÖÂÆäÉú²ú¶î±ÈÆäÉú²úÁ¦ËùÄÜÉú²úµĵ͵öࡣ´ËÖ־­Ӫ·½ʽ£¬µ±ȻÊDz»Àûµġ£µ«ËոñÀ¼Ôںϲ¢ÒÔǰ£¬ËÆÒòÉüÐó¹ýÓڵÍÁ®£¬²»µò»²Éȡ´ËÖֲ»Àûµľ­Ӫ·½ʽ¡£ÖÁÓÚÉüÐó´ó´óÌڹó֮º󣬸ùú´󲿷ֵط½£¬ºÎÒÔÒÀȻÑØÓþɷ¨£¬ÄÇÊÇÒòΪÔÚÈô¸ɵط½¡£ÈËÃñÓÞÃÁ¾ÐÄà¹Åϰ£¬¶øÔڴó¶àÊýµط½£¬ÓÖÓÉÓÚÊÂÀí֮×ÔȻ£¬²»Èݼ´ʱ»ò¼±ËٲÉÓÃÓÅÁ¼·½·¨¡£ÆäÖÐÕϰ­£¬¿ɴó±ðΪ¶þ£ºµÚһ£¬×âµØÈËƶÀ§£¬»¹²¨ÓÐ×㹻ʱ¼äÀ´ȡµÃ×㹻µÄÉüÐó£¬ʹËûÃÇÄܸüÍêȫµظû×÷ÆäÍÁµء£ËûÃÇ×ÊÁ¦ÓÐÏޣ¬ÉüÐóÌڹó£¬ËÇÑø¸ü¶àÉüÐóËä¶ÔËûÃÇÓÐÀû£¬µ«ҲʹËûÃÇÄÑÓڶ๺¡£µڶþ£¬×Ýʹ×âµØÈ˾ßÓд˵È×ÊÁ¦£¬¶øÄÁ²ݵصıÙÖΣ¬Òà·Çһõí¿ɼ¸¡£×Ü֮£¬ÉüÐóÔö¼ӺÍÍÁµظÄÁ¼ÕâÁ½Õߣ¬ÊÆÐëͬʱ½øÐУ¬²»ÄܷÖÏȺó¡£ÉüÐóûÓÐÔö¼ӣ¬ÍÁµرãÎ޷¨¸Ľø£»ÍÁµØҪ²»ÊǴó´ó¸Ľø£¬ÉüÐóÓֲ»»áÏÔÖøÔö¼ӣ¬ÒòΪ²»´ó´ó¸ĽøÍÁµأ¬¾Ͳ»ÄÜά³ִó´óÔö¼ӵÄÉüÐó¡£ÏóÕâÖָï¹Êͼйý³ÌÖеÄ×ÔȻÕϰ­£¬·ÇÓг¤ʱÆڵÄÇÚÃã½ÚԼ£¬ÄÇÊÇÎ޷¨²ù³ýµġ£Ïֽ񣬾ɷ½ʽËäÔÚÖð½¥˥Â䣬µ«Ҫ¹úÄڸ÷µØȫÅ̷ϳý£¬¿ÖÅ»¹Ҫ¾­¹ý°ëÊÀ¼ͻòһÊÀ¼͵Äʱ¼䡣ËոñÀ¼´ÓÓëӢ¸ñÀ¼ºϲ¢Ëùµõ½µÄһÇÐÉÌҵÀûÒ棬ҲÐíֻÉüÐó¼۸ñÌڹóΪ×î´óÀûÒ档ÉüÐóµÄÌڹ󣬲»µ«Ìá¸ßÁ˸ߵØһ´øµزúµļÛֵ£¬ͬʱ£¬ÓֳÉΪµ͵Øһ´ø¸ĽøµÄÖ÷ҪԭÒò¡£ @@ -625,7 +625,7 @@ ¡¡¡¡²»ÂÛÈκιú¼ң¬±ØÐëÒÀÈËÁ¦Éú²úµÄһÇÐÍÁµØÉú²úÎï¼۸ñ£¬ҪÊDz»×ãÒԳ¥»¹ÍÁµصĸÄò¯·ÑÓü°¸û×÷·ÑÓ㬸ùúµÄÍÁµأ¬¾ö²»»áÍêȫÓÃÀ´¸û×÷£¬Íêȫµõ½¸ÄÁ¼¡£Ҫʹȫ¹úÍÁµØÍêȫÓÃÓڸûÖֺ͵õ½¸ÄÁ¼£¬¸÷ÖÖÉú²úÎïµļ۸񣬵Úһ£¬Ҫ×㹻֧¸¶Á¼ºùÈÌïµĵØ×⣬ÒòΪÆäËû´󲿷ָûµصĵØ×⣬¶¼ÊӹÈÌïµØ˰ΪתÒƣ»µڶþ£¬ҪÄܶÔũ¼ÒËù¸¶µÄÀͶ¯ºͷÑÓ㬸øÓëͬÁ¼ºùÈÌïͨ³£ËùÌṩµÄһÑùºõı¨³ꡣ»»ÑÔ֮£¬ũ¼ұØÐëÓÉÕâ¼۸ñ£¬ȡ»ØÆä×ʱ¾£¬²¢»ñµÃ×ʱ¾µÄÆÕͨÀûÈ󡣸÷ÖÖÉú²úÎï¼۸ñµÄÉÏÕǣ¬ÏÔȻ±ØÐëÏÈÓÚÉú²úÕâ¸÷ÖÖÉú²úÎïµÄÍÁµصĸÄÁ¼¡£µÃÀûÊÇһÇиÄÁ¼µÄĿµģ¬¸ÄÁ¼µıØȻ½á¹ûÈçΪËðʧ£¬¼´²»µÃνΪ¸ÄÁ¼¡£µ«ÈçÓɸÄÁ¼¶øÉú²úµÄÎïƷ¼۸񣬲»×㲹³¥¸ÄÁ¼µķÑÓã¬ÄÇĩ£¬¸ÄÁ¼µĽá¹û£¬¾ͱØȻÊÇËðʧ¡£Òò´ˣ¬ȫ¹úÍÁµصĸÄÁ¼Óë¸û×÷£¬ÈçȷΪһÇй«¹²ÀûÒæÖеÄ×î´óÀûÒ棬ÔòÕâһÀàԭÉú²úÎï¼۸ñµÄÉÏÕǣ¬¾Ͳ»ÄÜÊÓΪ¹«¹²Ôֻö£¬¶øӦÊÓΪ×î´óµĹ«¹²ÀûÒæµıØÐëµÄÏÈÇýºͰéËæÎ ¡¡¡¡ÉÏÊöһÇÐԭÉú²úÎïµÄÃûÒå¼۸ñ»ò»õ±Ҽ۸ñµÄÉÏÕǣ¬²¢·ÇÒø¼ÛÏÂÂ䵼á¹û£¬¶øÊÇÕâЩ²úÎï×ÔÉíÕæʵ¼۸ñÉÏÕǵĽá¹û¡£ÕâЩÉú²úÎﲻµ«ֵ¸ü´óµÄÒøÁ¿£¬¶øÇÒֵ±ÈÒÔǰ¶àµÄÀͶ¯Á¿ºÍʳƷÁ¿¡£ËüÃÇÉÏÊмÈÐè·Ñȥ¸ü¶àµÄÀͶ¯Á¿ºÍʳƷÁ¿£¬Òò´ËÉÏÊÐ֮ºó£¬ËüÃǴú±í¸ü¶àµÄÀͶ¯Á¿ºÍʳƷÁ¿£¬»òÕß˵£¬ÔڼÛֵÉϵÈÓڸü¶àµÄÀͶ¯Á¿ºÍʳƷÁ¿¡£ -¡¡¡¡µÚÈýÀà +¡¡¡¡µÚÈýÀà ¡¡¡¡µÚÈýÀ༴×îºóһÀàԭÉú²úÎïµļ۸ñ£¬Ëæ×ŸÄÁ¼³̶ȵÄÔö½ø¶ø×ÔȻµØÉÏÕǡ£ÈËÀàÇÚÀͶÔÔö¼Ӵ˵ȲúÎïËùÊյÄʵЧ£¬»òΪÓÐÏޣ¬»òΪ²»ȷ¶¨¡£Òò´ˣ¬ÕâÀàԭÉú²úÎïµÄÕæʵ¼۸ñ£¬ËäÓÐËæ¸ÄÁ¼µĽø²½¶øÉÏÉýµÄ×ÔȻÇ÷Êƣ¬µ«ÓÐʱÉõ»ò»áÏÂÂ䣬ÓÐʱÔڸ÷²»ͬʱ´ú£¬»á¼ÌÐøͬһ״̬£¬ÓÐʱÓֻáÔÚͬһʱÆÚÀï»ò¶à»òÉٵØÉÏÉý£¬ÊÓËù·¢ÉúµIJ»ͬµÄż·¢Ê¼þʹÈËÀàÇÚÀ͵ÄŬÁ¦ÔڸòúÎïµÄÔö²úÉÏËùȡµõijɾ͵ĴóС¶ø²»ͬ¡£ ¡¡¡¡ijЩԭÉú²úÎïµÄÉú²ú£¬ÊÓËûÖֲúÎïµÄÉú²úΪתÒơ£Òò֮£¬һ¹úËùÄÜÌṩµÄǰһÀà²úÎïÁ¿£¬±ØȻÊÜËüËùÄÜÌṩµĺóһÀà²úÎïÁ¿µÄ֧Å䡣ÀýÈ磬һ¹úµÄÑòë»òƤ¸ïµÄÁ¿£¬±ØÊܸùúËùά³ֵÄţÑòͷÊýµÄ֧Å䣻ËüËùÄÜά³ֵÄţÑòͷÊý£¬ÓֱØȻÊܸùú¸ÄÁ¼״¿ö¼°ũҵÐÔÖʵÄ֧Å䡣 ¡¡¡¡ҲÐíÓÐÈË˵£¬ÔڸĽøµĹý³ÌÖУ¬ʹţÑòÈâ¼۸ñÖð½¥Ìá¸ߵÄԭÒò£¬ҲͬÑù»áʹë¸ïµļ۸񣬰´¼¸ºõÏàͬµıÈÀý¶øÌá¸ߡ£Èç¹ûÔڽøÐиÄÁ¼µijõÆڣ¬ë¸ïÊг¡ºͼÒÐóÄÚÊг¡£¬ͬÑù¾ÖÏÞÓÚÏÁխ·¶Χ£¬ÔòÉÏÃæËù˵£¬ҲÐí»á³ÉΪÊÂʵ¡£¿ÉÊǣ¬ÕâÁ½ÕߵÄÊг¡·¶Χ£¬ͨ³£ÊǼ«²»Ïàͬµġ£ @@ -648,7 +648,7 @@ ¡¡¡¡¾Íһ¹ú½ðÒøÁ¿ȡ¾öÓÚÉÏÊöÁ½Çé¿öµĺóһÇé¿ö£¨ÒԽðÒø¹©¸øÊÀ½çÉ̳¡µĸ÷¿óɽµķÊñ¤Çé¿ö£©À´˵£¬½ðÒøµÄÕæʵ¼۸񣬻»ÑÔ֮£¬ËüÃÇËùÄܹºÂòËùÄܽ»»»µÄÀͶ¯Á¿ºÍʳƷÁ¿£¬±ذ´ÕÕÄǿóɽ·áÈÄƶñ¤Çé¿öµıÈÀý¶ø»ò¶à»òÉٵØÉý½µ¡£ ¡¡¡¡µ«ºÜÃ÷Ïԣ¬ÔÚһ¶¨ʱÆÚÄÚÒԽðÒø¹©¸øÊÀ½çµĿóɽ£¬¾¿¾¹ÊǷáÈ쬻òÊÇƶ񤣬ÓëһÌض¨¹ú¼ҵIJúҵ״̬´óµÖûÓкεȹØϵ£¬¶øÇÒÓëһ°ãÊÀ½çµIJúҵ״̬£¬ËƺõҲûÓкεȱØȻµĹØϵ¡£¹ÌȻ£¬Ôڼ¼ÒÕÓëóÒ×Öð½¥ÏòÊÀ½ç¸ü¹ãµĵØÃæÀ©չ£¬¶ø¿óɽµÄ̽Ë÷ҲËæ×ÅÏò¸ü¹ãµĵØÃæÀ©´óµij¡ºϣ¬Ð¿óɽ·¢ÏֵĻú»ᣬ±رÈÆä̽Ë÷ֻÏÞÓڱȽÏÏÁխµØÇøµÄʱºòÀ´µô󡣵«Ôھɿóɽ½¥´ξ򾡵Äʱºò£¬Äܷñ·¢ÏÖпóɽÊǼ«ÎްÑÎյÄÊ£¬¾ø·ÇÈËÀ༼ÇɺÍÇÚÀÍËùÄܱ£֤¡£²»ÊÇʵ¼ʷ¢Ï֣¬²»ÊDzɾò³ɹ¦£¬²»ÄÜȷ¶¨Ð¿óɽµļÛֵ£¬ÉõÖÁ²»ÄÜȷ¶¨Ð¿óɽµĴæÔڡ£һÇм£Ï󶼲»¿ɿ¿£¬ÕâÊÇÊÀËù¹«Èϵġ£ÔڽøÐÐ̽Ë÷пõɽµÄʱºò£¬ÈËÀàÇÚÀͳɹ¦»򲻳ɹ¦µĿÉÄÜÐԣ¬ËƺõͬÊÇÎÞÏ޴óµġ£½ñºóһ¶þÊÀ¼ÍÖУ¬ҲÐíÄܷ¢ÏֽÏÒÔǰ¸üΪ·áÈĵÄпóɽ£¬¶øÄÇʱºòÏÖÔÚ×î¶à²úµĿóɽ£¬½«±ÈÃÀÖ޸÷¿óɽ·¢ÏÖÒÔǰµÄÈκοóɽ»¹ҪÏԵÃƶ񤣬ÕâҲÊǿÉÄÜÓеÄÊ¡£ÎÞÂÛÕâÁ½ÕßÖÐÄÇһ¸öʵÏ֣¬¶ÔÓÚÊÀ½çµÄÕæʵ²Ƹ»ºͷ±È٣¬»»ÑÔ֮£¬¶ÔÓÚÍÁµغÍÀͶ¯µÄÄê²úÎïµÄÕæʵ¼Ûֵ£¬ÊÇÎ޹ØÖØˣµġ£ÕâÄê²úÎïµÄÃûÒå¼Ûֵ£¬»»ÑÔ֮£¬±íÃ÷»ò´ú±íÕâÄê²úÎïµĽðÒøÁ¿£¬ÎÞÒɻáÓм«´óµIJîÒ죬¿ÉÊǣ¬ÆäÕæʵ¼Ûֵ£¬»»ÑÔ֮£¬ÆäËùÄܹºÂòËùÄÜ֧ÅäµÄÕæʵÀͶ¯Á¿£¬ȴÍêȫһÑù¡£ÔÚǰһ³¡ºϣ¬һÏÈÁî¿ÉÄÜֻ´ú±í½ñÈÕһ±ãʿËùÄܴú±íµÄͬÁ¿ÀͶ¯¡£Ôںóһ³¡ºϣ¬һ±ãʿ¿ÉÄܴú±í½ñÈÕһÏÈÁîËù´ú±íµÄͬÁ¿ÀͶ¯¡£µ«ÔÚǰһ³¡ºϣ¬³ÖÓÐһÏÈÁîµÄÈˣ¬²¢²»¼ûµñȽñÈճÖÓÐһ±ãʿµÄÈ˸»£¬Ôںóһ³¡ºϣ¬³ÖÓÐһ±ãʿµÄÈˣ¬Ҳ²¢²»±ȽñÈճÖÓÐһÏÈÁîµÄÈËÇÈËÀà´Óǰһ³¡ºÏËùÏíµõÄΨһÀûÒ棬ÊǽðÒøÆ÷ÃóµĵÍÁ®Ó뷱¶࣬ÈËÀà´Ӻóһ³¡ºÏÃÉÊܵÄΨһ²»Àû£¬ֻÊÇÕâÀ಻¹ØÖØҪµķDZØÐèƷµİº¹óÓëϡÉ١£ -¡¡¡¡¹ØÓÚÒø¼۱䶯µĽáÂÛ +¡¡¡¡¹ØÓÚÒø¼۱䶯µĽáÂÛ ¡¡¡¡ËѼ¯¹ŴúÉÌƷ»õ±Ҽ۸ñµÄ×÷¼ң¬´ó¶¼ÒԹÈÎPһ°ãÎïƷ»õ±Ҽ۸ñµĵÍÁ®£¬»»ÑÔ֮£¬´ó¶¼ÒԽðÒø¼Ûֵµİº¹󣬲»½ö×÷Ϊ´˵ȽðÊô²»×ãµÄ֤¾ݣ¬¶øÇÒ×÷Ϊµ±ʱһ°ã¹ú¼Òƶ·¦ҰÂùµÄ֤¾ݡ£ÕâÖָÅÄÊǺÍÄÇÒÔһ¹ú¸»ԣÓÉÓڽðÒø·áÈġ¢һ¹úƶ·¦ÓÉÓڽðÒø²»×ãµľ­¼ÃѧÌåϵ·ֲ»¿ªµġ£¹ØÓڴËÖ־­¼ÃѧÌåϵ£¬Îҽ«ÓڵÚËÄƪ¼ÓÒԳä·ֵÄ˵Ã÷£¬Ôڴ˽öÂÛÒÔÏÂÊÂʵ£¬¼´½ðÒø¼Ûֵµİº¹󣬽ö¿É֤Ã÷ÒԴËÀà½ðÊô¹©¸øÊÀ½çÉ̳¡µĸ÷¿óɽµÄƶ񤣬¾ö²»ÄÜ֤Ã÷½ðÒø°º¹ó¹ú¼ҵÄƶÇîÓëҰÂù¡£ƶ¹ú²»ÄÜÏ󸻹ú¹ºÂòÄÇô¶àµĽðÒø£¬Ҳ²»ÄܶÔÓڽðÒø֧¸¶ÄÇô¸ߵļ۸ñ¡£ËùÒԣ¬´˵ȽðÊôµļÛֵ£¬ÔÚƶ¹ú¾ö²»»á±ȸ»¹ú¸ü¸ߡ£Öйú±ÈŷÖÞÈκιú¼Ҷ¼¸»µö࣬µ«¹ó½ðÊô¼ÛֵÔÚÖйú£¬ȴ±ÈŷÖ޸÷¹ú¸ߵöࡣ¹ÌȻ£¬ŷÖ޵IJƸ»£¬×ÔÃÀÖ޿óɽ·¢ÏÖÒÔÀ´£¬ÒѴóÓÐÔö¼ӣ¬ͬʱ½ðÒø¼ÛֵÒàÖ𽥵ÍÂ䡣µ«ÕâÖּÛֵµÄÏÂÂ䣬²¢·ÇÆðÒòÓÚŷÖÞÕæʵ²Ƹ»µÄÔö¼ӣ¬»òÆäÍÁµغÍÀͶ¯µÄÄê²úÎïµÄÔö¼ӣ¬¶øÊÇÆðÒòÓڿõ¹ÅδÓеķáÈĿóɽµÄżȻ·¢Ï֡£ŷÖ޽ðÒøÁ¿µÄÔö¼ÓÓëÖÆÔìҵ¼°ũҵµķ¢´ËäȻÊǷ¢ÉúÔڼ¸ºõͬһ¸öʱÆڣ¬µ«ÆäԭÒòȴ·dz£²»Ïàͬ£¬Á½ÕßÏ໥¼ä¼òֱûÓкεÈ×ÔȻ¹Øϵ¡£½ðÒøÁ¿µÄÔö¼ӣ¬Ê³öżȻ£¬ÓëÈκÎÉîÂǡ¢ÈκÎÕþ²ßÎ޹أ¬¶øÇÒÉîÂÇÓëÕþ²ߣ¬ÒàÎÞÄÜΪÁ¦¡£ÖÆÔìҵ¼°ũҵµķ¢´ÔòÊÇÆðÒòÓڷ⽨ÖƶȵıÀÀ£ÓëÐÂÕþ¸®µijÉÁ¢¡£ºóÕ߶ÔÓڲúҵ£¬¸øÓèÁËËüËùÐèÇóµÄΨһ½±Àø£¬¼´Ï൱±£֤Á˸÷È˵ÃÏíÊܸ÷ÈËÀͶ¯µĹûʵ¡£·⽨ÖƶÈÖÁ½ñÒÀ¾ɲдæµIJ¨À¼£¬Æäƶ·¦״¿ö²¶àºÍÃÀÖ޷¢ÏÖÒÔǰÎÞÒ졣Ȼ¶øÔڲ¨À¼£¬ҲÏóÔÚŷÖÞÆäËû¸÷µØһÑù£¬¹ÈÎïµĻõ±Ҽ۸ñÌڹóÁˣ¬½ðÒøµÄÕæʵ¼ÛֵÏÂÂäÁˡ£¿É֪Ôڲ¨À¼£¬¹ó½ðÊôҲÏóÔÚËû¹úһÑù£¬ÊýÁ¿Ôö¼ÓÁˣ¬ÆäÔö¼ӵÄÊýÁ¿£¬¾ÍÆä¶ԸùúÍÁµغÍÀͶ¯µÄÄê²úÎïµıÈÀýÀ´˵£¬ҲºÍËû¹úÏàËơ£¿ÉÊǣ¬ÕâÖֹó½ðÊôµÄÔö¼ӣ¬Ëƺõ²¢²»ÔøÔö¼ӸùúµÄÄê²úÎ²»ÔøÔö½øÆäÖÆÔìҵ¼°ũҵ£¬Ҳ²»Ôø¸ÄÉÆÆä¾ÓÃñµľ³Óö¡£Î÷°àÑÀºÍÆÏÌÑÑÀ¶þ¹ú£¬ÔÚÃÀÖÞӵÓÐÐí¶à¿óɽ£¬µ«ÔÚŷÖ޸÷¹úÖУ¬¿ÖÅÂËüÃÇÊǽö´ÎÓڲ¨À¼µÄÁ½¸ö×îƶ¹ú¼ÒÁˡ£¿ÉÊǣ¬¹ó½ðÊôµļÛֵ£¬ÔÚÎ÷°àÑÀºÍÆÏÌÑÑÀ£¬ȴһ¶¨±ÈŷÖÞÆäËûµط½µͣ¬ÒòΪ£¬¹ó½ðÊôÊÇÕâÁ½¹úÔËÍùŷÖ޸÷µص쬲»µ«Ҫ¸½¼ÓÔ˷Ѻͱ£Ïշѣ¬¶øÒÑÓÉÓÚÕâÁ½¹ú½ðÒøµÄÊä³ö£¬»򱻽ûֹ»òÐè½ÉÄÉÖØ˰£¬»¹Ҫ¸¶×ß˽·ÑÓá£ËùÒԣ¬¾ÍÆä¶ÔÍÁµغÍÀͶ¯µÄÄê²úÎïµıÈÀý˵£¬¹ó½ðÊôÁ¿ÔÚÕâÁ½¹úһ¶¨±ÈŷÖÞÆäËû¸÷¹ú¶ࡣȻ¶ø£¬ËüÃÇȴ±ÈŷÖÞÆäËû¸÷¹úƶ¡£ËüÃÇËäÒѷϳýÁ˷⽨Öƶȣ¬µ«´úÐ˵IJ¢²»ÊǸüºõÄÖƶȡ£ ¡¡¡¡ÕýÈç½ðÒø¼ÛֵµĵÍÂ䣬²¢²»ÄÜ֤Ã÷һ¹úµĸ»ԣ·±È٣¬½ðÒø¼ÛֵµÄÌڹ󣬻»ÑÔ֮£¬¹ÈÎPһ°ãÎïƷ»õ±Ҽ۸ñµĵÍÂ䣬Ҳ²»ÄÜ֤Ã÷һ¹úµÄƶÀ§¡¢ҰÂù¡£ ¡¡¡¡²»¹ý£¬һ¹úµÄƶÀ§¡¢ҰÂù£¬Ë䲻ÄÜȡ֤ÓڹÈÎïµĵͼú£¬ȴ¿Éʮ֮°˾Åȡ֤ÓڼÒÐ󡢼ÒÇݡ¢һÇÐҰÉúÄñÊÞÕâÀණÎ÷µĻõ±Ҽ۸ñ±ȹÈÎïµĻõ±Ҽ۸ñÀ´µõÍÕâ¸öÊÂʵ¡£ÕâÀණÎ÷»õ±Ҽ۸ñµĵͼú£¬Ã÷ÏԵØ֤Ã÷ÁËÒÔÏÂÁ½¸öÊÂʵ£ºµÚһ£¬´˵ȲúÎïµķ±¶à³̶ȣ¬´óÓڹÈÎ¿É֪ÐóÄÁ»ĵØËùռµÄÃæ»ý£¬½ϹÈÎï¸ûµشóµöࣻµڶþ£¬ÐóÄÁ»ĵصĵؼۣ¬½ϹÈÎï¸ûµصĵؼ۵ÍÁ®£¬¿É֪¸ùú´󲿷ÖÍÁµػ¹δ¼ÓÒԸû×÷º͸ÄÁ¼¡£´˶þÕß֤Ã÷£¬ÕâÖֹú¼ҵÄ×ʲƺÍÈ˿ڣ¬¶ÔÆäÍÁµØÃæ»ýËù³ֵıÈÀý£¬ÓëÆÕͨÎÄÃ÷¹ú²»ͬ£¬´Ӷø֤Ã÷ÆäÉç»á״̬ÏòÔÚÓ×Öɽ׶Ρ£×Ü֮£¬ÎÒÃÇÓÉһËһõÎïÓÈÆäÊǹÈÎïµĻõ±Ҽ۸ñµĸߵÍËùÄÜÍƶϵģ¬ֻÊÇÄÇʱºòÒԽðÒø¹©¸øÊÀ½çÉ̳¡µĸ÷¿óɽµķÊ񤣬¾ö²»ÄܾÝÒÔÍƶϸùúµÄƶ¸»¡£µ«Êǣ¬ÎÒÃǴÓijЩÖÖÀà»õÎïµĻõ±Ҽ۸ñÓëÆäËû»õÎïµĻõ±Ҽ۸ñ¶Աȵĸߵͣ¬ȴ¿ɼ¸ºõÍêȫ׼ȷµØÍƶϣ¬¸ùúÊǸ»ԣ£¬»òÊÇƶÀ§£»Æä´󲿷ÖÍÁµأ¬ÊǷñ¸ÄÁ¼£»ÆäÉç»á״̬£¬ÊǽӽüҰÂù£¬»¹ÊǽӽüÎÄÃ÷¡£ @@ -676,7 +676,7 @@ ¡¡¡¡Ӣ¸ñÀ¼ÍùʱÖÆÔì´Öë֯Ʒµķ½·¨£¬Óë½ñÈչ¤ҵÓ×ÖɹúËùÓõÄÏàͬ£¬Ëü´ó¸ÅÊÇһÖּÒͥÖÆÔìҵ£¬Æ乤×÷µĸ÷²¿·֣¬²¶àÿһ¸ö¼ÒͥµĚ°һ¸ö³ÉԱ£¬¶¼ż¶ûµ£µ±¹ý¡£µ«ËûÃÇͨ³£ֻÔÚûÓÐÆäËû¹¤×÷¿É×öʱ²Å×öÕ⹤×÷£¬Õ⹤×÷²¢²»ÊÇËûÃǴ󲿷ÖÉú»î×ÊÁÏËùÑö¸øµÄÀ´Դ¡£ÀͶ¯Õߵ±×÷¸±ҵÖƳɵÄÎïƷ£¬Æä¼۸ñ×ܱÈÆäÉú»î·ÑÍêȫ»ò´󲿷Öȡ×ʵÄÖÆƷµļ۸ñµ͵ö࣬ÄÇÊÇÎÒÃÇÔÚǰÃæÒѾ­˵¹ýµġ£ÖÁÓھ«ë֯Ʒ£¬ÄÇʱºòӢ¸ñÀ¼ÉÐÎÞÖÆÔ죬¶øÊÇÑö¸øÓÚÉÌÎñ·±ʢµĸ¥À¼µ¡£ÄÇʱº򣬸õØÖÆÔìÕâÖÖë֯ƷµÄÈˣ¬´ó¸ÅҲÏóÏÖÔÚһÑù£¬´ÓÕ⹤×÷ȡ¸øÆäȫ²¿»ò´󲿷ÖÉú»î·ѡ£´ËÍ⣬µ±ʱ¸¥À¼µÂÖÆƷ£¬ÊÇһÖÖÍâ»õ¡£¶ԹúÍõÐë½ÉÄÉÈô¸ɸ³˰£¬ÖÁÉ٣¬ÒàµýÉÄÉÍùʱͨÐеĶÖ˰ºͰõ˰¡£ÕâЩ˰´ó¸Ų»ºܸߣ¬µ±ʱŷÖ޹ú¼ҵÄÕþ²ߣ¬²»ÔÚÓÚÉè¸߹Ø˰ÒÔÏÞÖÆÍâ¹úÖÆƷÊäÈ룬ȴÄþԸ½±ÀøÉÌÈˣ¬ʹÄÜÁ®¼ÛÊäÈëºÀÉðÏԹóËùϣÇóµı¾¹ú²»ÄÜ×ÔÖƵıãÀûƷºÍÉݳÞƷ¡£ ¡¡¡¡´˵ÈÇé¿ö£¬ҲÐí¿ÉÔÚijÖ̶ֳÈÉÏ˵Ã÷£¬´ÖÖÆƷµÄÕæʵ¼۸ñ£¬Ó뾫ÖÆƷÕæʵ¼۸ñÏà±ȣ¬ºÎÒÔÎôʱԶµÍÓڽñÈա£ -¡¡¡¡±¾ÕµĽáÂÛ +¡¡¡¡±¾ÕµĽáÂÛ ¡¡¡¡ÎÒÔڴ˽«ÒÔÏÂÊöÒéÂۣ¬½áÊøÕâÈ߳¤µÄһÕ¡£¼´һÇÐÉç»á״¿öµĸÄÁ¼£¬¶¼ÓÐһÖÖÇãÏò£¬ֱ½ӻò¼ä½ÓʹÍÁµصÄÕæʵµØ×âÉÏÉý£¬ʹµØÖ÷µÄÕæʵ²Ƹ»Ôö´ó£¬ʹµØÖ÷¶ÔËûÈ˵ÄÀͶ¯»òÀͶ¯Éú²úÎïÓиü´óµĹºÂòÁ¦¡£ ¡¡¡¡¸ÄÁ¼¼°¸û×÷µÄÀ©´󣬿Éֱ½Ó̧¸ßÍÁµصÄÕæʵµØ×⡣µØÖ÷ËùµÃÄÇһ·ÝÉú²úÎ±ØȻËæȫ²¿Éú²úÎïµÄÔö¼ӶøÔö¼ӡ£ ¡¡¡¡ÍÁµØԭÉú²úÎïÖУ¬ÓÐһ²¿·ֵÄÕæʵ¼۸ñµÄÌÚԱ£¬×î³õÊÇÍÁµظÄÁ¼º͸û×÷À©´óµĽá¹û£¬½Ó×ţ¬ÓÖÊǴٽøÍÁµظÄÁ¼º͸û×÷À©´óµÄԭÒò¡£ÀýÈ磬ÉüÐó¼۸ñµÄÌڹ󣬻áֱ½ӶøÇÒÒԸü´ó±ÈÀý£¬Ìá¸ßÍÁµصØ×⡣µØÉÏËùµò¿·ֵÄÕæʵ¼Ûֵ£¬»»ÑÔ֮£¬Ëû֧ÅäËûÈËÀͶ¯µÄÄÜÁ¦£¬»áËæÍÁµØÉú²úÎïÕæʵ¼ÛֵµÄÌá¸߶øÔö´󣬶øËûÔÚȫ²¿Éú²úÎïÖÐËù·ֵıÈÀýÒà»áËæ֮Ôö´ó¡£ÕâÖÖÉú²úÎÔÚÆäÕæʵ¼ÛֵÔö¸ßÒԺ󣬲¢²»ÐèҪʹÓñÈÒÔǰ¶àµÄÀͶ¯Á¿À´ȡµÃËü¡£Òò´ˣ¬ÔÚÍÁµØȫ²¿Éú²úÎïÖУ¬ֻÐëÒÔһ½ÏС²¿·ÖÀ´²¹³¥¹ÍÓÃÀͶ¯µÄ×ʱ¾¼°֧¸¶ÆÕͨµÄÀûÈó¡£ÓÉÊǾÍÓнϴ󲿷ֹ鵨Ö÷ËùÓС£ @@ -690,14 +690,14 @@ -µڶþƪ ÂÛ×ʲƵÄÐÔÖʼ°ÆäÐî»ýºÍÓÃ; -ÐòÂÛ +µڶþƪ ÂÛ×ʲƵÄÐÔÖʼ°ÆäÐî»ýºÍÓÃ; +ÐòÂÛ ¡¡¡¡ÔÚÎ޷ֹ¤£¬Éٽ»»»£¬×ԼºËùÐèҪµÄһÇÐÎïƷ¶¼ÓÉ×Լº¹©¸øµÄԭʼÉç»á״̬Ï£¬Ҫ¾­ӪÉç»áÊÂҵ£¬ÎÞÐëԤ´¢×ʲơ£ÈËÈ˶¼Á¦ͼÒÀ¿¿×ԼºµÄÀͶ¯À´Âú×ã×ÔÉíËæʱ·¢ÉúµÄÐèҪ¡£¶öÁ˱㵽ɭÁÖȥ´òÁԣ»Ò·þ»µÁˣ¬±ã°þÊÞÀàµÄƤ¸ïÀ´´©£»·¿ÎÝÆÆÁˣ¬±ã¾ͽü·¥ȡÊ÷֦²ÝƤ£¬¾¡ÆäËùÄܣ¬¼ÓÒÔÐÞÈס£ ¡¡¡¡Ôڳ¹µ×ʵÐзֹ¤֮ºó£¬һÈË×ԼºÀͶ¯µIJúÎ±ã½öÄÜÂú×ã×ÔÉíËæʱ·¢ÉúµÄÐèҪµļ«С²¿·֡£ÆäËû´󲿷ÖÐèҪ£¬±صÃÑöÀµËûÈËÀͶ¯µIJúÎïÀ´¹©¸ø¡£ÕâÖֲúÎï±ØÓɹºÂò¶øµá£¹ºÂòµÄÊֶμ´ÊÇËû×ԼºµIJúÎ»òÕß˵£¬Ëû×Լº²úÎïµļ۸񡣵«ÔڹºÂòÒÔǰ£¬²»½ö×ԼºÀͶ¯µIJúÎïҪÒѾ­×÷³ɣ¬»¹ҪÒѾ­Âôµô£¬ËùÒÔÖÁÉÙÔÚÕâÁ½¼þÊÂÇéÄܹ»°쵽ÒÔǰ£¬±ØÐëÏÈÔÚij¸öµط½´¢Óи÷ɫ¸÷ÑùµĻõÎ×ãÒÔά³ÖËûµÄÉú»²¢Ìṩ²ÄÁϺ͹¤¾߹©ËûʹÓá£ÀýÈç֯½³ÔÚ֯ÎïÉÐδ×÷³ɡ¢ÉÐδÂôµôÒÔǰ£¬Ҫ²»ÊÇÔÚ×ԼºÊÖÖлòËûÈËÊÖÖÐÓÐËùÐî»ý£¬×ãÒÔά³ÖËûµÄÉú»²¢¸øËûÌṩ²ÄÁϺ͹¤¾ߣ¬Ëû¾Í֯²»³öÈκζ«Î÷¡£ºÜÃ÷Ïԣ¬ÕâÖִ¢Ðî·ÇÔÚËû¿ªʼ´ÓÊÂÕâÏîְҵºܾÃÒÔǰÍê³ɲ»¿ɡ£ ¡¡¡¡°´ÕÕÊÂÎïµı¾Ðԣ¬×ʲƵÄÐî»ý£¬±ØÐëÔڷֹ¤ÒÔǰ¡£ԤÐîµÄ×ʲÆÓú·áԣ£¬·ֹ¤¾ÍÄܰ´±ÈÀýµØÓúϸÃܣ¬¶ø·ֹ¤ԽϸÃܣ¬ͬһÊýÁ¿¹¤ÈËËùÄܼӹ¤µIJÄÁϣ¬¾ÍÄܰ´¸ü´óµıÈÀýÔö¼ӡ£ÿ¸ö¹¤ÈËËùµ£ÈεIJÙ×÷£¬¼Ƚ¥Ç÷¼򵥣¬±ãÓи÷ÖÖлúе·¢Ã÷ʹ²Ù×÷¸üΪ¼ò±ãѸË١£ËùÒԣ¬µ±·ֹ¤½ø²½Á˵Äʱº򣬹ÍÓù¤ÈËÊýĿ²»±䣬Ëù±ØÐëԤÏȴ¢ÓеÄʳÎ﹩Ӧ£¬ҪºÍÔڷֹ¤ûÓÐÕâÑù½ø²½ʱÏàͬ£»¶ø±ØÐëԤÏȴ¢ÐîµIJÄÁϺ͹¤¾ߣ¬ȴҪ±ÈÔڷֹ¤ûÓÐÕâÑù½ø²½ʱËùÐèҪµÄÀ´µöࡣ¿öÇң¬һÖÖÐÐҵ·ֹ¤ԽÊÇϸÃܣ¬ËüµĹ¤ÈËÈËÊýÍùÍùԽÊÇÔö¼ӣ»¸üȷÇеØ˵£¬ʹËûÃǷֹ¤Äܹ»ԽÀ´ԽϸÃܵ쬾ÍÊÇËûÃÇÈËÊýµÄÔö¼ӡ£ ¡¡¡¡ҪÕâÑù´ó´ó¸ĽøÀͶ¯Éú²úÁ¦£¬ԤÐî×ʲÆÊǾø¶ԱØҪµġ£¶øÕâÖÖÐî»ý£¬Òà×ÔȻ»ᵼÖÂÕâÖָĽø¡£Ͷ×ʹÍÓÃÀͶ¯µÄÈˣ¬×ÔȻϣÍûͶ×ʷ½·¨Äܹ»¾¡Á¿²ú³ö×î´óÁ¿µIJúƷ¡£ËùÒԣ¬¶Թ¤ÈËְÎñµķÖÅ䣬±ØŬÁ¦ÆÚÆäÊʵ±£»ÔÚÄܹ»·¢Ã÷»ò¹ºÂòµÄÏ޶ÈÄڣ¬ËûËù±¸ÖõĻúе£¬±ØŬÁ¦ÆÚÆ侫Á¼¡£µ«ÔÚÕâÁ½·½Ã棬ËûµÄÄÜÁ¦ÔõÑù£¬ÍùÍùҪ¿´ËûÄÜÓжàÉÙ×ʲƣ¬¿´ËûÄܹͶàÉٹ¤Èˡ£ËùÒԣ¬ÔÚÿһ¹ú¼ÒÀ²»½ö²úҵµÄÊýÁ¿Ëæ×žٰì²úҵµÄ×ʲƵÄÔö¼ӶøÔö¼ӣ¬¶øÇң¬ÓÉÓÚ×ʲÆÔö¼ӵĽá¹û£¬ͬÁ¿²úҵËùÄÜÉú²úµIJúƷÒà»á´óÔö¡£ ¡¡¡¡ÎÒÔڱ¾ƪËùҪ˵Ã÷µÄÊǣº×ʲƵÄÐÔÖÊÔõÑù£¬×ʲÆÐî»ý¶Ը÷ÖÖ×ʱ¾µÄӰÏìÔõÑù£»×ʱ¾ÓÃ;²»ͬ£¬ÆäӰÏìÓÖÊÇÔõÑù£¿±¾ƪ¹²·ÖÎåÕ¡£ÎÒÃÇ֪µÀ£¬һ¸öÈ˻òһ¸ö´óÉç»áµÄ×ʲƣ¬×ÔȻ»á·ֳɼ¸¸ö²¿Ãţ¬ËùÒÔÔڵÚһÕ£¬ÎÒҪ˵Ã÷ʲôÊÇÕâЩ²¿Ãš£ÎÒÃǰѻõ±ҿ´×öÉç»á×Ü×ʲƵÄһ¸öÌØÊⲿÃţ¬ËùֻÔڵڶþÕ£¬ÎÒҪÌÖÂۻõ±ҵÄÐÔÖʺÍ×÷Ó᣻ýΪ×ʱ¾µÄ×ʲƣ¬»òÓÉËùÓÐÕß×ԼºʹÓ㬻ò´ûÓëËûÈËʹÓã¬ËùÒÔÔڵÚÈýÕº͵ÚËÄÕ£¬ÎÒҪ¾ÍÕâÁ½ÖÖÇéÐμÓÒÔÌÖÂۡ£µÚÎåÕÂËùҪÌÖÂ۵ģ¬ÊÇ×ʱ¾µIJ»ͬÓÃ;£¬¶ԹúÃñ²úҵÁ¿¼°ÍÁµغÍÀͶ¯µÄÄê²úÎïÁ¿£¬»áֱ½ӷ¢Éúʲô²»ͬµÄӰÏ졣 -µÚһÕ¡¡ÂÛ×ʲƵĻ®·Ö +µÚһÕ¡¡ÂÛ×ʲƵĻ®·Ö ¡¡¡¡һÈËËùÓеÄ×ʲƣ¬Èô½ö×ãά³ÖËûÊýÈջòÊýÖܵÄÉú»ËûºÜÉٻáÏë´ÓÕâ±Ê×ʲÆȡµÃÊÕÈ롣Ëû½«É÷֮ÓÖÉ÷µØÏû·ÑËü£¬²¢ÇÒϣÍûÔÚÓÃÍêËü֮ǰ£¬ÄÜÒÀ¿¿×ÔÉíµÄÀͶ¯£¬ȡµÃһЩ¶«Î÷À´×÷²¹³䡣ÔÚÕⳡºϣ¬ËûµÄÊÕÈëÍêȫÀ´×ÔËûµÄÀͶ¯¡£¸÷¹úƶÇîÀͶ¯Õߴ󲿷־ÍÊǹýÕâÖÖÉú» ¡¡¡¡ËûËùÓеÄ×ʲƣ¬Èç×㹻ά³ÖËûÊýÔ»òÊýÄêµÄÉú»Ëû×ÔȻϣÍûÕâ±Ê×ʲÆÖÐÓÐһ´󲿷ֿÉÒÔÌṩÊÕÈ룻Ëû½«½ö±£ÁôһÊʵ±²¿·֣¬×÷ΪδÔøȡµÃÊÕÈëÒÔǰµÄÏû·ѣ¬ÒÔά³ÖËûµÄÉú»ËûµÄȫ²¿×ʲÆÓÚÊǷֳÉÁ½²¿·֡£ËûϣÍû´ÓÒÔȡµÃÊÕÈëµIJ¿·֣¬³ÆΪ×ʱ¾¡£Áíһ²¿·֣¬Ôò¹©ĿǰÏû·ѣ¬ÆäÖаüº¬ÈýÏÎ÷£º£¨һ£©ԭΪÕâһĿµĶø±£ÁôµÄÄDz¿·Ö×ʲƣ»£¨¶þ£©Ö𽥵ÃÀ´µÄÊÕÈ룬²»ÂÛÀ´ԴÈçºΣ»£¨Èý£©ÓÃÒÔÉÏÁ½ÏîÓÚÒÔǰÂò½øÀ´µ«ÖÁ½ñÉÐδÓÃÍêµÄÎïƷ£¬È类·þ¡¢¼Ҿߵȵȡ£ΪĿǰµÄÏû·Ѷø±£ÁôµÄ×ʲƣ¬»ò°üº¬ÈýÏî֮һ£¬»òÈýÏî֮¶þ£¬»òÈýÏîȫÓС£ ¡¡¡¡¶ÔͶ×ÊÕßÌṩÊÕÈë»òÀûÈóµÄ×ʱ¾£¬ÓÐÁ½ÖÖʹÓ÷½·¨¡£ @@ -725,7 +725,7 @@ -µڶþÕ¡¡ÂÛ×÷ΪÉç»á×Ü×ʲƵÄһ²¿ÃŻò×÷Ϊά³ֹúÃñ×ʱ¾µķÑÓõĻõ±Ò +µڶþÕ¡¡ÂÛ×÷ΪÉç»á×Ü×ʲƵÄһ²¿ÃŻò×÷Ϊά³ֹúÃñ×ʱ¾µķÑÓõĻõ±Ò ¡¡¡¡ÔڵÚһƪ£¬ÎÒÔøָ³ö£ºÒòΪÉÌƷµÄÉú²úºÍÉÏÊУ¬Ôø¾­ʹÓÃÀͶ¯¡¢×ʱ¾ÓëÍÁµأ¬ËùÒԴ󲿷ÖÉÌƷµļ۸񶼷ֽâΪÈý¸ö²¿·֣¬ÆäһΪÀͶ¯¹¤×ʣ¬Æä¶þΪ×ʱ¾ÀûÈ󣬯äÈýΪÍÁµصØ×⡣³ÏȻ£¬ÊÂʵÉÏÓÐЩÉÌƷµļ۸񣬽öÓÉÁ½²¿·ֹ¹³ɣ¬¼´ÀͶ¯¹¤×ʺÍ×ʱ¾ÀûÈó£»ÉõÖÁ»¹Óм«ÉÙÊýÉÌƷµļ۸񣬵¥µ¥ÓÉһ²¿·ֹ¹³ɣ¬¼´ÀͶ¯¹¤×ʡ£µ«ÎÞÂÛÈçºΣ¬ÉÌƷ¼۸ñÖչé³ÉΪÉÏÊöÄÇÈý¸ö²¿·ÖÖеÄһ¸ö»òȫ²¿¡£²»¹éÓڵØ×æҲ²»¹éÓڹ¤×ʵIJ¿·֣¬±عéÓÚÀûÈó¡£ ¡¡¡¡¾͸÷ÌØÊâÉÌƷ·ֱðÂÛÊö£¬ÇéÐÎÒÑÈçÉÏÊö£¬¾͹¹³Éȫ¹úÍÁµغÍÀͶ¯µÄÄê²úÎïµÄȫ²¿ÉÌƷ¶ø×ÜÀ¨ÂÛÊö£¬ÇéÐÎÒà±ØÈç´ˡ£ÎÒÔڵÚһƪ˵¹ý£ºһ¹úÄê²úÎïµÄ×ܼ۸ñ»ò×ܽ»»À¼Ûֵ£¬Òà±طֽâΪÕâÈý¸ö²¿·ֶø·ÖÅäÓڹúÄڸ÷¾ÓÃ񡣲»ÊÇ×÷ΪÀͶ¯¹¤×ʣ¬²»ÊÇ×÷Ϊ×ʱ¾ÀûÈ󣬾ÍÊÇ×÷ΪÍÁµصØ×⡣ ¡¡¡¡һ¹úÍÁµغÍÀͶ¯µÄÄê²úÎïµÄȫ²¿¼Ûֵ£¬ËäÈç´˷ֹé¸÷¾ÓÃ񣬶ø³ÉΪ¸÷¾ÓÃñµÄÊÕÈ룬µ«Êǣ¬ºÃÏó¸öÈË˽ÓÐÍÁµصĵØ×â¿ÉÒԷÖΪ×ܵØ×âºʹ¿µØ×âһÑù£¬¹úÄÚȫ²¿¾ÓÃñµÄÊÕÈ룬Òà¿ɷÖΪ×ÜÊÕÈëºʹ¿ÊÕÈ롣 @@ -830,7 +830,7 @@ -µÚÈýÕ ÂÛ×ʱ¾»ýÀ۲¢ÂÛÉú²úÐԺͷÇÉú²úÐÔÀͶ¯ +µÚÈýÕ ÂÛ×ʱ¾»ýÀ۲¢ÂÛÉú²úÐԺͷÇÉú²úÐÔÀͶ¯ ¡¡¡¡ÓÐһÖÖÀͶ¯£¬¼ÓÔÚÎïÉϣ¬ÄÜÔö¼ÓÎïµļÛֵ£»ÁíһÖÖÀͶ¯£¬ȴ²»Äܹ»¡£ǰÕßÒò¿ÉÉú²ú¼Ûֵ£¬¿ɳÆΪÉú²úÐÔÀͶ¯£¬ºóÕ߿ɳÆΪ·ÇÉú²úÐÔÀͶ¯¡£ÖÆÔìҵ¹¤È˵ÄÀͶ¯£¬ͨ³£»á°Ñά³Ö×ÔÉíÉú»îËùÐèµļÛֵÓëÌṩ¹ÍÖ÷ÀûÈóµļÛֵ£¬¼ÓÔÚËù¼ӹ¤µÄԭ²ÄÁϵļÛֵÉϡ£·´֮£¬¼ÒÆ͵ÄÀͶ¯£¬ȴ²»ÄÜÔö¼Óʲô¼Ûֵ¡£ÖÆÔìҵ¹¤È˵Ť×ʣ¬ËäÓɹÍÖ÷µ渶£¬µ«ÊÂʵÉÏÂÄÖ÷ºÁÎÞËù·ѡ£ÖÆÔìҵ¹¤È˰ÑÀͶ¯ͶÔÚÎïÉϣ¬ÎïµļÛֵ±ãÔö¼ӡ£ÕâÑùÔö¼ӵļÛֵ£¬ͨ³£¿ÉÒԲ¹»¹¹¤×ʵļÛֵ£¬²¢ÌṩÀûÈ󡣼ÒÆ͵Äά³ַѣ¬ȴÊDz»ÄÜÊջصġ£¹ÍÓÃÐí¶๤Èˣ¬ÊÇÖ¸»µķ½·¨£¬ά³ÖÐí¶à¼ÒÆͣ¬ÊÇÖÂƶµÄ;¾¶¡£µ«¼ÒÆ͵ÄÀͶ¯£¬ÒàÓÐËü±¾ÉíµļÛֵ£¬Ïó¹¤È˵ÄÀͶ¯һÑù£¬Ӧµõ½±¨³ꡣ²»¹ý£¬ÖÆÔìҵ¹¤È˵ÄÀͶ¯£¬¿ÉÒԹ̶¨²¢ÇÒʵÏÖÔÚÌØÊâÉÌƷ»ò¿ÉÂôÉÌƷÉϣ¬¿ÉÒԾ­ÀúһЩʱº򣬲»»áËæÉúËæÃð¡£ÄÇËƺõÊǰÑһ²¿·ÖÀͶ¯Öü´æÆðÀ´£¬ÔڱØҪʱÔÙÌá³öÀ´ʹÓá£ÄÇÖÖÎïƷ£¬»òÕß˵ÄÇÖÖÎïƷµļ۸ñ£¬ÈպóÔڱØҪʱ»¹¿ÉÓÃÒԹÍÓúÍԭΪÉú²úÕâÎïƷ¶øͶϵÄÀͶ¯Á¿ÏàµȵÄÀͶ¯Á¿¡£·´֮£¬¼ÒÆ͵ÄÀͶ¯£¬ȴ²»¹̶¨Ò಻ʵÏÖÔÚÌØÊâÎïƷ»ò¿ÉÂôÉÌƷÉϡ£¼ÒÆ͵ÄÀͶ¯£¬ËæÉúËæÃð£¬Ҫ°ÑËüµļÛֵ±£´æÆðÀ´£¬¹©Èպó¹ÍÓõÈÁ¿ÀͶ¯֮Óã¬ÊǺÜÀ§Äѵġ£ ¡¡¡¡ÓÐЩÉç»áÉϵȽ׼¶ÈËʿµÄÀͶ¯£¬ºͼÒÆ͵ÄÀͶ¯һÑù£¬²»Éú²ú¼Ûֵ£¬¼Ȳ»¹̶¨»òʵÏÖÔÚÄ;ÃÎïƷ»ò¿ÉÂôÉÌƷÉϣ¬Ò಻Äܱ£²ØÆðÀ´¹©Èպó¹ÍÓõÈÁ¿ÀͶ¯֮Óá£ÀýÈ磬¾ýÖ÷ÒԼ°ËûµĹÙÀôºͺ£½¾ü£¬¶¼ÊDz»Éú²úµÄÀͶ¯Õߡ£ËûÃÇÊǹ«Æͣ¬¹²Éú¼ÆÓÉËûÈËÀͶ¯Äê²úÎïµÄһ²¿·ÖÀ´ά³֡£ËûÃǵÄְÎñ£¬ÎÞÂÛÊÇÔõÑù¸߹ó£¬ÔõÑùÓÐÓã¬ÔõÑù±ØҪ£¬µ«Öվ¿ÊÇËæÉúËæÃ𣬲»Äܱ£ÁôÆðÀ´¹©ÈպóȡµÃͬÁ¿ְÎñ֮Óá£ËûÃÇÖÎÀí¹úÊ£¬º´ÎÀ¹ú¼ң¬¹¦À͵±Ȼ²»С£¬µ«½ñÄêµÄÖ쨣¬Â򲻵½Ã÷ÄêµÄÖ쨣»½ñÄêµİ²ȫ£¬Â򲻵½Ã÷Äêµİ²ȫ¡£ÔÚÕâһÀàÖУ¬µ±Ȼ°üº¬×Ÿ÷ÖÖְҵ£¬ÓÐЩÊǺÜ×ð¹óºÜÖØҪµģ¬ÓÐЩȴ¿É˵ÊÇ×ÖØҪµġ£ǰÕßÈçÄÁʦ¡¢ÂÉʦ¡¢ҽʦ¡¢ÎÄÈˣ»ºóÕßÈçÑÝԱ¡¢¸èÊ֡¢Î赸¼ҡ£ÔÚÕâһÀàÀͶ¯ÖУ¬¼´ʹÊÇ×îµͼ¶µģ¬ÒàÓÐÈô¸ɼÛֵ£¬֧ÅäÕâÖÖÀͶ¯¼ÛֵµÄԭÔ򣬾ÍÊÇ֧ÅäËùÓÐÆäËûÀͶ¯¼ÛֵµÄԭÔ򡣵«ÕâһÀàÀͶ¯ÖУ¬¾ÍÁ¬×î×ð¹óµģ¬Ò಻ÄÜÉú²úʲô¶«Î÷¹©Èպó¹ºÂòµÈÁ¿ÀͶ¯֮Óá£ÏóÑÝԱµĶ԰ף¬Ð۱ç¼ҵÄÑÝ˵£¬ÒôÀּҵĸ質£¬ËûÃÇÕâһ°ãÈ˵Ť×÷£¬¶¼ÊÇËæÉúËæÃðµġ£ ¡¡¡¡Éú²úÐÔÀͶ¯Õߡ¢·ÇÉú²úÐÔÀͶ¯ÕßÒԼ°²»ÀͶ¯Õߣ¬ͬÑùÑöʳÓÚÍÁµغÍÀͶ¯µÄÄê²úÎÕâÉú²úÎïµÄÊýÁ¿ÎÞÂÛÔõô´󣬾ö²»ÊÇÎÞÇîµģ¬¶øÊÇÓÐÏ޵ġ£Òò´ˣ¬ÓÃÒÔά³ַÇÉú²úÐÔÈËÊֵIJ¿·ÖÓú´ó£¬ÓÃÒÔά³ÖÉú²úÐÔÈËÊֵIJ¿·ֱØÓúС£¬´Ӷø´ÎÄêÉú²úÎïÒà±ØÓúÉ١£·´֮£¬ÓÃÒÔά³ַÇÉú²úÐÔÈËÊֵIJ¿·ÖÓúС£¬ÓÃÒÔά³ÖÉú²úÐÔÈËÊֵIJ¿·ֱØÓú´󣬴Ӷø´ÎÄêÉú²úÎïÒà±ØÓú¶ࡣ³ýÁËÍÁµØÉÏÌìȻÉú²úµÄÎïƷ£¬һÇÐÄê²úÎﶼÊÇÉú²úÐÔÀͶ¯µĽá¹û¡£ @@ -874,7 +874,7 @@ -µÚËÄÕ Â۴û³öȡϢµÄ×ʲÆ +µÚËÄÕ Â۴û³öȡϢµÄ×ʲÆ ¡¡¡¡´û³öȡϢµÄ×ʲƣ¬³ö½èÈË×ÜÊǿ´×÷×ʱ¾¡£³ö½èÈË×ÜϣÍû½è´ûÆÚÂú£¬×ʲƸ´¹éÓڼº£¬¶øÔڽèÆÚÖнèÓÃÈËÒòÔøʹÓÃÕâ×ʲƣ¬Ҫ¸¶ËûÄê×âÈô¸ɡ£ÕâÖÖ×ʲƣ¬ÔڽèÓÃÈËÊÖÀ¿ÉÓÃ×÷×ʱ¾£¬Òà¿ÉÓÃ×÷Áô¹©ĿǰÏû·ѵÄ×ʲơ£Èç¹ûÓÃ×÷×ʱ¾£¬¾ÍÊÇÓÃÀ´ά³ÖÉú²úÐÔÀͶ¯Õߣ¬¿ÉÔÙÉú²ú¼Ûֵ£¬²¢ÌṩÀûÈó¡£ÔÚÕⳡºϣ¬ËûÎÞÐë¸îÈûòÇÖʴÈκÎÆäËûÊÕÈëµÄ×ÊԴ±ãÄܳ¥»¹¸Ã×ʱ¾¼°ÆäÀûϢ¡£Èç¹ûÓÃ×÷ĿǰÏû·ѵÄ×ʲƣ¬Ëû¾ͳÉΪÀ˷ÑÕߣ¬Ëû¶áȥÁËά³ÖÇÚÀͽ׼¶µĻù½ð£¬À´ά³ÖÓζè½׼¶¡£ÔÚÕⳡºϣ¬³ý·ÇËûÇÖʴijÖÖÊÕÈëµÄ×ÊԴÈçµزú»òµØ×⣬Ëû¾ÍÎ޷¨³¥»¹×ʱ¾£¬֧¸¶ÀûϢ¡£ ¡¡¡¡´û³öȡϢµÄ×ʲƣ¬ÎÞÒÉÓÐʱ¼æÓÃÔÚÕâÁ½ÖÖÓÃ;Éϣ¬µ«ÓÃÔÚǰһÓÃ;µĽ϶࣬ÓÃÔںóһÓÃ;µĽÏÉ١£½èǮ»ӻôµÄÈˣ¬ÊÆÄѾÃÁ¢£¬½èǮ¸øËûµÄÈˣ¬³£Ҫºó»ÚÓ޲»¿ɼ°¡£³ýÁËÖØÀûÅ̰þÕߣ¬ÏóÕâÑùµĴû½裬¶Ô˫·½¶¼ºÁÎÞÀûÒ档Éç»áÉϹÌȻÄÑÃâÓÐÕâÑù´û½èµÄʼþ·¢Éú£¬µ«ÒòÈ˸÷×ÔÀû£¬ËùÒԣ¬¿ÉÒÔÏàÐţ¬Ëü²»»áÏóÎÒÃÇËùÏëÏóµÄÄÇÑù³£ÓС£ÈκαȽϽ÷É÷µĸ»Èˣ¬Èç¹ûÎÊËûԸÒԴ󲿷Ö×ʲƴû¸øıÀûµÄÈËÄأ¬»òÊÇÀ˷ѵÄÈËÄأ¬ËûÌýÁˣ¬ÅÂֻ»ᷢЦ£¬ЦÄã»áÌá³öÕâÑù²»³ÉÎÊÌâµÄÎÊÌ⡣½èÓÃÈËËäȻ²»ÊÇÊÀÉϺÜÓÐÃûµĽڼó¼ң¬µ«¼´ÔÚËûÃÇ֮ÖУ¬½ڼóµÄÖձرÈÉݳ޵Ķàµö࣬ÇÚÀ͵ÄÖձرÈÓζèµĶàµöࡣ ¡¡¡¡½è¿îͽ¹©»ӻôµģ¬ֻÓÐÏçÉð¡£ÏçÉð½è¿ͨ³£ÓвƲúΪµÖѺ£¬ÆäËù½è¿³£·ÇÓÃÓÚÓÐÀûµÄÓÃ;¡£µ«¾ÍÁ¬ÏçÉ𣬽èǮÒಢ·Çȫ¹©À˷ѡ£Ëù½èµÄǮ£¬³£³£ÔçÔÚδ½è֮ǰ¾ÍÒÑÓù⡣ËûÃÇÈճ£ÏíÓõĶ«Î÷£¬¶àÏòÉ̵êÀϰåÉ޹º£¬ÍùÍùÉ޵úܶ࣬±ØÐë³öϢ½è¿îÀ´»¹ÇåÕËĿ£¬ÏçÉðÃÇËù½èµÄ×ʱ¾ʵÊDz¹³¥É̵êÀϰåµÄ×ʱ¾£¬ËûÃÇËùÊյĵØ×⣬²»¹»³¥»¹£¬ËùÒÔÏò±ðÈ˽è¿îÀ´³¥»¹¡£ÕâʱËû½èǮ²¢²»ÊÇΪÁËҪ»¨·ѣ¬ֻÊÇΪÁËҪ²¹³¥ÏÈǰÒѾ­»¨µôÁ˵Ä×ʱ¾¡£ @@ -895,7 +895,7 @@ -µÚÎåÕ ÂÛ×ʱ¾µĸ÷ÖÖÓÃ; +µÚÎåÕ ÂÛ×ʱ¾µĸ÷ÖÖÓÃ; ¡¡¡¡һÇÐ×ʱ¾£¬Ë䶼ÓÃÒÔά³ÖÉú²úÐÔÀͶ¯£¬µ«µÈÁ¿×ʱ¾ËùÄÜÍƶ¯µÄÉú²úÐÔÀͶ¯Á¿£¬ËæÓÃ;µIJ»ͬ¶ø¼«²»Ïàͬ£¬´Ӷø¶Ôһ¹úÍÁµغÍÀͶ¯µÄÄê²úÎïËùÄÜÔö¼ӵļÛֵ£¬Ò༫²»Ïàͬ¡£ ¡¡¡¡×ʱ¾ÓÐËÄÖֲ»ͬÓÃ;¡£µÚһ£¬ÓÃÒԻñȡÉç»áÉÏÿÄêËùÐëʹÓÃËùÐëÏû·ѵÄԭÉú²úÎµڶþ£¬ÓÃÒÔÖÆÔìԭÉú²úÎʹÊÊÓÚÑÛǰµÄʹÓúÍÏû·ѣ»µÚÈý£¬ÓÃÒÔÔËÊäԭÉú²úÎï»òÖÆÔìƷ£¬´ÓÓÐÓàµĵط½ÔËÍùȱ·¦µĵط½£»µÚËģ¬ÓÃÒԷÖɢһ¶¨²¿·ֵÄԭÉú²úÎï»òÖÆÔìƷ£¬ʹ³ÉΪ½ÏСµIJ¿·֣¬ÊÊÓÚÐèҪÕߵÄÁÙʱÐèҪ¡£µÚһÖÖÓ÷¨ÊÇũҵ¼ҡ¢¿óҵ¼ҡ¢Óæҵ¼ҵÄÓ÷¨£»µڶþÖÖÓ÷¨ÊÇÖÆÔìÕߵÄÓ÷¨£»µÚÈýÖÖÓ÷¨ÊÇÅú·¢ÉÌÈ˵ÄÓ÷¨£»µÚËÄÖÖÓ÷¨ÊÇÁãÊÛÉÌÈ˵ÄÓ÷¨¡£ÎÒÒÔΪ£¬ÕâËÄÖÖÓ÷¨£¬ÒѾ­°üÀ¨ÁËһÇÐͶ×ʵķ½·¨¡£ ¡¡¡¡ÕâËÄÖÖͶ×ʷ½·¨£¬ÓÐÏ໥ÃÜÇйØϵ£¬ÉÙÁËһÖ֣¬ÆäËû²»ÄܶÀ´棬¼´ʹ¶À´棬Ò಻Äܷ¢չ¡£ΪȫÉç»áµĸ£Àû¼ƣ¬ÒàÊÇȱһ²»¿ɡ£ @@ -933,8 +933,8 @@ -µÚÈýƪ¡¡Â۲»ͬ¹ú¼ÒÖвƸ»µIJ»ͬ·¢չ -µÚһÕ¡¡Â۲Ƹ»µÄ×ÔȻµķ¢չ +µÚÈýƪ¡¡Â۲»ͬ¹ú¼ÒÖвƸ»µIJ»ͬ·¢չ +µÚһÕ¡¡Â۲Ƹ»µÄ×ÔȻµķ¢չ ¡¡¡¡ÎÄÃ÷Éç»áµÄÖØҪÉÌҵ£¬¾ÍÊǶ¼ÊоÓÃñÓëũ´å¾ÓÃñͨÉ̡£ÕâÖÖÉÌҵ£¬ÓеÄÊÇÒÔԭÉú²úÎïÓëÖÆÔìƷֱ½ӽ»»»£¬ÓеÄÊÇÒԻõ±һòֽ±Ò×÷ý½齻»»¡£ũ´åÒÔÉú»î×ÊÁϼ°ÖÆÔì²ÄÁϹ©¸ø¶¼ÊУ¬¶¼ÊÐÔòÒÔһ²¿·ÖÖÆÔìƷ¹©¸øũ´å¾ÓÃ񡣲»ÔÙÉú²úÒ಻ÄÜÔÙÉú²úÉú»î×ÊÁϵͼÊУ¬Æäȫ²¿²Ƹ»ºÍȫ²¿Éú»î×ÊÁ϶¼¿É˵ÊǵÃ×Ôũ´塣µ«ÎÒÃDz»Ҫ¸ù¾ÝÕâµ㣬¾Í˵¶¼ÊеÄÀûµü´ÊÇũ´åµÄËðʧ¡£ËûÃÇÓÐÏ໥µÄÀûº¦¹Øϵ¡£ÕâÀ·ֹ¤µĽá¹û£¬ÏóÆäËû·½Ãæµķֹ¤һÑù£¬¶Ô˫·½´Óʸ÷ÖÖְҵµľÓÃñ¶¼ÓÐÀûÒ档ũ´å¾ÓÃñ£¬ÓëÆäÇ××ÔÀͶ¯À´ÖÆÔìËûÃÇÐèҪµÄÖÆÔìƷ£¬ÎÞÄþ×÷ÕâÖֽ»»»£¬ÒòΪÓÉÕâÖֽ»»»£¬ËûÃǿÉÓýÏСÁ¿µÄ×ÔÉíÀͶ¯Éú²úÎﹺµýϴóÁ¿µÄÖÆÔìƷ¡£¶¼ÊÐÊÇũ´åʣÓà²úÎïµÄÊг¡£¬ũÃñÓò»Á˵Ķ«Î÷£¬¾ÍÄõ½¶¼ÊÐȥ½»»»ËûÃÇÐèҪµÄÎïƷ¡£¶¼ÊеľÓÃñÓú¶࣬Æä¾ÓÃñµÄÊÕÈëÓú´ó£¬ũ´åʣÓà²úÎïµÄÊг¡Óú¹ãÀ«¡£ÕâÖÖÊг¡Óú¹ãÀ«£¬¶Թã´óÈËÃñÓúÓÐÀû¡£ÔÚÀ붼ÊÐһÁ¨Éú²úµĹÈÎÓëÔÚÀ붼ÊжþʮÁ¨Éú²úµĹÈÎÔÚÊÐÉϵÄÊۼ۶¼һÑù¡£µ«ºóÕßËùµõÄÊۼۣ¬һ°ãµØ˵£¬²»µ«Ҫ²¹³¥ÆäÉú²ú·ÑÓúÍÉÏÊзÑÓ㬶øÇÒҪ¶Ôũҵ¼ÒÌṩũҵµÄÆÕͨÀûÈó¡£ËùÒԣ¬¶¼Êи½½üµÄũҵ¼Һ͸û×÷Õߣ¬´ӹÈÎïÊۼÛËùµõ쬲»½öÊÇũҵµÄÆÕͨÀûÈ󣬶øÇҰüÀ¨×ÔԶµØÔËÀ´³öÊ۵ĹÈÎïµÄÔ˷Ñȫ²¿¼Ûֵ¡£´ËÍ⣬ÔÚËûÃǹºÂòµĶ«Î÷µÄÂò¼ÛÉϣ¬ËûÃǻ¹½ÚʡÕâЩ¶«Î÷µÄԶ;Ô˷ѵÄȫ²¿¼Ûֵ¡£ÊÔһ±Ƚ϶¼Êи½½ü¸÷ũ´åºÍԶÀ붼Êи÷ũ´åµĸû×÷ÊÂҵ£¬Äã¾Í֪µÀ¶¼ÊÐÉÌҵÊÇÔõÑùÓÐÀûÓÚũ´塣¾ÍÁ¬ËùÓÐÐû´«óÒײî¶îµĸ÷ÖÖÃý˵£¬ҲûÓÐһÖָÒÍý˵³ÇÏçͨÉ̶ԳÇÊлò¶ÔÏç´åÓÐËðµġ£ ¡¡¡¡°´ÕÕÊÂÎïµı¾Ðԣ¬Éú»î×ÊÁϱØÏÈÓڱãÀûƷºÍÉݳÞƷ£¬ËùÒԣ¬Éú²úǰÕߵIJúҵ£¬Òà±ØÏÈÓÚÉú²úºóÕߵIJúҵ¡£ÌṩÉú»î×ÊÁϵÄũ´åµĸûÖֺ͸ÄÁ¼£¬±ØÏÈÓÚֻÌṩÉݳÞƷºͱãÀûƷµĶ¼ÊеÄÔö¼ӡ£Ïç´å¾ÓÃñÐëÏÈά³Ö×Լº£¬²ÅֻʣÓà²úÎïά³ֶ¼ÊеľÓÃñ¡£ËùÒԣ¬ҪÏÈÔö¼Óũ´å²úÎïµÄʣÓ࣬²Å̸µÃÉÏÔöÉ趼ÊС£µ«Òò¶¼ÊÐÉú»î×ÊÁϣ¬²»һ¶¨ҪÑö¸øÓڸ½½üµÄũ´壬ÉõÖÁ²»һ¶¨ҪÑö¸øÓڹúÄڵÄũ´壬¶ø¿ÉÒԴÓԶ·½ÔËÀ´£¬ËùÒԣ¬ÕâËäȻ²»ÊÇһ°ãԭÔòµÄÀýÍ⣬ȴʹ¸÷ʱ´ú¸÷¹ú¼ҽø²½·±ÈٵĹý³̣¬Òò¶øÓÐËù²îÒ졣 ¡¡¡¡ũ´åÏÈÓڶ¼ÊеÄÊÂ̬£¬Ôڴó¶àÊý¹ú¼ң¬ÊÇÓÉÐèҪÆȳɵ쬵«ÔÚËùÓйú¼ң¬ÓÖÓÐÈËÀàÌìÐԴÙÆäʵÏ֡£ֻҪÈËΪÖƶȲ»ѹÒÖÈËÀàÌìÐԣ¬ÔòÔھ³ÄÚÍÁµØÉÐδÍêȫ¿ª¿ѸÄÁ¼ÒÔǰ£¬¶¼ÊеÄÔöÉ裬¾ö²»Äܳ¬¹ýũ´åµĸû×÷Çé¿öº͸ÄÁ¼Çé¿öËùÄÜ֧³ֵÄÏ޶ȡ£Èç¹ûÀûÈóÏàµȻ򼸺õÏàµȣ¬¶àÊýÈ˱ØÄþԸͶ×ÊÒԸÄÁ¼ÍÁµؿª¿ÑÍÁµأ¬²»ԸͶ×ÊÓڹ¤ҵ¼°¹úÍâóÒס£ͶÔÚÍÁµØÉϵÄ×ʱ¾£¬¿ÉÊܵ½Ͷ×ÊÈË×ÔÉí¸üֱ½ӵļà²죻ÓëÉÌÈË×ʱ¾±Ƚϣ¬ËûµIJƲú²»Ò×ÔâÓöÒâÍ⡣ÉÌÈ˵IJƲú£¬²»µ«³£Ðëð¿ñ·ç¾ÞÀ˵ÄΣÏգ¬¶øÇÒÓÉÓÚÉÌÈ˳£Ðë¶ԷçË×Çé¿ö¶¼²»Ò×ÊìϰµÄԶ½¼µÄÈ˴û¸øÐÅÓ㬻¹ҪðÈËÀàµÄÓ޴ÀÓ벻ÕýÐÐΪÕâЩ¸ü²»¿ɿ¿ÒòËصÄΣÏա£·´֮£¬µØÖ÷µÄ×ʱ¾£¬ȴ¿ɹ̶¨ÔÚÍÁµظÄÁ¼ÎïÉϣ¬¿Éֻ˵ÊǾ¡ÁËÈËÊÂËù×öµõ½µİ²ȫ¡£¶øÇң¬Ïç´å·羰µÄÃÀÀö£¬Ïç´åÉú»îµÄÓä¿죬Ïç´åÐÄÀíµÄÌ񾲣¬ÒԼ°Ïç´åËùÌṩµĶÀÁ¢Ðԣ¬ֻҪÕâ¶ÀÁ¢ÐԲ»Êܵ½ÈËΪµÄÆȺ¦µĻ°£¬ÕâЩʵ¾ßÓÐÎüÒýÿһ¸öÈ˵ľ޴ó÷ÈÁ¦¡£¸û×÷ÍÁµؼÈΪÈ˵ÄԭʼĿ±꣬ËùÒԣ¬ÔÚÓÐÈËÀà´æÔڵÄһÇн׶Σ¬Õâ¸öԭʼµÄְҵ½«ΪÈËÀàËùÓÀԶ°®Ôᣠ@@ -947,7 +947,7 @@ -µڶþÕ¡¡ÂÛÂÞÂíµ۹ú±ÀÀ£ºóũҵÔÚŷÖ޾É״̬ÏÂËùÊܵ½µÄ×èÒÖ +µڶþÕ¡¡ÂÛÂÞÂíµ۹ú±ÀÀ£ºóũҵÔÚŷÖ޾É״̬ÏÂËùÊܵ½µÄ×èÒÖ ¡¡¡¡×ÔÈնúÂüÃñ×åºÍÈûÎ÷ÑÇÃñ×åÇÖÈÅÂÞÂíµ۹úÎ÷²¿ÒÔÀ´£¬ŷÖÞÆðÁËһ¸ö´ó±ä¸¸ú×ÅÕâ¸ö´ó±ä¸﷢ÉúµÄÊǣ¬ŷÖÞÈÅÈÁÁ˺ü¸°ÙÄꡣҰÂùÃñ×å¶Ôԭ¾ÓÃñµÄÂӶáºÍÆȺ¦£¬ÖжÏÁ˳ÇÏç¼äµÄóÒס£³ÇÊж¼³ÉÁ˻ÄÐ棬Ïç´åÒàÎÞÈ˸û×÷¡£ÔÚÂÞÂíµ۹úͳÖÎʱºܸ»ԣµÄÎ÷ŷ£¬һ±ä¶øΪ¼«ƶ·¦£¬¼«ҰÂù¡£ÔڽÓÁ¬²»¶ϵÄÈÅÈÁÖУ¬ÄÇЩÃñ×åµÄͷ×ӣ¬ռÓлò´۶áÁËÕâЩ¹ú¼ҵĴ󲿷ÖÍÁµء£ÓÐÈ˸û×÷µÄÍÁµØËäȻ²»¶࣬µ«ҪÕÒһ¿éûÓÐËùÓÐÖ÷µÄÍÁµأ¬ȴ²»¿ÉÄܡ£һÇÐÍÁµض¼±»Í̲¢Áˣ»ÆäÖд󲿷ÖÊDZ»ÉÙÊý´óµØÖ÷ËùÍ̲¢¡£ ¡¡¡¡×î³õÍ̲¢»ĵصÄΣº¦Ëäºܴ󣬵«ÓпÉÄÜֻ²»¹ýÊÇÔÝʱµÄΣº¦¡£ÕâЩÍÁµر¾¿Éͨ¹ý¼̳лò·ָ°ÑËüÃDzðС¡£µ«³¤Äгм̷¨£¬ʹ´óÍÁµز»ÄÜÒò³м̶ø²ðС£»ÏÞËü̳з¨ÓÖʹ´óÍÁµز»ÄÜÒò·ָî¶ø²ðС¡£ ¡¡¡¡Èç¹ûÎÒÃǰÑÍÁµؿ´×÷ֻÊÇıÉúÇóÀֵÄÊֶΣ¬ºͶ¯²úһÑù£¬ÄÇĩ£¬°´ÕÕ×ÔȻ³м̷¨£¬µ±Ȼ»á°ÑÍÁµØÏ󶯲úһÑù£¬·ָø¼ÒÄÚËùÓеĶùŮ¡£ÒòΪÿһ¸ö¶ùٵÄÉú¼ƣ¬¶¼ΪÀϸ¸ËùͬÑù¹ØÐġ£ÂÞÂíÈ˾ÍÊDzÉÐÐÕâÖÖ×ÔȻ³м̷¨¡£ËûÃDz»·ֱð³¤Óף¬²»·ֱðÄÐŮ£¬ֻҪÊÇ×ԼºÑøµģ¬¾ͿÉÒԳмÌ×ԼºµÄÍÁµء£ËûÃǴ¦·ÖÍÁµصķ½·¨£¬ºÍÎÒÃÇÏÖÔڴ¦·ֶ¯²úµķ½·¨һÑù¡£²»¹ý£¬µ±ÍÁµر»¿´×÷²»µ¥ÊÇıÉúµÄÊֶΣ¬¶øÊÇȨÁ¦ǿÈõËùϵµÄʱº򣬾ͱ»ÈÏΪÒԲ»·ָî¶øר¹éÓÚһÈ˱ȽÏÊʵ±¡£ÔÚÄÇЩ²»°²¾¸µÄʱº򣬴óµØÖ÷ͬʱ¶¼ÊÇС¹ó×塣Ëûµĵ軧£¬±ãÊÇËûµÄÁ¥Êô¡£ËûÊÇËûÃǵIJÃÅй٣¬ÊÇËûÃǺÍƽʱ½ڵÄÁ¢·¨Õߣ¬ÒàÊÇËûÃÇսÕùʱ½ڵÄÁ쵼Èˡ£Ëû¿ÉÈÎÒâ½øÐÐսÕù£¬¶ÔÁڹú×÷ս£¬ÓÐʱ¶ԹúÍõ×÷ս¡£ÔÚÕâÖÖ״̬Ï£¬һ¸öµزúÊǷñ°²ȫ£¬ÆäÖоÓÃñÓÐÎޱ£Õϣ¬¶¼ȡ¾öÓÚËüµĴóС¡£°Ñһ¸öµزú·ֲð£¬ÎÞÒì°ÑËüÆƻµ£¬»»ÑÔ֮£¬ÎÞÒì°ÑËü²ð¿ªÀ´£¬ʹ¸÷²¿·ֶ¼ÈÝÒ×ÊÜǿÁڵÄÇÖʴÍ̲¢¡£ËùÒԣ¬ÊÊӦ×ŵ±ʱÕâÖÖÇé¿ö£¬Ôڵزú³м̷½Ã棬³¤Äгм̷¨£¬ÂýÂý£¨²»ÊÇÁ¢¼´£©ʢÐÐÆðÀ´¡£ΪÁËͬһÀíÓɣ¬¾ýÖ÷¹úͨ³£ÒàÓɳ¤ÄÐһÈ˳м̡£ËäȻ×î³õ²¢²»×ÜÊÇÈç´ˡ£Ϊ¾ýÖ÷¹úµİ²ȫÓëȨÁ¦¼ƣ¬¹úÍÁÄþ¿ɲ»¼ӷÖÁѡ¢Äþ¿ÉÔÚÖî¶ùŮÖУ¬ѡÔñһ¸öÈËÀ´µ¥¶À³м̡£µ«ѡÔñ˭Äأ¬ÄÇÑùÖØҪµÄһ¼þÊ£¬µ±ȻҪ֣Öع涨һ¸öÆÕͨ¹æÀý£¬ʹѡÔ񲻰´¸öÈË×ÊÖʺûµÕâ¸ö²»´ó¿ɿ¿µÄÇø±𣬶ø°´ijÖÖÃ÷°׵ġ¢Î޿ÉÕùÂ۵ıê׼¡£ÔÚͬһ¼Òͥµĸ÷¶ùŮÖУ¬¡¢³ýÁËÐԱðÓëÄêÁ䣬ÔÙûÓÐÆäËûÎ޿ÉÕùÂ۵ÄÇø±ðÁˡ£¸ù¾Ýһ°㾭Ñ飬ÄÐÐԱÈŮÐԺ㬶øÔÚÆäËûһÇÐÌõ¼þÏàµȵij¡ºϣ¬Ä곤µıÈÄêÓ׵ĺᣳ¤ÄгмÌȨ£¬¾ÍÕâÑù³ÉÁ¢Áˡ£¶øËùνֱϵ¼̳У¬Òà¾ʹӴ˷¢ÉúÁˡ£ @@ -972,7 +972,7 @@ -µÚÈýÕ¡¡ÂÛÂÞÂíµ۹ú±ÀÀ£ºó¶¼ÊеIJªÐËÓë½ø²½ +µÚÈýÕ¡¡ÂÛÂÞÂíµ۹ú±ÀÀ£ºó¶¼ÊеIJªÐËÓë½ø²½ ¡¡¡¡ÂÞÂíµ۹ú±ÀÀ£º󣬶¼ÊоÓÃñµľ³¿ö£¬²¢²»±Èũ´å¾ÓÃñºá£²»¹ý£¬ÄÇʱºò¶¼ÊÐÖеľÓÃ񣬺͹ŴúϣÀ°¹²º͹ú¡¢Òâ´óÀû¹²º͹úÄڵľÓÃñ´ó²»Ïàͬ¡£ÔÚÕâµȹŴú¹²º͹úÄڣ¬µØÖ÷ռ¾ÓÃñÖеĶàÊý£¬ËûÃǷÖռ¹«µأ¬¶¼¾õµ÷¿ÎÝÅþÁ¬£¬»·ÒÔΧǽ£¬±ãÓڹ²ͬ·ÀÓù¡£µ«ÔÚÂÞÂíµ۹ú±ÀÀ£º󣬵ØÖ÷´ó¶¼ɢ¾ÓÓڸ÷×ÔÁìµصijÇկÄڣ¬סÔڸ÷×Եĵèũ¼°ÊôÃñÖм䡣ÊÐÕòÉϵľÓÃ񣬴ó¶¼ÊÇÉÌÈ˺ͼ¼¹¤¡£ËûÃǵĴ¦¾³ÎÞÒìÓÚÁ¥Òۣ¬»ò½üËÆÓÚÁ¥Òۡ£¹Åʱ¸÷ÏÜÕÂËù¸³ÓëŷÖ޸÷ÖØҪ¶¼ÊоÓÃñµÄȨÀû£¬³ä·Ö֤Ã÷ÁËËûÃÇÔÚδȡµÃÕâЩȨÀûÒÔǰµÄÉú»îÇé¿ö¡£ÕâЩÏÜÕ£¬׼Ðí¶¼ÊÐÈËÃ񣬵Úһ£¬¿ÉÒÔ×ÔÓɼÞŮ£¬²»±ØÁìÖ÷Ðí¿ɣ»µڶþ£¬ÔÚËûËÀºó£¬ËûµIJÆÎ¿ÉÓɶùËï³м̣¬²»ÓÉÁìÖ÷Áìȡ£»µÚÈý£¬×ÔÉíÒŲú£¬¿ÉÓÉÒÅÖö´¦·֡£ÕâÖÖȨÀûµİ䏸£¬³ä·Ö֤Ã÷ÁËÔÚδ°ä¸øǰ£¬ËûÃÇÊǺÍũ´å¸û×÷Õ߼¸ºõһÑù£¬»ò¾¹ȫȻһÑù£¬´¦Óڼúū״̬¡£ ¡¡¡¡ÕâЩÈˣ¬ÎÞÒÉÊǺÜƶÀ§ºÜϼúµģ¬ËûÃǼçÌôׯõÎ¹ýÊи°Ð棬´ÓÕâÀïÅܵ½ÄÇÀÓë½ñÈÕÀ­³µºɵ£µÄС··ÏàÀàËơ£ÄÇʱŷÖ޸÷¹ú£¬ÏóÏÖÔÚÑÇÖ޵Ä÷²÷°Õþ¸®һÑù£¬¾­³£ÔÚÕâЩÂÃÐÐÕ߾­¹ýijЩ²ÉÒأ¬¾­¹ýijЩÇÅÁº£¬¸°ÊгÃÐ棬Éè̯ÊۻõµÄʱº򣬰Ѹ³˰¼ÓÔÚËûÃǵÄÈËÉíÓë»õÎïÉϡ£ÔÚӢ¸ñÀ¼£¬ÕâЩ˰£¬½Ð×ö¹ý½ç˰¡¢¹ýÇŻú¡¢Â䵨˵¡¢̯˰¡£ÓеÄʱº򣬹úÍõÒԼ°ÔÚijЩ³¡ºÏӵÓÐÕâÏîȨÁ¦µĴóÁìÖ÷£¬ÌØÐíijЩÉÌÈˣ¬ÌرðÊÇסÔÚËûÃÇÁìµØÄڵÄÉÌÈˣ¬ÃâÄɸ÷˰¡£Òò´ˣ¬ÕâЩÉÌÈ˵ĵØλ£¬ËäÔÚÆäËû¸÷µãÓëÁ¥ÒÛÎÞÒì»ò¼«ÏàÀàËƣ¬µ«ÈԱ»³ÆΪ×ÔÓÉÉÌÈˡ£²»¹ý£¬ËûÃÇΪ±¨´𱣻¤Õߵı£»¤£¬ͨ³£ÿÄêÐëÄÉÈËͷ˰Èô¸ɡ£µ±ʱ·Ǹ¶ºñ³꣬±£»¤²»Ò׻ñµá£ËùÒԣ¬ÕâÀàÈËͷ˰¿ɿ´×÷ËûÃǶԱ£»¤ÕßÉáÆúÆäËû˰ÊÕËùÌṩµIJ¹³¥¡£ÕâÖֽ»»»Ìõ¼þµÄʵÐУ¬µ±³õֻÏÞÓڸöÈˣ¬ÆäÆÚÏ޻òÏÞÓÚÆäÈË֮Éí£¬»òƾ±£»¤Õߵĺöñ¡£Ӣ¹úÍÁµØÇåÕɲá¹ØÓڼ¸¸ö¶¼Êеĺܲ»ÍêȫµļÇÔأ¬³£³£ÌἰijijÊÐÃñΪÕâÖֱ£»¤¸÷ÄÉÈËͷ˰Èô¸ɸø¹úÍõ»ò´óÁìÖ÷¡£ÓÐʱ£¬ËüÓÖֻ¼Ç¼ÕâЩÈËËùÄɵÄ˰µÄ×ܺ͡£ ¡¡¡¡¶¼ÊоÓÃñµÄÇé¿ö£¬ÎÞÂ۵±³õÊÇÔõÑù±°¼ú£¬µ«ÓëÏç´å¸û×÷Õ߱Ƚϣ¬ËûÃÇȡµÃ×ÔÓÉÓë¶ÀÁ¢£¬ÔÚʱ¼äÉÏ×ÜҪÔçµöࡣ¶¼ÊоÓÃñµÄÈËͷ˰£¬ÊǹúÍõÊÕÈëµÄһ²¿·֣¬Õâһ²¿·ÖÊÕÈ룬¶àÓɹúÍõÖƶ¨±ȶÔÚһ¶¨ÄêÏÞÄڰü¸ø¸ÃÊг¤¹ٻòÆäËûÈËÕ÷Êա£µ«ÊÐÃñ×ԼºÒàÍùÍù¿ÉÒÔȡµÃÕâÑùµÄÐÅÓã¬À´¾­ÊÕËûÃDZ¾ÊеÄÕâÖÖ˰Êգ¬ÓÚÊǾͶÔÕâȫ²¿˰¶ÁªºϸºÔð¡£ÕâÖְü˰°취£¬¶ÔÓÚŷÖ޸÷¹ú¹úÍõµÄһ°㾭¼ã¬µ±ÊÇʮ·ÖÊÊÒ˵ģ¬ÒòΪËûÃDZ¾À´¹ßÓڰÑׯ԰ȫ²¿µÄ˰Êգ¬½»ÓÉׯ԰ȫÌåµèũ°ü°죬ʹ¶ÔÕâȫ²¿˰ÊոºÁ¬´øÔðÈΡ£µ«ÕâÖְ취£¬¶ԵèũÒàÓÐÀû¡£ËûÃǿÉÕÕ×Լºϲ»¶µķ½·¨´ÓÊ»üÕ÷£¬²¢ͨ¹ý×ԼºƸԱ֮Êֽ«˰¿îÄÉÓڹú¿⣬²»±ØÔÙÊܹúÍõÅɳöµÄÀôÒ۵ĺᱩÁˡ£ÕâÔڵ±ʱ±»ÊÓΪ¼«ÖشóµÄһ¼þÊ¡£ @@ -996,7 +996,7 @@ -µÚËÄÕ¡¡¶¼ÊÐÉÌҵ¶Ôũ´å¸ÄÁ¼µĹ±Ï× +µÚËÄÕ¡¡¶¼ÊÐÉÌҵ¶Ôũ´å¸ÄÁ¼µĹ±Ï× ¡¡¡¡¹¤ÉÌҵ¶¼ÊеÄÔö¼ÓÓ븻ԣ£¬¶ÔËùÊôũ´åµĸÄÁ¼Ó뿪·¢£¬ÓÐËù¹±Ïף¬Æ乱Ï׵Ä;¾¶ÓÐÈý¡£ ¡¡¡¡һ£»Ϊũ´åµÄԭÉú²úÎïÌṩһ¸ö¾޴ó¶ø±ãÒ׵ÄÊг¡£¬´Ӷø¹ÄÀøÁËũ´åµĿª·¢Óë½øһ²½µĸĽø¡£Êܵ½ÕâÀûÒæµģ¬²»½ö½öÊǶ¼ÊÐËùÔڵÄũ´塣·²Ó붼ÊÐͨÉ̵Äũ´壬¶¼¶àÉÙÊÜÆäʵ»ݡ£ËüÃÇΪ´˵Èũ´åµÄԭÉú²úÎï»òÖÆÔìƷ£¬ÌṩÁËÊг¡£¬½á¹û¾͹ÄÀøÁËÆä²úҵºͲúҵµĸĽø¡£µ±Ȼ£¬¿¿½ü¶¼ÊеÄũ´壬ËùµÃʵ»ݣ¬×ԱØ×î´ó¡£ÆäԭÉú²úÎïµÄÔËÊ䣬Ëù·ѼȽÏʡ£¬ËùÒԣ¬Óë½ÏԶũ´åµIJúÎï±Ƚϣ¬ÉÌÈËÃǼ´ʹ¸¶¸øÉú²úÕ߽ϸߵÄÂò¼ۣ¬µ«¶ÔÓÚÏû·ÑÕߣ¬ȡ¼ÛȴÈԿÉһÑùµÍÁ®¡£ ¡¡¡¡¶þ£¬¶¼ÊоÓÃñËù»ñµIJƸ»£¬³£ÓÃÒԹºÂò´ýÊ۵ÄÍÁµأ¬ÆäÖкܴóһ²¿·ÖÍùÍùÊÇÏò먦¿ѵÄÍÁµء£ÉÌÈËÃǶ¼¿ÊÍû±ä³ÉÏçÉ𡣶øÇң¬ÔÚËûÃDZä³ÉÁËÏçÉðµÄʱºò£¬ËûÃÇÍùÍù×îÄܸÄÁ¼ÍÁµء£ÉÌÈËÓëÏçÉð²»ͬ¡£ÏçÉðÊÇһÏòÉݳ޹ßÁ˵ģ¬Ëûֻ»ỨǮ£¬´ÓÀ´²»»áÏ뵽׬Ǯ¡£ÉÌÈËȴ³£ÓÃǮÀ´¾­ӪÓÐÀûÊÂҵ£¬ËûÓÃһ¸öǮ£¬¾ÍϣÍûÔÚÕâһ¸öǮ»ØÀ´µÄʱº򣬴ø»ØһЩÀûÈó¡£ËûÃÇÕâÖֲ»ͬµÄϰ¹ߣ¬±ØȻ»áӰÏìËûÃÇÔÚһÇÐÊÂҵÉϵÄÐÔÇéºÍƢÆø¡£ÉÌÈËÍùÍùÊÇÓ¸ҵÄÊÂҵ¼ң¬ÏçÉðÍùÍùÊǵ¨ÇӵÄÊÂҵ¼ҡ£¾ÍÉÌÈË˵£¬Èç¹ûËû¾õµÃͶÏ´ó×ʱ¾À´¸ÄÁ¼ÍÁµأ¬ÓÐϣÍû°´ÕշÑÓõıÈÀýÔö´óËüµļÛֵ£¬Ëû¾ͺÁ²»³ÙÒɵØÂíÉÏȥ×ö¡£µ«ÏçÉðºÜÉÙÓÐ×ʱ¾£¬¼´ʹÓÐЩ×ʱ¾£¬ҲºÜÉٸÒÈç´ËÀ´ʹÓá£Èç¹ûËûÕæµÄ×ÅÊֽøÐиÄÁ¼£¬ËùÓÃÒԸÄÁ¼µģ¬ÒàÍùÍù²»ÊÇ×ʱ¾£¬¶øÊÇÿÄêÊÕÈëµÄʣÓࡣÉèÄãÐҶøסÔÚËÄÖÜũ´å¶à먦¿ѵÄÉÌҵ¶¼ÊÐÖУ¬Ä㵱Äܿ´µ½ÉÌÈËÔÚÕⷽÃæµĻ£¬±ÈÏçÉðÊǻîԾµöడ¡£´ËÍ⣬ÉÌÈËÓɾ­É̶øÑø³ɵİ®ÖÈÐ򡢽Úʡ¡¢½÷É÷µȸ÷ÖÖϰ¹ߣ¬ҲʹËû¸üÊʺÏÓڽøÐÐÍÁµØÉϵÄÈκθÄÁ¼£¬²»³³ɹ¦£¬²»³»ñÀû¡£ @@ -1024,12 +1024,12 @@ -µÚËÄƪ¡¡ÂÛÕþÖξ­¼ÃѧÌåϵ -ÐòÂÛ +µÚËÄƪ¡¡ÂÛÕþÖξ­¼ÃѧÌåϵ +ÐòÂÛ ¡¡¡¡±»¿´×÷ÕþÖμһòÁ¢·¨¼ҵÄһÃſÆѧµÄÕþÖξ­¼Ãѧ£¬Ìá³öÁ½¸ö²»ͬµÄĿ±꣺µÚһ£¬¸øÈËÃñÌṩ³ä×ãµÄÊÕÈë»òÉú¼ƣ¬»òÕ߸üȷÇеØ˵£¬ʹÈËÃñÄܸø×ԼºÌṩÕâÑùµÄÊÕÈë»òÉú¼ƣ»µڶþ£¬¸ø¹ú¼һòÉç»áÌṩ³ä·ֵÄÊÕÈ룬ʹ¹«ÎñµÃÒԽøÐС£×Ü֮£¬ÆäĿµÄÔÚÓڸ»¹úԣÃñ¡£ ²»ͬʱ´ú²»ͬ¹úÃñµIJ»ͬ¸»ԣ³̶ȣ¬Ôø²úÉúÁ½Öֲ»ͬµĹØÓڸ»¹úԣÃñµÄÕþÖξ­¼ÃѧÌåϵ¡£Æäһ£¬¿ɳÆΪÖØÉÌÖ÷Ò壻Æä¶þ£¬¿ɳÆΪÖØũÖ÷Ò塣¹ØÓÚÕâÁ½¸öÖ÷Ò壬Îҽ«¾¡ÎÒËùÄܣ¬×÷ÏêϸÃ÷Á˵Ä˵Ã÷£¬¶øÇҽ«´ÓÖØÉÌÖ÷Ò忪ʼ¡£ÕâÊǽüÊÀµÄѧ˵£¬ÔÚÎҹú½ñÈÕÓÖ×îΪÈËËùÀí½⡣ -µÚһÕ ÉÌҵÖ÷Òå»òÖØÉÌÖ÷ÒåµÄԭÀí +µÚһÕ ÉÌҵÖ÷Òå»òÖØÉÌÖ÷ÒåµÄԭÀí ¡¡¡¡²Ƹ»Óɻõ±һò½ðÒø¹¹³ÉÕâһͨ³£Á÷Ðеļû½⣬ÊÇ×ÔȻ¶øȻµØÒò»õ±ÒÓÐÁ½ÖØ×÷Óöø²úÉúµġ£»õ±ÒÊǽ»Ò׵Äý½飬ÓÖÊǼÛֵµij߶ȡ£ÒòΪËüÊǽ»Ò׵Äý½飬ËùÒԣ¬ÎÒÃÇÓûõ±ң¬±ÈÓÃÈκÎÆäËûÉÌƷ£¬¶¼¸üÈÝÒ×ȡµÃÎÒÃÇËùÐèµÄÎïƷ¡£ÎÒÃÇ×ÜÊǾõµã¬»ñȡ»õ±ÒÊÇһ¼þҪÊ¡£ֻҪÓлõ±ң¬ÒԺóËæ±㹺Âòʲô£¬¶¼ûÓÐÀ§Äѡ£ÒòΪËüÊǼÛֵµij߶ȣ¬ÎÒÃDZãÓø÷ÖÖÉÌƷËùÄܻ»µõĻõ±ÒÁ¿£¬À´¹À¼ÆÆäËû¸÷ÖÖÉÌƷµļÛֵ¡£Óкܶà»õ±ҵÄÈˣ¬±»³ÆΪ¸»Èˣ»ֻÓм«ÉÙһµã»õ±ҵÄÈˣ¬±»³ÆΪÇîÈˡ£¼óÆӵĻòÏ뷢²ƵÄÈˣ¬±»˵³ÉÊǰ®»õ±ҵÄÈˣ»²»½÷É÷µġ¢²»ÁߨĵĻòÉݳ޵ÄÈˣ¬±»˵³ÉÊÇĮÊӻõ±ҵÄÈˡ£·¢²ƵÈÓÚÊÇÓÐÁ˻õ±ҡ£×Ü֮£¬°´ÕÕͨË׵Ä˵·¨£¬²Ƹ»Óë»õ±ң¬ÎÞÂ۴ÓÄÄһµ㿴À´£¬¶¼ÊÇͬÒåÓ ¡¡¡¡Ïó¸»ÈËһÑù£¬¸»×ãµĹú¼ÒÍùÍù±»ÈÏΪӵÓкܶà»õ±ҡ£ÔÚÈκιú¼ң¬Öü»ý½ðÒø±»ÈÏΪÊÇÖ¸»µĽݾ¶¡£ÃÀÖ޷¢Ïֺó£¬ÓÐһ¸öʱÆڣ¬Î÷°àÑÀÈËÿµ½һ¸öÉúÊèµĺ£°¶£¬µÚһ¸öҪÎʵÄÎÊÌ⣬¾ÍÊǽü´¦ÓÐÎ޽ðÒø·¢Ï֡£ËûÃǾ͸ù¾ÝÕâÖÖÇ鱨£¬Åж¨ÄǸöµط½ÓÐûÓÐֳÃñµļÛֵ£¬ÄËÖÁÓÐûÓÐÕ÷·þµļÛֵ¡£ÒÔǰ£¬·¨À¼Î÷¹úÍõÌØDzɮÈËÆÕÀ­ŵ¡¤¿¨¶û±Èŵȥ¼ûÓÐÃûµijɼª˼º¹µÄһλÍõ×ӡ£¾ÝÕâλ´óʹ˵£¬÷²÷°ÈËËù³£³£Îʵ½µģ¬ֻÊǷ¨À¼Î÷Íõ¹úµÄţÑò¶಻¶ࡣËûÃǵÄÎÊÌâºÍÎ÷°àÑÀÈ˵ÄÎÊÌâÓÐͬÑùµÄĿµġ£ËûÃÇÏëҪ֪µÀÄǸö¹ú¼ÒÊǷñʮ·ָ»×㣬ֵµÃËûÃÇȥÕ÷·þ¡£÷²÷°È˺ÍÆäËûһÇÐÄÁÐóÃñ×壬´󶼲»֪µÀ»õ±ҵÄÓô¦£»ÔÚËûÃÇÖм䣬ÉüÐó±ãÊǽ»Ò׵Äý½飬±ãÊǼÛֵµij߶ȡ£ËùÒÔÔÚËûÃǿ´À´£¬²Ƹ»ÊÇÓÉÉüÐ󹹳ɣ¬ÕýÈçÔÚÎ÷°àÑÀÈ˿´À´£¬²Ƹ»ÊÇÓɽðÒø¹¹³ÉһÑù¡£ÔÚÕâÁ½Öֿ´·¨ÖУ¬÷²÷°È˵Ŀ´·¨ҲÐí×î½ӽüÓÚÕæÀí¡£ ¡¡¡¡Âå¿ËÏÈÉúÔøָ³ö»õ±ÒÓëÆäËû¸÷Öֶ¯²úµÄÇø±ð¡£Ëû˵£¬ÆäËû¸÷Öֶ¯²úÊÇÄÇôÈÝÒ×Ïûºģ¬ÒÔÖÂÓÉÕâµȶ¯²ú¹¹³ɵIJƸ»²»̫¿ɿ¿£»½ñÄ긻ÓÐÕâµȶ¯²úµĹú¼ң¬¼´ʹºÁÎÞÊä³ö£¬ֻҪÊÇÉݳÞÀ˷ѣ¬Ã÷Äê¾ͿÉÄܺÜȱÉÙÕâµȶ¯²ú¡£·´֮£¬»õ±ÒȴÊÇһ¸ö¿ɿ¿µÄÅóÓѣ¬ËüËäȻ»áÓÉÕâ¸öÈËת¸øÄǸöÈˣ¬µ«ÈôÄÜʹËü²»Á÷³ö¹úÍ⣬¾ͺܲ»ÈÝÒ×À˷ÑÏûºġ£ËùÒԣ¬ÔÚËû¿´À´£¬½ðÒøÄËÊÇһ¹ú¶¯²úÖÐ×î¼á¹Ì×î¿ɿ¿µIJ¿·֣»ËûÈÏΪ£¬ÓÉÓÚÕâ¸öԵ¹ʣ¬Ôö¼Ӵ˵ȽðÊô£¬Ӧµ±ÊǸùúÕþÖξ­¼õĴóĿ±ꡣ @@ -1078,7 +1078,7 @@ -µڶþÕ¡¡ÂÛÏÞÖƴÓÍâ¹úÊäÈë¹úÄÚÄÜÉú²úµĻõÎï +µڶþÕ¡¡ÂÛÏÞÖƴÓÍâ¹úÊäÈë¹úÄÚÄÜÉú²úµĻõÎï ¡¡¡¡ÒԸ߹Ø˰»ò¾ø¶Խûֹµİ취ÏÞÖƴÓÍâ¹úÊäÈë¹úÄÚÄܹ»Éú²úµĻõÎ¹úÄڴÓÊÂÉú²úÕâЩ»õÎïµIJúҵ±ã¶àÉٿÉÒÔȷ±£¹úÄÚÊг¡µĶÀռ¡£ÀýÈ磬½ûֹ´ÓÍâ¹úÊäÈë»îÉüÐóºÍëçÖÆʳƷµĽá¹û£¬Ӣ¹úÄÁÐóҵÕ߾Íȷ±£Á˹úÄÚÈâÀàÊг¡µĶÀռ¡£¶ԹÈÎïÊäÈë¿ÎÒԸ߶î¹Ø˰£¬¾͸øÓë¹ÈÎïÉú²úÕßÒÔͬÑùµÄÀûÒ棬ÒòΪÔÚһ°ã·áÊյÄʱºò¶ԹÈÎïÊäÈë¿ÎÒԸ߶î¹Ø˰£¬µÈÓڽûֹËüµÄÊäÈ롣Íâ¹úë֯ƷÊäÈ뵼ûֹ£¬ͬÑùÓÐÀûÓÚë֯ƷÖÆÔìҵ¡£˿³ñÖÆÔìҵËùÓõIJÄÁÏËäȫϵ²ú×ԹúÍ⣬µ«½üÀ´ҲÒÑȡµÃÁËͬÑùµÄÀûÒ档Â鲼ÖÆÔìҵÉÐδȡµÃÕâÑùµÄÀûÒ棬µ«ÕýÔڴó̤²½ÏòÕâһĿ±êÂõ½ø¡£»¹ÓÐÆäËûÐí¶àÖÖÀàµÄÖÆÔìҵͬÑùµØÔÚӢ¹úÍêȫȡµÃÁ˻򼸺õȡµÃÁ˲»ÀûÓÚͬ°ûµĶÀռȨ¡£Ӣ¹úËù¾ø¶ԽûֹÊäÈë»òÔÚijЩÌõ¼þϽûֹÊäÈëµĻõÎÆäÖÖÀà֮·±¶࣬²»ºÜÊìϤ¹Ø˰·¨µÄÈËÊǼòֱ¼«²»ÈÝÒײÂÏë³öÀ´µġ£ ¡¡¡¡ÕâÖֹúÄÚÊг¡µĶÀռ£¬¶ÔÏíÓжÀռȨµĸ÷ÖֲúҵÍùÍù¸øÓèºܴóµĹÄÀø£¬²¢ÍùÍùʹÉç»áÔÚÄÇÇé¿öÏÂÓнϴ󲿷ֵÄÀͶ¯ºÍ×ʲÆתÓõ½ÕⷽÃæÀ´£¬ÄÇÊǺÁÎÞÒÉÎʵġ£µ«Õâ°취»᲻»áÔö½øÉç»áµÄȫ²¿²úҵ£¬»᲻»áÒýµ¼ȫ²¿²úҵ×ßÉÏ×îÓÐÀûµķ½Ïò£¬ҲÐí²¢²»ÊÇʮ·ÖÃ÷ÏԵġ£ ¡¡¡¡Éç»áȫ²¿µIJúҵ¾ö²»»ᳬ¹ýÉç»á×ʱ¾ËùÄÜά³ֵÄÏ޶ȡ£ÈκθöÈËËùÄܹÍÓõŤÈËÈËÊý±ض¨ºÍËûµÄ×ʱ¾³ÉijÖֱÈÀý£¬ͬÑùµأ¬´óÉç»áµÄһÇгÉԱËùÄܼÌÐø¹ÍÓõŤÈËÈËÊý£¬Ҳһ¶¨ͬÄÇÉç»áµÄȫ²¿×ʱ¾³ÉijÖֱÈÀý£¬¾ö²»»ᳬ¹ýÕâ¸ö±ÈÀý¡£ÈκÎÉÌҵÌõÀý¶¼²»ÄÜʹÈκÎÉç»áµIJúҵÁ¿µÄÔö¼ӳ¬¹ýÆä×ʱ¾ËùÄÜά³ֵÄÏ޶ȡ£ËüֻÄÜʹ±¾À´²»ÄÉÈëijһ·½ÏòµÄһ²¿·ֲúҵתµ½Õâ¸ö·½ÏòÀ´¡£ÖÁÓÚÕâ¸öÈËΪµķ½ÏòÊǷñ±È×ÔȻµķ½Ïò¸üÓÐÀûÓÚÉç»ᣬȴ²»ÄÜȷ¶¨¡£ @@ -1127,8 +1127,8 @@ -µÚÈýÕ¡¡Â۶ÔÆäóÒ׵IJî¶ÈÏΪ²»ÀûÓÚÎҹúµÄÄÇЩ¹ú¼ҵĸ÷ÖֻõÎïµÄÊäÈëËù¼ӵÄÒ쳣ÏÞÖÆ -¡¡¡¡µÚһ½ڼ´ʹ¸ù¾ÝÖØÉÌÖ÷ÒåµÄԭÔò£¬ÕâÖÖÏÞÖÆҲ²»ºÏÀí +µÚÈýÕ¡¡Â۶ÔÆäóÒ׵IJî¶ÈÏΪ²»ÀûÓÚÎҹúµÄÄÇЩ¹ú¼ҵĸ÷ÖֻõÎïµÄÊäÈëËù¼ӵÄÒ쳣ÏÞÖÆ +¡¡¡¡µÚһ½ڼ´ʹ¸ù¾ÝÖØÉÌÖ÷ÒåµÄԭÔò£¬ÕâÖÖÏÞÖÆҲ²»ºÏÀí ¡¡¡¡ÖØÉÌÖ÷ÒåËùÌᳫµÄÔö¼ӽðÒøÁ¿µĵڶþ¸ö·½·¨£¬ÊǶÔÆäóÒײî¶ÈÏΪ²»ÀûÓÚÎҹúµÄÄÇЩ¹ú¼ҵļ¸ºõһÇлõÎïµÄÊäÈ룬¼ÓÒÔÒ쳣µÄÏÞÖơ£ÀýÈ磬Î÷ÀûÎ÷ÑǵÄϸÖ񲼣¬½ÉÄÉÁËһ¶¨µÄ˰£¬¼´¿ÉÊäÈëӢ¹ú£¬¹©Ӣ¹ú±¾¹úÏû·ѣ»µ«·¨¹úµÄϸ¸𲼼°ϸÖ񲼣¬ȴ³ýÁËÊäÈëÂ׶ظÛÂäջÒԴýÊä³öÒÔÍ⣬±ã½ûֹÊäÈ롣·¨¹úÆÏÌѾÆÊäÈëËùÐ븺µ£µÄ˰£¬Òà½ÏÆÏÌÑÑÀ»òÈκÎÆäËû¹ú¼ÒÆÏÌѾÆΪÖء£ÒÀÕÕ1692ÄêËùνÊäÈë˰£¬һÇз¨¹úÉÌƷ£¬¶¼Ðë½ÉÄÉÆä¼ÛֵµİٷÖ֮¶þʮÎåµÄ˰£»µ«ÆäËû¸÷¹úµĻõÎïËùÄɵÄ˰£¬ȴ´󲿷ÖҪÇáµö࣬ºÜÉٳ¬¹ý°ٷÖ֮Î塣³ÏȻ£¬·¨¹úÆÏÌѾơ¢°×À¼µء¢ʳÑΡ¢´ף¬²»ÔڴËÏޣ¬µ«´˵ÈÉÌƷ£¬ȴÒÀÕձðÏÂɻòÕâ¸ö·¨ÁîµÄÌØÊâÌõ¿½ÉÄɱðÖֿÁÖصÄ˰¡£1696Ä꣬ÓÖÈÏΪ´˰ٷÖ֮¶þʮÎ壬»¹²»¹»×èֹ·¨¹úÉÌƷÊäÈ룬ÓÚÊÇÓֶ԰×À¼µØÒÔÍâµķ¨¹ú»õÎïÔٿÎÒ԰ٷÖ֮¶þʮÎåµÄ˰£¬ͬʱ¶Է¨¹úÆÏÌѾÆÿ´óͰ¿ÎÐÂ˰¶þʮÎå°÷²¢¶Է¨¹ú´×ÿ´óͰ¿ÎÐÂ˰ʮÎå°÷¡£·¨¹ú»õÎï´ÓδʡÃâ˰ÔòÉÏÁоٵĸ÷ÖֻõÎï»ò´󲿷ֻõÎï±ØÐë½ÉÄɵÄÄÇЩһ°㲹Öú˰»ò°ٷÖ֮Îå˰¡£ҪÊǰÑÈý·Ö֮һ²¹Öú˰ºÍÈý·Ö֮¶þ²¹Öú˰Ҳ¼ÆËãÔÚÄڣ¬×÷Ϊȫ²¿Ҫ½ÉÄɵIJ¹Öú˰£¬ÄǾͿÎÓÐÄÇЩ²¹Öú˰µÄÎåÖ֡£Òò´ˣ¬ÔÚÕâ´ÎսÕù¿ªʼÒÔǰ£¬·¨¹ú´󲿷Öũ²úƷºÍÖÆÔìƷ£¬ÖÁÉÙҲÐ븺µ£°ٷÖ֮ÆßʮÎåµÄ˰¡£µ«´󲿷ֻõÎïʵÔڸºµ£²»ÆðÕâÑùÖصÄ˰¡£ËùÒԣ¬¿ÎËüÃÇÒÔÕâÑùÖصÄ˰ÎÞÒì½ûֹÆäÊäÈ롣ÎÒÏàÐţ¬·¨¹úҲÕë·æÏà¶ԵØÒÔͬÑù¿ÁÖصÄ˰£¬¼ÓÔÚÎÒÃǵĻõÎPÖÆÔìƷÉϣ¬ËäȻÎҲ»֪µÀËüËù¿εÄ˰¾ßÌå¿ÁÖص½ʲôµز½¡£ÕâÖÖÏ໥µÄÏÞÖƣ¬¼¸ºõ¶ϾøÁËÁ½¹ú¼äһÇй«ƽóÒף¬ʹ·¨¹ú»õÎïÔËÖÁӢ¹ú£¬ºÍӢ¹ú»õÎïÔËÖÁ·¨¹ú£¬Ö÷Ҫ¶¼¿¿×ß˽¡£ÎÒÔÚǰÕÂËù¿¼²ìµÄÓÐԭÔ򣬷¢ԴÓÚ˽ÈËÀûº¦¹ØϵºͶÀռ¾«Éñ£»ÔÚÕâÕÂËùҪ¿¼²ìµĸ÷ԭÔò£¬ȴ·¢ԴÓڹúÃñµÄƫ¼ûÓëµÐÒ⡣Òò´ˣ¬ÎÒÔÚÕâÕÂËùҪ¿¼²ìµÄԭÔò¸ü²»ºÏÀí¡£ÉõÖÁ¸ù¾ÝÖØÉÌÖ÷ÒåµÄԭÔòÀ´˵£¬ҲÊDz»ºÏÀíµġ£ ¡¡¡¡µÚһ£¬¼´ʹӢ¡¢·¨¼ä×ÔÓÉͨÉ̵Ľá¹û£¬óÒײî¶îȷ¶Է¨¹úÓÐÀû£¬ÎÒÃÇÒ಻ÄÜÒò´˱ã¶ÏÑԣ¬ÄÇÑùһÖÖóÒ׽«¶ÔӢ¹ú²»Àû£¬Ò಻ÄÜÒò´˱ã¶ÏÑԣ¬Ӣ¹úȫ²¿óÒ××ܲî¶½«Òò´ËÖÖóÒ׶øÓú²»ÀûÓÚӢ¹ú¡£Èç¹û·¨¹úÆÏÌѾƣ¬±ÈÆÏÌÑÑÀÆÏÌѾƼÛÁ®ÎïÃÀ£¬ÆäÂ鲼Ôò±ȵÂÒâ־µÄÂ鲼¼ÛÁ®ÎïÃÀ£¬ÄÇĩӢ¹úËùÐèµÄÆÏÌѾÆÓëÍâ¹úÂ鲼£¬µ±ȻÒÔÏ򷨹ú¹ºÂòΪÓÐÀû£¬ÒÔÏòÆÏÌÑÑÀ¡¢µÂÒâ־¹ºÂòΪ²»Àû¡£´ӷ¨¹úÿÄêÊäÈëµĻõÎïµļÛֵ£¬¹̽«´óÔö£¬µ«ÒòͬƷÖʵ퍹ú»õÎï½ÏÁ®ÓÚÆÏÌÑÑÀ¡¢µÂÒâ־¶þ¹ú»õÎ¹Êȫ²¿ÊäÈëƷµļÛֵ±ؼõÉ٣¬¶ø¼õÉٵÄÊýÁ¿£¬ÔòÓëÆäµÍÁ®³̶ÈÏà³ơ£¼´ʹÊäÈ˵퍹ú»õÎïÍêȫÔÚӢ¹úÏû·ѣ¬Çé¿öҲÊÇÈç´ˡ£ ¡¡¡¡µڶþ£¬ËùÊäÈëµÄȫ²¿·¨¹ú»õÎÓд󲿷ֿÉÄÜÔÙÊ䵽ÆäËû¹ú¼Òȥ×÷ÓÐÀûµķ·Âô¡£ÕâÖÖÔÙÊä³ö£¬ҲÐí»á´ø»ØÓ뷨¹úȫ²¿ÊäÈëƷµÄԭʼ·ÑÓÃÓÐͬµȼÛֵµĻس̻õ¡£ÈËÃǹØÓڶ«ӡ¶ÈóÒ×Ëù³£˵µĻ°£¬¶Է¨¹úóÒ×Ҳ¿ÉÊÊÓ㬾ÍÊÇ˵£¬¶«ӡ¶ȻõÎËäÓд󲿷ÖÊÇÓýðÒø¹ºÂ򣬵«ÓÉÆäÖÐһ²¿·ֻõÎïµÄÔÙÊä³ö£¬Ëù´ø»ص½±¾¹úÀ´µĽðÒø£¬±Èȫ²¿»õÎïµÄԭʼ·ÑÓû¹¶ࡣÏÖÔڣ¬ºÉÀ¼×îÖØҪóÒײ¿ÃÅ֮һ£¬¾ÍÊÇÔ˷¨¹ú»õÎﵽŷÖÞÆäËû¸÷¹ú¡£Ӣ¹úÈËÒûµķ¨¹úÆÏÌѾƣ¬ÒàÓÐһ²¿·ÖÃØÃÜÓɺÉÀ¼¼°Î÷À¼ÊäÈ롣Èç¹ûӢ·¨¼äóÒ××ÔÓɣ¬»򷨹ú»õÎïÔÚÊäÈëʱÓëŷÖÞÆäËû¸÷¹ú½ÉÄÉͬÑùµÄ˰£¬²¢ÔÚÊä³öʱÊջأ¬ÄÇĩӢ¹ú¿ÉÄܾͻá·ÖÏíµ½ÄǶԺÉÀ¼˵À´ʮ·ÖÓÐÀûµÄóÒ׵ĺô¦¡£ @@ -1158,7 +1158,7 @@ ¡¡¡¡°¢ķ˹Ìص¤ÒøÐÐÐû³ƣ¬²»ÒԴ¢½ðÈκβ¿·ִû³ö£»´¢½ðÕ˲¾ÉÏÿ¼ÇÏÂһ¶ܣ¬¼´Ôڽð¿âÄڣ¬±£²صÈÓÚһ¶ܼÛֵµĻõ±һò½ðÒøÌõ¿顣ÊÜÁì֤ÊéÉÐδʧЧ£¬Ëæʱ¿ÉÀ´Ìáȡ£¬¶øÊÂʵÉϲ»¶ϵØÁ÷³öºÍÁ÷ÈëµÄÄÇһ²¿·ֻõ±ÒÓë½ðÒøÌõ¿飬ȫ±£²ØÔڽð¿âÄڣ¬²»ÈÝÖÂÒɣ¬µ«ÊÜÁì֤Êé¾ÃÒÑÂúÆڣ¬ÔÚƽ³£ºÍƽ¾²ʱºò²»ÄÜҪÇóÌáȡ£¬¶øʵ¼ÊÉϴó¸ÅÔÚÁª°î¹ú¼ҴæÔڵÄʱÆÚÄÚÓÀԶÁôÔÚÒøÐÐÀïµÄÄÇһ²¿·Ö×ʱ¾£¬ÊǷñÒàÊÇÕâÑù£¬ȴËƺõÓÐÒÉÎʡ£Ȼ¶ø£¬Ôڰ¢ķ˹Ìص¤£¬ÓÐһ¶ÜÒøÐлõ±Ҽ´ÓÐһ¶ܽðÒø´æÔÚÒøÐнð¿âÀïÕâһÐÅÌõ£¬Ôڸ÷ÖÖÐÅÌõÖÐ×ÜËãÊǷîÐÐ×îÁ¦µÄÁˡ£°¢ķ˹Ìص¤ÊÐ×÷ÁËÕâ¸öÐÅÌõµı£֤Èˡ£ÒøÐйéËĸöÏÖÈÎÊг¤¼ල£¬ÕâËĸöÊг¤ÿÄê¸Äѡһ´Σ¬ÐÂÈεÄËĸöÊг¤£¬±ÈÕÕÕ˲¾£¬µ÷²éÒøÐнð¿⣬ÐûÊĽӹܣ¬ºóÀ´£¬ÔÙÒÔͬÑùׯÑϵÄÒÇʽ£¬°ѽð¿âµ㽻¸ø¼ÌÈεÄÈˡ£ÔÚÕâÕæ³ϵÄ×ڽ̹ú¼ң¬ÐûÊÄÖƶÈÆù½ñδ·ϡ£ÓÐÁ˴ËÖָüµü£¬¶ÔÓÚһÇв»Õýµ±ÐÐΪ£¬ËƺõÓÐÁ˳ä×ãµı£Õϡ£µ³ÕùÔڰ¢ķ˹Ìص¤ÕþÖÎÉÏÒýÆð¹ýÐí¶à´θïÃü£¬µ«ÔÚÕâһÇиïÃüÖУ¬ռÓÅÊƵĵ³Åɣ¬¶¼ûÔÚÒøÐйÜÀíÄÇһµãÉϹ¥»÷ËûÃÇǰÈεIJ»Öҳϡ£¶ÔÓÚʧÊƵĵ³ÅɵÄÃûÓþÓëÐÅÓã¬ÔÙûÓеڶþÖÖÊÂÇé±ÈÕâÖֹ¥»÷ÓиüÉî¿̵ÄӰÏìµÄÁˣ»Èç¹ûÕâÖֹ¥»÷ÕæÓиù¾ݣ¬ÎÒÃǿÉÒԶÏÑԣ¬ÄÇÊÇһ¶¨»áÌá³öÀ´µġ£1672Ä꣬µ±ʱ·¨ÍõÔÚÎڵÂÀÕ֧£¬°¢ķ˹Ìص¤ÒøÐи¶¿îѸË٣¬ÒÔÖÂÎÞÈ˻³ÒÉËüÂÄÐÐÆõԼµÄÖҳϡ£µ±ʱ£¬´ÓÒøÐнð¿âÖÐÌá³öµĻõ±ң¬»¹ÓÐЩÔøΪÒøÐÐÉèÁ¢ºóÊÐÕþÌü´ó»ðËùÉս¹¡£ÕâЩ»õ±ң¬±ض¨ÊǴÓÄÇʱºòÆ𣬼´±£´æÔÚÒøÐнð¿âÄڵġ£ ¡¡¡¡ÕâÒøÐеĽðÒø×ܶ¾¹ÓÐÈô¸ɣ¬ÀÏÔç¾ͳÉΪºÃÊÂÕßÒܲâµÄÎÊÌ⡣µ«¹ظÉÕâ×ܶî¶àÉ٣¬ֻÄÜÍƲ⡣һ°ãÈÏΪ£¬ÓëÕâÒøÐÐÓÐÕËĿÀ´ÍùµÄÈˣ¬ԼÓжþǧ£»¼ÙÉèËûÃÇÿÈËƽ¾ù´æÓÐһǧÎå°ٰ÷µļÛֵ£¨ÄÇÊÇ×î´óµļÙÉ裩£¬ÄÇĩÒøÐлõ±Ò×ܶÒò¶ø£¬ÒøÐнðÒø×ܶ±ã´óԼµÈÓÚÈý°ÙÍò°÷£¬ÒÔÿ°÷ʮһ¶ܼÆË㣬¾ʹóԼµÈÓÚÈýǧÈý°ÙÍò¶ܡ£ÕâÑùһ¸ö´óÊý¶×ãÒԾ­Ӫ¼«¹㷺µÄÁ÷ͨ£¬µ«±ÈһЩÈ˹ØÓÚÕâ×ܶî¿ä´óµÄÒܲ⣬ȴСµöࡣ ¡¡¡¡°¢ķ˹Ìص¤ÊдÓÕâÒøÐлñµÃÁ˺ܴóµÄÊÕÈ롣³ýÁËËùν²ֿâ×â½𣬷²µÚһ´ÎÓëÒøÐпªÀ´ÍùÕ˻§µģ¬ÐëÄɷÑʮ¶ܣ»ÿ¿ªһ´ÎÐÂÕˣ¬ÓÖò¢ÄɷÑÈý¶ÜÈý˹̩¸¥£»ÿתһ´ÎÕˣ¬ÐëÄɷѶþ˹̩¸¥£»Èç¹ûתÕ˵ÄÊýĿ²»¼°Èý°ٶܣ¬ÔòÐëÄÉÁù˹̩¸¥£¬ÒԷÀֹС¶îµÄתÕˡ£ÿÄ겻ÇåËãÕËĿ¶þ´ε쬷£¶þʮÎå¶ܡ£תÕ˵ÄÊýĿÈç¹û³¬¹ýÁ˴¢´æµÄÕÍĿ£¬ÐëÄɷѵÈÓڳ¬¹ý¶îµİٷÖ֮Èý£¬ÆäÇëÇóµ¥Ò౻¸éÖ᣾Ýһ°ãÈËÉèÏ룬ÒøÐÐÓÉÊÜÁì֤ÊéÂúÆڹéΪ¼ºÓеÄÍâ¹úÖý±ÒÓë½ðÒøÌõ¿飬ÔÚÓÐÀûʱ³öÊۣ¬Òà»ñµò»ÉÙÀûÈ󡣴ËÍ⣬ÒøÐлõ±ÒÒ԰ٷÖ֮ÎåµÄÌùˮÂô³ö£¬Ò԰ٷÖ֮ËĵÄÌùˮÂòÈ룬Òà¸øÒøÐÐÌṩÀûÈó¡£ÕâЩ²»ͬÀûµã¬´ó´󳬹ý֧¸¶ְԱнٺºͿª֧¹ÜÀí·ÑÓᣵ¥µ¥´¢´æËùÄɱ£¹ܷÑһÏ¾Ý˵µÈÓÚʮÎåÍò¶ÜÖÁ¶þʮÍò¶ܵÄÄ괿ÊÕÈ롣²»¹ý£¬Õâ»ú¹ØÉèÁ¢µÄĿ±꣬ԭÀ´²»ÊÇÊÕÈ룬¶øÊǹ«Ò档ÆäĿµÄÔڸÉʹÉÌÈ˲»ÖÁÒò²»ÀûµĻã¶Ҷø³Կ÷¡£Óɴ˶øÉúµÄÊÕÈ룬ÊDz»ÔøԤÁϵ½µģ¬¼òֱ¿ÉÒÔ˵ÊÇһÖÖÒâÍ⡣ÎÒΪÁËҪ˵Ã÷£¬ΪʲôÀíÓɣ¬ÓÃÒøÐлõ±ҶҸ¶µĹú¼ҺÍÓÃͨÓûõ±ҶҸ¶µĹú¼ң¬Æä»ã¶Ҵó¶¼ËƺõÓÐÀûÓÚǰÕߣ¬¶ø²»ÀûÓںóÕߡ£²»֪²»¾õµØ˵³öÁËÈ߳¤µÄÌâÍ⻰£¬ÏÖÔڣ¬ÎҸûص½±¾Ì⡣ǰһÖֹú¼ÒÓÃÒԶҸ¶»ãƱµĻõ±ң¬Æä¹ÌÓмÛֵ×ÜÊDz»±䣬ǡÓëÆäÔì±ҳ§±ê׼Ïà·û£»ºóһÖֹú¼ÒÓÃÒԶҸ¶»ãƱµĻõ±ң¬Æä¹ÌÓмÛֵ²»¶ϱ䶯£¬¶øÇҼ¸ºõ¶¼¶àÉٵÍÓÚÆäÔì±ҳ§±ê׼¡£ -¡¡¡¡ µڶþ½ڸù¾ÝÆäËûԭÔò£¬ÕâÖÖÒ쳣µÄÏÞÖÆҲ²»ºÏÀí +¡¡¡¡ µڶþ½ڸù¾ÝÆäËûԭÔò£¬ÕâÖÖÒ쳣µÄÏÞÖÆҲ²»ºÏÀí ¡¡¡¡Ôڱ¾ÕµÄǰ½ڣ¬ÎҽßÁ¦˵Ã÷£¬¼´¸ù¾ÝÖØÉÌÖ÷ÒåµÄԭÀí£¬¶ÔÓÚóÒײî¶ÈÏΪ²»ÀûÓÚÎҹúµÄÄÇЩ¹ú¼ҵĻõÎïµÄÊäÈ룬Ҳ²»±ؼÓÒÔÒ쳣µÄÏÞÖơ£ ¡¡¡¡Ȼ¶ø£¬´ËÖÖÏÞÖÆÒԼ°Ðí¶àÆäËûÉÌҵÌõÀýËù¸ù¾ݵÄÕû¸öóÒײî¶îѧ˵£¬ÊÇÔٲ»ºÏÀí²»¹ýµġ£µ±Á½µØͨÉÌʱ£¬ÕâÖÖѧ˵ÈÏΪ£¬Èç¹ûóÒ׶îƽº⣬ÔòÁ½µظ÷Î޵Ãʧ£»Èç¹ûóÒ׶îÂÔÓÐƫÒУ¬¾ͱØһ·½Ëðʧ¡¢Áíһ·½µÃÀû£¬µÃʧ³̶ȺÍƫÒг̶ÈÏà³ơ£µ«ÕâÁ½ÖÖÉèÏ붼ÊǴíÎóµġ£ÏóÎҺóÃæËùҪ˵Ã÷µÄÄÇÑù£¬½±Àø½ðÓë¶ÀռȨ£¬ËäΪ±¾¹úÀûÒæ¶øÉèÁ¢£¬µ«Óɽ±Àø½𼰶ÀռȨËù´ٳɵÄóÒף¬ȴ¿ÉÄܶԱ¾¹ú²»Àû£¬¶øÇÒÊÂʵÉϳ£ÊÇÕâÑù¡£·´֮£¬²»ÊÜÏÞÖƶø×ÔȻµء¢Õý³£µؽøÐеÄÁ½µؼäµÄóÒף¬Ëäδ±ضÔÁ½µØͬÑùÓÐÀû£¬µ«±ضÔÁ½µØÓÐÀû¡£ ¡¡¡¡ËùνÀûÒæ»òÀûµã¬ÎҵĽâÊͣ¬²»ÊǽðÒøÁ¿µÄÔö¼ӣ¬¶øÊÇһ¹úÍÁµغÍÀͶ¯Äê²úÎサ»»¼ÛֵµÄÔö¼ӣ¬»òÊÇһ¹ú¾ÓÃñÄêÊÕÈëµÄÔö¼ӡ£ @@ -1179,7 +1179,7 @@ -µÚËÄÕ¡¡ÂÛÍË˰ +µÚËÄÕ¡¡ÂÛÍË˰ ¡¡¡¡ÉÌÈ˺ÍÖÆÔìҵÕߣ¬²»ÒԶÀռ¹úÄÚÊг¡ΪÂú×㣬ȴΪËûÃǵĻõÎïıÇó×î¹ã´óµĹúÍâÏúÊÛÊг¡¡£µ«ÓÉÓÚËûÃǵĹú¼ÒÔÚÍâ¹úûÓйÜϽȨ£¬ËûÃÇҪ¶ÀռÍâ¹úµÄÊг¡£¬¼òֱÊDz»¿ÉÄܵġ£ËùÒԣ¬һ°ãµØ˵£¬ËûÃÇֻºÃÇëÇó½±ÀøÊä³ö¡£ ¡¡¡¡Ôڸ÷Öֽ±ÀøÖУ¬ËùνÍË˰£¬ËƺõÊÇ×îºÏÀíµÄÁˡ£ÔÚÉÌÈËÊä³öʱ£¬Í˻¹±¾¹ú²úҵÉϵĹú²ú˰»ò¹úÄÚ˰µÄȫ²¿»òһ²¿·֣¬²¢²»»áʹ»õÎïµÄÊä³öÁ¿£¬´ó¸ÉÎÞ˰ʱ»õÎïµÄÊä³öÁ¿¡£ÕâÖֽ±Àø£¬²»»áÇýʹ´󲿷ֵÄ×ʱ¾£¬Υ·´×ÔȻÇ÷Êƣ¬תÏòijһÌض¨ÓÃ;£¬µ«ȴ»áʹ¿Î˰²»ÖÁÓÚÇýʹÕⲿ·Ö×ʱ¾ÖеÄÈκβ¿·Öתµ½ÆäËûÓÃ;ȥ¡£ÕâÖֽ±Àø£¬²»»áÆƻµÉç»áÉϸ÷ÖÖÓÃ;¼äµÄ×ÔȻƽº⣬µ«ȴ»áʹ¿Î˰²»²úÉúÆƻµÕâÖÖ×ÔȻƽºâµÄ×÷Óá£ÕâÖֽ±Àø£¬²»»áÆƻµÉç»áÉÏÀͶ¯µÄ×ÔȻ·ÖÅ䣬¶ø»ᱣ´æÕâÖַÖÅ䡣Ôڴó¶àÊý³¡ºϣ¬±£´æÕâÖַÖÅäÊÇÓÐÀûµġ£ ¡¡¡¡ÊäÈëµÄÍâ¹ú»õÎÔÚÔÙÊä³öʱ£¬Òà¿ÉÍË˰¡£ÔÚӢ¹ú£¬ËùÍ˵Ä˰£¬´󶼵ÈÓÚÊäÈë˰µÄ×î´󲿷֡£¹涨½ñÈÕËùν¾ɲ¹Öú˰µÄÄǸöÒé»ᷨÁîµĸ½ÔòµĵڶþÏî¹涨£¬ÿ¸öÉÌÈˣ¬²»Â۹ú¼®£¬¶¼¿ÉÓÚÊä³öʱ£¬ÊջØÕâÖ־ɲ¹Öú˰µÄһ°롣µ«Ӣ¹úÉÌÈˣ¬ӦÓÚʮ¶þ¸öÔÂÄÚÊä³ö£¬¶øÍâ¹úÉÌÈËӦÓھŸöÔÂÄÚÊä³ö¡£ֻÓÐÆÏÌѾơ¢СÆÏÌѸɺÍ˿¾«ÖÆƷ¡£ÒòÒÑÁìÓÐÆäËû¸üÓÐÀûµĽòÌù£¬¹ʲ»ÊÊÓôËÌõÀý¡£Õâ¸öÒé»ᷨÁîËù¹涨µÄ˰£¬Ôڵ±ʱÊÇΨһµÄÍâ¹úÉÌƷÊäÈë˰¡£ºóÀ´£¬°ÑÕâÖּ°ÆäËû¸÷ÖÖÍË˰µÄÇëÇóÆÚÏÞÑӳ¤µ½ÈýÄ꣨ÇÇÖÎһÊÀµÚÆßÄ귨ÁîµڶþʮһºŵÚʮÌõ£©¡£ @@ -1199,7 +1199,7 @@ -µÚÎåÕ¡¡Â۽±Àø½ð +µÚÎåÕ¡¡Â۽±Àø½ð ¡¡¡¡¶ÔӢ¹úijЩ²úҵµIJúƷ£¬³£³£ÓÐÈËÇëÇóÊä³ö½±Àø½𣬶øÕþ¸®ÓÐʱҲ·¢¸øÊä³ö½±Àø½𡣾Ý˵£¬ÎҹúÉÌÈ˺ÍÖÆÔìҵÕߣ¬ÀµÓÐÕâÖֽ±Àø½𣬲ÅÄÜÔÚÍâ¹úÊг¡Éϣ¬ÒÔÓ뾺ÕùÕßͬÑùµÍÁ®»ò¸üΪµÍÁ®µļ۸ñ³öÊÛËûÃǵĻõÎ¾Ý˵£¬Êä³öÁ¿Òò´ËÔö´󣬶øóÒײî¶îÒà±äµøüÓÐÀûÓÚÎҹú¡£ÔÚÍâ¹úÊг¡Éϣ¬ÎÒÃDz»ÄÜÏóÔڹúÄÚÊг¡ÄÇÑù£¬¸øÎÒÃǹ¤ÈËÒԶÀռȨ¡£¶ÔÍâ¹úÈˣ¬ÎÒÃDz»ÄÜÏó¶Ա¾¹úÈËÄÇÑù£¬ǿÆÈËûÃǹºÂòÎҹú¹¤ÈËÉú²úµĻõÎÓÚÊǣ¬Ïë³öÁ˵ڶþ¸ö×îºð취£¬¼´¸¶Ǯ¸øÍâ¹úÈ˹ºÂò¡£Õâ¸öÒÔóÒײî¶¹ú¸»Ãñµİ취£¬ÄËÊÇÖØÉÌѧ˵ËùÌᳫµġ£ ¡¡¡¡ÓÐÈËÈÏΪ£¬½±Àø½ðֻӦ¸÷¢¸øÄÇЩÎ޽±Àø½𼴲»Äܾ­ӪµÄÉÌҵ²¿Ã𣵫ÎÞÂÛʲôÉÌҵ²¿Ãţ¬Èç¹ûÉÌÈËÊۻõËùµü۸񣬿ÉÒԳ¥»¹´˻õÎïÖÆÔìÄËÖÁÉÏÊÐËùͶϵÄ×ʱ¾²¢ÌṩÆäÆÕͨÀûÈó£¬ÄÇĩ¼´ʹûÓн±Àø½ð£¬Òà±ØÄܼÌÐø¾­Ӫ¡£ÕâÑùµÄÉÌҵ²¿Ãţ¬ÓëÆäËûÔÚÎ޽±Àø½ð״̬Ͼ­Ӫµĸ÷ÉÌҵ²¿Ãţ¬Ã÷ÏԵش¦ÔÚͬµȵØλ£¬ËùÒԣ¬ÕâÑùµÄÉÌҵ²¿ÃŲ»ÐèҪ½±Àø½ð£¬ÕýÏóÆäËûÉÌҵ²¿ÃŲ»ÐèҪ½±Àø½ðһÑù¡£ֻÓÐÉÌÈËÊۻõ¼۸ñ²»×㲹»¹Æä×ʱ¾²¢ÌṩÆäÆÕͨÀûÈóµÄÉÌҵ£¬»òÊۻõ¼۸ñ²»×ãµֳ¥»õÎïÉÏÊÐʵ¼ʷÑÓõÄÉÌҵ£¬²ÅÐèҪ½±Àø½𡣽±Àø½𷢸øµÄĿµģ¬ÔÚÓڲ¹³¥´ËËðʧ£¬½±ÀøËü¼ÌÐø¾­Ӫ»򿪴´һÖֱ»ÈÏΪ¿ª֧´óÓÚÊÕÒæµÄÉÌҵ£¬¾ÍÊÇ˵£¬ÿ¾­Ӫһ´Σ¬ͶϵÄ×ʱ¾¼´¿÷ʴһ²¿·֣¬¶øһÇÐÆäËûÉÌҵÈ綼¾ßÓÐÕâÑùµÄÐÔÖʣ¬ÄÇĩȫ¹ú×ʱ¾²»¾þͻáÆÆÃðÎ޴档 ¡¡¡¡Ӧ¸Ãָ³ö£¬¿¿½±Àø½ð¾­ӪµÄÉÌҵ£¬ֻÊÇÄÜÔÚÁ½¹ú¼䳤Æھ­ӪÏÂȥ¶øһ¹úÀÏÊǿ÷±¾£¨¼´»õÎïÊۼÛÉÙÓڻõÎïÉÏÊÐʵ¼ʷÑÓ㩵ÄÉÌҵ¡£µ«Êǣ¬Èç¹ûûÓн±Àø½ðÀ´²¹»¹ÉÌÈ˻õÎïÊۼÛÉϵÄËðʧ£¬Ëû×ÔÉíµÄÀûº¦¹Øϵ£¬²»¾ÃҲ»áʹËû¸ıä×ʱ¾ÓÃ;£¬»òѰÕÒÆäËûÄÜÒԻõÎïÊۼ۳¥»¹»õÎïÉÏÊÐËùÓõÄ×ʱ¾²¢ÌṩÆäÆÕͨÀûÈóµÄÐÐҵ¡£ÏóÖØÉÌÖ÷ÒåËùÌᳫµÄÆäËû¸÷Öְ취µĽá¹ûһÑù£¬·¢¸ø½±Àø½ðµĽá¹û£¬ֻ²»¹ýÆÈʹһ¹úÉÌҵ£¬²»Ïò×ÔȻ·½Ã淢չ£¬¶øÏò´ó´ó²»Àûµķ½Ã淢չ¡£ @@ -1330,7 +1330,7 @@ -µÚÁùÕ¡¡ÂÛͨÉÌÌõԼ +µÚÁùÕ¡¡ÂÛͨÉÌÌõԼ ¡¡¡¡ҪÊÇijһ¹ú¼ң¬ÊÜÌõԼÊø¸¿£¬ֻÐíijһÍâ¹úijÖÖÉÌƷÊäÈ룬¶ø½ûֹÆäËûÍâ¹úÕâÖÖÉÌƷÊäÈ룬»ò¶ÔÆäËûÍâ¹úijÖÖÉÌƷ¿Î˰£¬¶ø¶ÔijһÍâ¹úÕâÖÖÉÌƷÃâ˰£¬ÄÇÉÌҵÉÏÊܻݵĹú¼ң¬ÖÁÉ٣¬ËüµÄÉÌÈ˺ÍÖÆÔìҵÕߣ¬±ØȻ»á´ÓÕâÖÖÌõԼȡµúܴóÀûÒ档ÕâЩÉÌÈ˺ÍÖÆÔìҵÕߣ¬ÔÚÕâÑù¿íºê¶ԴýËûÃǵĹú¼ÒÄڣ¬ÏíÊÜÁËһÖֶÀռȨ¡£Õâ¸ö¹ú¼ң¬¾ͳÉΪËûÃÇÉÌƷµÄһ¸ö¸ü¹ãÀ«ÓָüÓÐÀûµÄÊг¡¡£¸ü¹ãÀ«£¬ÒòΪÆäËû¸÷¹úµĻõÎ²»ÊÜÅų⣬¾ÍҪ¿θüÖصÄ˰£¬Òò´ËÕâ¸ö¹ú¼ҵÄÊг¡ÈÝÄÉÁ˱ÈûÓÐÌõԼʱ¸ü¶àµÄËûÃǵĻõÎ¸üÓÐÀû£¬ÒòΪÊܻݹúÉÌÈˣ¬ÔÚÄÇÀïÏíÊÜÁËһÖֶÀռȨ£¬Òò´ËÍùÍùÄÜÒԱÈ×ÔÓɾºÕù³¡ºϸüºõļ۸ñ£¬ÊÛȥËûÃǵĻõÎ ¡¡¡¡ÕâÑùµÄÌõԼ£¬Ëä¿ÉÓÐÀûÓÚÊܻݹúµÄÉÌÈ˼°ÖÆÔìҵÕߣ¬µ«±ز»ÀûÓÚʩ»ݹúµÄÉÌÈ˼°ÖÆÔìҵÕߡ£ÕâÑù¾ͰÑһÖÖÓк¦ÓÚËûÃÇ×ԼºµĶÀռȨ¸øÓëijһÍâ¹ú£¬¾ÍÐ볣ÒԱÈ×ÔÓɾºÕù³¡ºϸü°º¹óµļ۸񣬹ºÂòËûÃÇËùÐèµÄÍâ¹úÉÌƷ¡£Õâ¸ö¹ú¼ÒÓÃÒԹºÂòÍâ¹úÉÌƷµÄÄÇһ²¿·ֱ¾¹ú²úÎ±ØÐëÒԸüµÍÁ®µļ۸ñ³öÊۣ¬ÒòΪÔÚÁ½¸öÎïƷ»¥Ïཻ»»ʱ£¬һ¸öÎïƷµĵÍÁ®ÄËÊÇÁíһ¸öÎïƷ°º¹óµıØȻ½á¹û£¬¸üÕýȷµØ˵£¬Á½ÕßÊÇһ¶ø¶þ¡¢¶þ¶øһµġ£ËùÒԣ¬ËüµÄÄê²úÎïµĽ»»»¼Ûֵ£¬¾ͻáÒò´ËÖÖÌõԼ¶ø¼õÉ١£µ«ÕâÖּõÉ٣¬²»¿ÉÒÔ˵ÊǾø¶ԵÄËðʧ£¬ȴֻÊDZ¾À´¿ɵõ½µÄÀûÒæµļõÉ١£Ëü³öÊۻõÎïµļ۸ñ£¬ËäµÍÓÚÎÞͨÉÌÌõԼʱËù¿ÉÊ۵õļ۸񣬵«ÊۼÛ×ܲ»»᲻¼°³ɱ¾£¬¶øÇң¬¾ö²»»áÏóһЩ»õËûÄÇÑù£¬²»ÁìÊܽ±Àø½𣬾Ͳ»×ãÒԲ¹³¥ÔËËͻõÎïÉÏÊÐËùͶµÄ×ʱ¾²¢ÌṩÆäÆÕͨÀûÈ󡣷ñÔò£¬ÕâÖÖóÒף¬¾Ͳ»Äܳ¤¾üÌÐø¡£ËùÒԣ¬¼´¾ͳػݹú˵£¬¾­Ӫ´ËÖÖóÒ×ÒàÊÇÓÐÀû£¬µ«ÓÐÀû³̶Ȳ»Ïó×ÔÓɾºÕù³¡ºÏÄÇô´ó¡£ ¡¡¡¡ÓÐЩͨÉÌÌõԼ£¬¸ù¾ÝÓë´˺ܲ»ÏàͬµÄԭÀí£¬ȴÈÏΪÓÐÀû¡£ÓÐʱ£¬ÉÌҵ¹ú¸øijһÍâ¹úijÖÖÉÌƷÒÔÓꦱ¾¹úµĶÀռȨ£¬ֻÒòΪϣÍûÔÚÁ½¹ú¼äµÄȫ²¿óÒ×Éϣ¬±¾¹úÿÄêËùÊۣ¬ÄܶàÓÚÿÄêËù¹º£¬ÒÔÖ½ðÒøµIJî¶îÿÄ궼¶Ô×ԼºÓÐÀû¡£1703ÄêӢÆÏͨÉÌÌõԼ£¬¾͸ù¾ÝÕâԭÀí¶ø²©µ÷dz£µÄÔÞÉ͡£ÒÔϱãÊÇÕâÌõԼµÄֱÒëÎ쬽öÓÐÈýÌõ£º @@ -1366,8 +1366,8 @@ -µÚÆßÕ¡¡ÂÛֳÃñµØ -µÚһ½ÚÂ۽¨Á¢ÐÂֳÃñµص͝»ú +µÚÆßÕ¡¡ÂÛֳÃñµØ +µÚһ½ÚÂ۽¨Á¢ÐÂֳÃñµص͝»ú ¡¡¡¡ŷÖÞÈË×î³õÔÚÃÀÖ޼°Î÷ӡ¶Ƚ¨Á¢ֳÃñµص͝»ú£¬²¢ûÃɹÅϣÀ°ÂÞÂí½¨Á¢ֳÃñµص͝»úÄÇôÃ÷Ïԡ¢ÄÇôÈÝÒ׿´µóöÀ´¡£ ¡¡¡¡¹ÅϣÀ°¸÷°¸÷ռÓм«СµÄÁìÍÁ£»ÈκÎһ°îÈËÃñ£¬Ôö¶ൽ±¾°îÁìÍÁ²»Ò×ά³ֵÄʱº򣬱ãDzËÍһ²¿·ÖÈËÃñ³öȥ£¬ÔÚÊÀ½çÉÏÁÉԶµĵط½£¬ѰÕÒеÄס´¦¡£ËûÃÇËÄÖܵĺÃսÁÚÈˣ¬ʹËûÃÇÈκÎһ°ºÜÄÑÔڹúÄڴó´óÀ©´óÆäÁìµء£¶àÀﰲÈ˴󶼵½Òâ´óÀû¼°Î÷Î÷ÀïȥֳÃñ¡£ÕâÁ½µأ¬ÔÚÂÞÂí½¨Á¢ÒÔǰ£¬ΪҰÂù먦»¯ÈËÃñËùռ¾ӡ£ÒÁÎÖÄáÑÇÈ˼°ÒÁÎÖÀûÑÇÈˣ¨ϣÀ°ÁíÍâÁ½´ó²¿Â䣩´󶼵½СÑÇϸÑǼ°°®Çٺ£¸÷µºȥֳÃñ¡£ÕâÁ½µؾÓÃñ£¬Ôڵ±ʱËÆÓëÒâ´óÀû¼°Î÷Î÷ÀﵱʱµÄÇé¿ö´óÖÂÏàͬ¡£ĸÊÐËäÊÓֳÃñµØΪ¶ù×ӣ¬³£³£¸øÓë´óµĶ÷»ÝÓëԮÖú£¬Ҳµõ½ֳÃñµصĸд÷£¬µ«ȴÊÓֳÃñµØΪÒѽâ·ŵĶù×ӣ¬²»ҪÇóֱ½ӵÄͳÖΡ£ֳÃñµØ×ԾöÕþÌ壬×Զ¨·¨Âɣ¬×Ôѡ¹ÙÀô£¬¶øÇÒÒԶÀÁ¢¹ú×ʸñÏòÁڹúÐûսæźͣ¬ÎÞÐèĸÊеijÐÈϻòͬÒ⡣ûÓÐʲôÄܱÈÊ÷Á¢ÕâÖÖֳÃñµĶ¯»ú¸üÃ÷Ïԡ¢¸üÈÝÒ׿´µóöÀ´¡£ ¡¡¡¡¹ÅÂÞÂí£¬ÏóÆäËû´󲿷ֹŴú¹²º͹úһÑù£¬ԭÀ´Êǽ¨Á¢ÔÚһÖÖÍÁµطÖÅ䷨Éϣ¬¼´°´һ¶¨±ÈÀý£¬½«ËùÓеĹ«ÓÐÁìµأ¬·ÖÅ䏸¹¹³ɹú¼ҵĸ÷ÊÐÃ񡣵«ÈËʵıäǨ£¬½á»éÄ쬳мÌÄ쬏îÈÃÄ쬱ØȻ»á°ÑԭÀ´µķÖÅä¸ãÂң¬³£ʹԭÀ´·Ö×÷Ðí¶à¼Ò×åά³ÖÊֶεÄÍÁµأ¬¹éһ¸öÈËËùÓС£Ϊ¾ÀÕý´ËÖֱײ¡¡ª¡ªËûÃÇҲÈÏΪÕâÊÇһÖֱײ¡£¬ËûÃǰ䲼ÁËеķ¨Âɣ¬ÏÞÖƸ÷ÊÐÃñËùռÓеÄÍÁµØÁ¿£¬²»µó¬¹ýÎå°ÙÖì¸ñÀ­£¬ԼºÏӢĶÈý°ÙÎåʮĶ¡£µ«ÕⷨÂɣ¬¾ÝÎÒËù֪£¬ËäʩÐйýһÁ½´Σ¬µ«´󶼱»È˺öÊӻò»رܣ¬¶ø²ƲúԽÀ´Խ²»ƽ¾ù¡£´󲿷ÖÊÐÃñ£¬ÊÇûÓÐÍÁµص컵«°´µ±ʱ·çË×ÈËÇ飬ÎÞÍÁµؼ´ÄÑÓÚά³Ö×ÔÓÉÈ˵ĶÀÁ¢¡£ÏÖʱ£¬ÎÞÍÁµØƶÃñ£¬ÈôÉÔÓÐ×ʲƣ¬¿É×â¸ûËûÈËÍÁµØÓò¾­ӪijһÖÖÁãÊÛҵ£»¼´ʹºÁÎÞ×ʲƣ¬Òà¿ɳäÈÎũ´åÀͶ¯Õ߻򼼹¤¡£µ«ÔڹÅÂÞÂí£¬ºÀ¸»È˼ҵÄÍÁµأ¬¶¼ÓÉūÁ¥¸ûÖ֣»ūÁ¥Ôڼ๤µļලϹ¤×÷£¬¼๤±¾ÉíҲÊÇūÁ¥£»ËùÒԣ¬ƶÇî×ÔÓÉÈˣ¬ºÜÉÙÓлú»á³ÉΪũÃñ»òũ´åÀͶ¯Õߡ£һÇÐÉÌҵ¡¢ÖÆÔìҵ£¬ÉõÖÁÁãÊÛҵ£¬Ò඼ΪÖ÷È˵ÄÀûÒæ¶øÓÉūÁ¥¾­Ӫ¡£Ö÷ÈËÃǵIJƸ»¡¢ȨÍþÓë·ÀÎÀ£¬ʹһ¸öƶÇîµÄ×ÔÓÉÈˣ¬ºÜÄѺÍËûÃǾºÕù¡£ËùÒԣ¬ÎÞÍÁµØÊÐÃ񣬳ýÁËÔÚÿÄêѡ¾Ùʱ£¬µõ½ºòѡÈ˵ÄÔù½ðÒÔÍ⣬¼¸ºõûÓбðÖÖÉú¼ÆÁˡ£µ±»¤Ãñ¹ÙÏë¹ÄÀøÈËÃ񷴿¹ºÀ¸»ʱ¡£¾ͽÐÈËÃñ»ØÏë¹ŴúµÄÍÁµطÖÅ䣬²¢˵ÏÞÖÆÄÇÖÖ˽²úµķ¨ÂÉÊǹ²º͹úµĻù±¾·¨Âɡ£ÈËÃ񳳳³ÄÖÄֵØҪÇóÍÁµأ¬µ«ÎÒÃÇ×ԿÉÏàÐţ¬¸»ºÀÃÇÊÇʮ·־öÒⲻ°ÑÈκβ¿·ÖÍÁµطָøËûÃǵġ£µ«ΪÁËҪ»æËûÃÇÏ൱³̶ȵÄÂú×㣬¸»ºÀÃÇÍùÍùÌáÒ齨Á¢ÐÂֳÃñµء£µ«×÷ΪÕ÷·þÕߵÄÂÞÂí£¬¼´ÔÚÕⳡºϣ¬ҲûÓбØҪµÀËÍÊÐÃñµ½ÊÀ½ç¸÷µØȥѰÕҳö·£¬Èç¹ûÎҿÉÕâÑù˵¡£ËüҪÏÈ֪µÀÊÐÃ񾿾¹½«ÔÚʲôµط½¶¨¾ӡ£Ëü´󶼰ÑÒâ´óÀû±»Õ÷·þ¸÷µصÄÍÁµأ¬ָ¶¨¸øÓëËûÃǡ£ËûÃÇÔÚÄÇÀÒàÏóÔڹ²º͹úÁìÍÁÉÏһÑù£¬²»Äܽ¨Á¢ÈκζÀÁ¢µĹ²º͹ú£¬ÖÁ¶àֻÄÜÐγÉһÖÖ×ÔÖÎÍÅÌ塣ÕâÖÖ×ÔÖÎÍÅÌ壬ËäÓÐÖƶ¨µط½·¨ÂɵÄȨÄܣ¬µ«ÐëÊÜĸÊеÄͳÖκͳͷ££¬²¢×ñÊØĸÊÐÖƶ¨µķ¨Âɡ£µ«ÕâÖÖֳÃñµصĽ¨Á¢£¬²»½ö½öÔÚÓÚÂú×ãһ²¿·ֵÄҪÇ󣬶øÇÒÒòΪһ¸öµط½Ð±»Õ÷·þ£¬µ±µØÈËÃñÊǷñ·þ´ӻ¹ÊôÒÉÎʣ¬³£¿ɽè´ËÔڵ±µØÉèÖÃһÖÖÊر¸¶ӡ£ËùÒԣ¬ÂÞÂíֳÃñµأ¬ÎÞÂ۾ÍÆäÐÔÖÊ˵»ò¾ÍÆ佨Á¢µĶ¯»ú˵£¬¶¼ÓëϣÀ°ֳÃñµØÍêȫ²»Ïàͬ¡£Òò´ˣ¬ԭÀ´ÓÃÒԱíʾÕâÖֽ¨ÖƵÄ×ÖÑۣ¬ÒàÓм«²»ÏàͬµÄÒâÒ塣À­һ¶¡Óïcolonaa±íʾֳÃ񣻷´֮£¬ϣÀ°Óï @@ -1567,7 +1567,7 @@ -µڰËÕ¡¡¹ØÓÚÖØÉÌÖ÷ÒåµĽáÂÛ +µڰËÕ¡¡¹ØÓÚÖØÉÌÖ÷ÒåµĽáÂÛ ¡¡¡¡ÖØÉÌÖ÷ÒåÌá³öµĸ»¹úÁ½´óÊֶΣ¬ËäÊǽ±ÀøÊä³öºÍ×èÒÖÊäÈ룬µ«¶ÔÓÚijЩÌض¨ÉÌƷ£¬ÔòËù·îÐеÄÕþ²ßÓÖËÆÓë´ËÏ෴£¬¼´½±ÀøÊäÈëºÍ×èÒÖÊä³ö¡£µ«¾ݳƣ¬Æä×îºóĿ±ê×ÜÊÇÏàͬ£¬¼´ͨ¹ýÓÐÀûµÄóÒײî¶ʹ¹ú¼ÒÖ¸»¡£Ëü×èÒֹ¤ҵԭÁϺÍְҵÓþߵÄÊä³ö£¬ʹÎҹúÉÌÈ˴¦ÓÚÓÐÀûµØλ£¬²¢ʹËûÃÇÔÚÍâ¹úÊг¡ÉÏÄÜÒԱÈÆäËû¸÷¹ú»õÎï¼۸ñµ͵ļ۸ñ³öÊÛËûÃǵĻõÎËüÌá³öÏÞÖƼ¸ÖּÛֵ²»´óµÄÉÌƷµÄÊä³ö£¬ʹÆäËûÉÌƷÔÚÊýÁ¿ºͼÛֵÉ϶¼ÓдóµöàµÄÊä³ö¡£ËüÓÖÌá³ö½±Àø¹¤ҵԭÁϵÄÊäÈ룬ʹÎҹúÈËÃñÄÜÒԽÏÁ®µļ۸ñ°ÑÕâЩԭÁÏÖƳɳÉƷ£¬´Ӷø·ÀֹÖÆÔìƷÔÚÊýÁ¿ºͼÛֵÉϽϴóµÄÊäÈ롣ÖÁÉ٣¬ÔÚÎҹúµķ¨ÂÉȫÊéÖУ¬ÎҲ»Ôø¿´µ½½±ÀøְҵÓþßÊäÈëµķ¨ÁÖÆÔìҵ·¢չµ½Ï൱¸ߵij̶ȵÄʱºò£¬ְҵÓþߵÄÖÆ×÷£¬¾ͳÉΪÐí¶༫ÖØҪÖÆÔìҵµÄĿ±ꡣ¶ÔÕâÖֹ¤¾ߵÄÊäÈë¸øÓèÈκν±Àø£¬µ±Ȼ´ó´ó·Á°­ÕâЩÖÆÔìҵÕߵÄÀûÒ档ËùÒԣ¬ÕâÑùµÄÊäÈ룬²»µ«²»±»½±Àø£¬¶øÇÒÍùÍù±»½ûֹ¡£ÀýÈ磬ÑòëÊá¾ߣ¬³ýÁ˴Ӱ®¶ûÀ¼ÊäÈ룬»ò×÷ΪÆƴ¬»õÎï»򲶻ñ»õÎïÊäÈ룬¾ÍÒÀ¾ݰ®µ»ªËÄÊÀµÚÈýÄêµķ¨Áî¶ø½ûֹÁˡ£ÒÁÀöɯ°×ŮÍõµÚÈýʮ¾ÅÄ꣬ÖØÉêÁËÕâÖֽûÁ´˺óµķ¨Á¼ÌÐø½ûֹ£¬ʹ´ËÖֽûֹ³ÉΪÓÀ¾õĽûֹ¡£ ¡¡¡¡¹¤ҵԭÁϵÄÊäÈ룬ÓÐʱµõ½Ãâ˰µĽ±Àø£¬ÓÐʱµõ½½±Àø½ð¡£ ¡¡¡¡Ñòë´ÓÈô¸ɹú¼ÒÊäÈ룬Ã޻¨´ÓһÇйú¼ÒÊäÈ룬ÉúÂ顢´󲿷ÖȾÁϺʹ󲿷ÖÉúƤ´Ӱ®¶ûÀ¼»òӢÁìֳÃñµØÊäÈ룬º£±ªƤ´ÓӢÁì¸ñÁÖÀ¼Ó泡ÊäÈ룬ÉúÌúºÍÌúÌõ´ÓӢÁìֳÃñµØÊäÈ룬ÒԼ°ÆäËû¼¸Öֹ¤ҵԭÁÏÊäÈ룬Èô°´Õýµ±ÊÖÐø³ʱ¨º£¹أ¬¼´¿ɵõ½Ãâ³ýһÇпÎ˰µĽ±Àø¡£ÕâÖÖÃâ˰ÌõÀý£¬ÒԼ°Ðí¶àÆäËûÉÌҵÌõÀý£¬ҲÐí¶¼ÊÇÎҹúÉÌÈ˺ÍÖÆÔìҵÕߣ¬³öÓÚ˽ÈËÀûº¦¹Øϵ£¬ӲҪÁ¢·¨µ±¾ÖÖƶ¨µġ£µ«ÕâЩ¹涨£¬ÊÇÍêȫÕýµ±µġ¢ºÏÀíµģ»ҪÊǷûºϹú¼ҵÄÐèҪ£¬¿ɰÑÕâÖֹ涨Íƹ㵽һÇÐÆäËû¹¤ҵԭÁϣ¬ÄÇÊÇһ¶¨ÓÐÀûÓÚÈËÃñ´óÖڵġ£ @@ -1624,7 +1624,7 @@ -µھÅÕ¡¡ÂÛÖØũÖ÷Ò弴ÕþÖξ­¼ÃѧÖаÑÍÁµØÉú²úÎ￴×÷¸÷¹úÊÕÈ뼰²Ƹ»µÄΨһÀ´Դ»òÖ÷ҪÀ´ԴµÄѧ˵ +µھÅÕ¡¡ÂÛÖØũÖ÷Ò弴ÕþÖξ­¼ÃѧÖаÑÍÁµØÉú²úÎ￴×÷¸÷¹úÊÕÈ뼰²Ƹ»µÄΨһÀ´Դ»òÖ÷ҪÀ´ԴµÄѧ˵ ¡¡¡¡¹ظÉÖØÉÌÖ÷Ò壬ÎҾõµÃÓÐÏêϸ˵Ã÷µıØҪ¡£µ«ÕþÖξ­¼ÃѧÖеÄÖØũÖ÷Ò壬ȴ²»ÐèҪÕâô³¤µÄ˵Ã÷¡£ ¡¡¡¡¾ÝÎÒËù֪£¬°ÑÍÁµØÉú²úÎ￴×÷¸÷¹úÊÕÈ뼰²Ƹ»µÄΨһÀ´Դ»òÖ÷ҪÀ´ԴµÄѧ˵£¬´ÓÀ´δ±»Èκιú¼ÒËù²ÉÓã»ÏÖÔÚËüֻÔڷ¨¹úÉÙÊý²©ѧ¶àÄܵÄѧÕߵÄÀíÂÛÖдæÔÚך£¶ÔÓÚһÖÖδÔø¡¢ҲÐíÓÀԶ²»»áΣº¦ÊÀ½çÉÏÈκεط½µÄѧ˵µÄÃýÎ󣬵±Ȼ²»ֵµó¤ƪ´óÂÛȥÌÖÂۡ£²»¹ý£¬¶ÔÓÚÕâ¸ö¼«΢ÃîµÄѧ˵£¬Îҽ«¾¡ÎÒËùÄܣ¬Ã÷ȷ˵³öËüµÄÂÖÀª¡£ ¡¡¡¡·Ò×ʮËÄÓÐÃûµĴ󳼿ƶû²®Ìأ¬ΪÈËÕýֱ£¬¶øÇÒÇÚÃãÒ쳣£¬ÓÐԨ²©µÄ֪ʶ£¬¶ÔÓڹ«¹²ÕËĿµļì²飬Óָ»Óо­Ñ飬¼«Æ侫Ã÷¡£×Ü֮£¬Ôڸ÷·½Ã棬ËûµÄÄÜÁ¦¶¼ʹËû¶ÔÓڹ«¹²ÊÕÈëµÄÕ÷ÊÕÓë֧³ö£¬Äܸãµþ®¾®ÓÐÌõ¡£²»Ðң¬Õâλ´󳼱§ÓÐÖØÉÌÖ÷ÒåµÄһÇÐƫ¼û¡£ÕâÖÖѧ˵£¬¾ÍÆäÐÔÖÊÓëʵÖÊ˵£¬¾ÍÊÇһÖÖÏÞÖÆÓë¹ÜÀíµÄѧ˵£¬ËùÒԣ¬¶ÔÓÚһ¸ö¹ßÓڹÜÀí¸÷²¿¹«Î񣬲¢ÉèÖñØҪµÄÖƲÃÓë¼ල£¬ʹ¸÷²¿ÊÂÎñ²»ÓâԽÆäÊʵ±·¶Χ£¬¶øÓÖÇڿ๤×÷µÄÊÂÎñ¼ң¬ÊǺܺÏƢθµġ£Ëû¶ÔÓÚһ¸ö´ó¹úµĹ¤ҵ¼°ÉÌҵËù²ÉÓõĹÜÀí·½ʽ£¬Óë¹ÜÀí¸÷²¿¹«Îñµķ½ʽһÑù£»Ëû²»Èø÷¸öÈËÔÚƽµÈ×ÔÓÉÓëÕýÒåµĹ«ƽ¼ƻ®Ï£¬°´Õո÷×ԵÄ·Ïߣ¬׷Çó¸÷×ԵÄÀûÒ棬ȴ¸øijЩ²úҵ²¿ÃÅÒÔÒ쳣µÄÌØȨ£¬¶ø¸øÆäËû²úҵ²¿ÃÅÒÔÒ쳣µÄÏÞÖơ£Ëû²»½öÏóŷÖÞÆäËû´ó³¼һÑù£»¸ü¶àµعÄÀø³ÇÊвúҵ£¬ºÜÉٹÄÀøũ´å²úҵ£»¶øÇÒËû»¹ԸÒâѹÒÖũ´å²úҵ£¬ÒÔ֧³ֳÇÊвúҵ¡£ΪÁËʹ³ÇÊоÓÃñµÃÒÔÁ®¼۹ºÂòʳÎ´Ӷø¹ÄÀøÖÆÔìҵÓë¹úÍâóÒף¬ËûÍêȫ½ûֹ¹ÈÎïÊä³ö£»ÕâÑù¾Íʹũ´å¾ÓÃñ²»ÄܰÑÆä²úҵ²úƷµÄ×îÖØҪ²¿·֣¬Ô˵½Íâ¹úÊг¡ÉÏȥ¡£ÕâÖֽûÁ¼ÓÉϾÉÈÕÏÞÖƸ÷ʡ¼ä¹ÈÎïÔËÊäµĸ÷ʡ·¨¹棬ÔټÓÉϸ÷ʡ¶Ըû×÷ÕߵĺáÕ÷±©Á²£¬¾ͰÑÕâ¸ö¹ú¼ҵÄũҵ£¬ѹÒֵò»ÄÜÒÀÕÕ×ÔȻÇ÷Êƣ¬°´Æä·ÊÎÖÍÁÈÀºͼ«ºÃÆøºòËùӦÓеķ¢չ³̶ȶø·¢չÁˡ£ÕâÖÖÏú³Á¾ÚɥµÄ״̬£¬ÔÚȫ¹ú¸÷µض¼¶àÉٸоõµ½Áˣ»¹ØÓڷ¢ÉúÕâÖÖ״̬µÄԭÒò£¬ÓÐÐí¶෽ÃæҵÒѿªʼÉîÌ֡£¿ƶû²®ÌعÄÀø³ÇÊвúҵ¹ýÓڹÄÀøũ´å²úҵµİ취£¬ËƺõÊǴËÖÐԭÒò֮һ¡£ @@ -1680,9 +1680,9 @@ -µÚÎåƪ¡¡Â۾ýÖ÷»ò¹ú¼ҵÄÊÕÈË -µÚһÕ¡¡Â۾ýÖ÷»ò¹ú¼ҵķÑÓà -µÚһ½ڡ¡Â۹ú·À·Ñ +µÚÎåƪ¡¡Â۾ýÖ÷»ò¹ú¼ҵÄÊÕÈË +µÚһÕ¡¡Â۾ýÖ÷»ò¹ú¼ҵķÑÓà +µÚһ½ڡ¡Â۹ú·À·Ñ ¡¡¡¡¾ýÖ÷µÄÒåÎñ£¬Ê×Ôڱ£»¤±¾¹úÉç»áµİ²ȫ£¬ʹ֮²»ÊÜÆäËû¶ÀÁ¢Éç»áµı©ÐÐÓëÇÖÂԡ£¶ø´ËÖÖÒåÎñµÄÍê³ɣ¬ÓÖֻÓнèÖúÓڱøÁ¦¡£µ«ƽʱ׼±¸±øÁ¦ºÍսʱʹÓñøÁ¦µķÑÓã¬ÔòÒòÉç»á״̬²»ͬÒԼ°½ø»¯ʱÆڲ»ͬ£¬¶ø´ó²»Ïàͬ¡£ ¡¡¡¡¾Í×îµͼ¶×î´ÖҰµÄá÷ÁÔÃñ×å˵£¬ÈËÈ˶¼ÊÇá÷ÁÔÕߣ¬ÈËÈËÒ඼ÊÇսʿ¡£Ïֽñ±±ÃÀÍÁÈˣ¬¾ÍÊÇÈç´ˡ£µ±ËûΪ±£»¤Éç»ᣬ»òΪÉç»Ḵ³ð¶øȥս³¡´òÕÌʱ£¬ËûҲÊÇÒÔ×ԼºµÄÀͶ¯ά³Ö×Լº£¬ÏóÔڼÒÖÐʱһÑù¡£ÔÚÕâÖÖ״̬Ï£¬µ±Ȼ¼ÈûÓоýÖ÷£¬ҲûÓйú¼ҡ£ËûµÄÉç»ᣬÎÞÐëΪËûÉÏս³¡£¬»òÎÞÐëΪËûÔÚ×÷սÆڼäµÄÉú»µ£ºÎÖַÑÓᣠ¡¡¡¡¾ͱȽϽø²½µÄÓÎÄÁÃñ×åµÄÉç»á״̬£¬Èç÷²÷°È˺Ͱ¢À­²®È˵ÄÉç»á״̬˵£¬Çé¿öҲ´óµÖÏàͬ¡£ÔÚÄÇÖÖÉç»áÖУ¬¸÷¸öÈËÊÇÓÎÊÕÕߣ¬ͬʱҲÊÇսʿ¡£ËûÃÇͨ³£ÔÚÅîĻÖУ¬»òÔÚһÖÖÈÝÒ×Òƶ¯µÄÓÐÅñÂí³µÖÐÉú»ûÓÐһ¶¨סËù¡£Õû¸ö²¿Âä»òÕû¸öÃñ×壬ÿÄêÒ򼾽ڲ»ͬ£¬»òÒòÆäËûż·¢Ê¹ʣ¬ʱʱǨÒơ£µ±ËûÃǵÄÐóȺ£¬°Ñһ¸öµط½µÄÄÁ²ݳԾ¡Áˣ¬ËûÃDZãÒÆסÁíһµط½£¬ÓִÓÄǵط½ÒÆÍùµÚÈýµط½¡£ËûÃÇÔڸÉÔ^½ڣ¬ǨÍùºӰ¶£»ÔÚÒõʪ¼¾½ڣ¬ÓÖÍ˻ظߵء£µ±ËûÃDZ¼¸°ս³¡ʱ£¬²¢²»°ÑÉüÐ󽻸øÀÏÈ˸¾Ů¶ùͯ¿´»¤£¬Ҳ²»°ÑÀÏÈ˸¾Ů¶ùͯÅ×Ôںó±ߣ¬¶ø²»ÓèÒԱ£»¤º͹©Ñø¡£ËûÃÇȫÃñ×åÔÚƽʱ¾͹ý¹ßÁËÁ÷À˵ÄÉú»ËùÒÔһµ±սÕù£¬ÈËÈ˶¼ºÜÈÝÒױäΪսʿ¡£²»¹Ü×÷Ϊ¾ü¶ӽø¾üʱ£¬»ò×÷ΪÓÎÄÁÃñÓÎÊÕʱ£¬ËûÃǵÄÉú»ʽ£¬×ܴóµÖһÑù£¬ËäȻĿµÄÓв»ͬ¡£սÕùÆðÀ´£¬ËûÃÇһͬ×÷ս£¬ËùÒÔÿ¸öÈ˶¼¾¡ÆäËùÄÜÀ´¶¯×÷¡£÷²÷°¸¾Ů²μÓսÕù£¬ÄÇÊÇÎÒÃÇʱ³£Ìýµ½µġ£ËûÃÇÈç¹ûսʤÁˣ¬µз½ȫÖÖ×åËùÓеÄһÇУ¬¶¼³ÉÁËËûÃǵÄʤÀû±¨³ꣻÈç¹ûս°ÜÁˣ¬¾ÍһÇж¼Í군£¬×ԼºµÄÉüÐóÄËÖÁ¸¾Ů¶ùͯ£¬ȫ¶¼³ÉÁËսʤÕߵÄսÀûƷ¡£Á¬´󲿷ÖûÓÐսËÀµÄսʿ£¬Ҳ²»µò»Ϊµõ½µ±ǰµÄÉú»î×ÊÁ϶ø·þ´ÓÕ÷·þÕߡ£ÆäÓàµÄһ²¿·ÖÈˣ¬ͨ³£±»ÖðËÄɢ£¬ËĴ¦ÌÓÍö¡£ @@ -1727,7 +1727,7 @@ ¡¡¡¡×Ü֮£¬¾ýÖ÷µĵÚһÒåÎ񣬾ÍÊDz߱¾¹úÉç»áµİ²ȫ£¬ʹÆ䲻ÊÜÆäËû¶ÀÁ¢Éç»áµĺᱩÓëÇֻڡ£ÕâÖÖÒåÎñµÄʵÐУ¬ÊƱØËæÉç»áÎÄÃ÷µĽø²½£¬¶øÖð½¥ÐèҪԽÀ´Խ´óµķÑÓá£ԭÀ´ÔÚƽʱÔÚսʱ¶¼ÎÞÐë¾ýÖ÷֧³öºεȷÑÓõÄÉç»áµıøÁ¦£¬Ëæ×ÅÉç»á½ø²½µĹý³̣¬³õÔòÔÚսʱҪ¾ýÖ÷³öǮά³֣¬ºóÔòÔÚƽʱÒà·ǾýÖ÷³öǮά³ֲ»¿ɡ£ ¡¡¡¡»ðÆ÷·¢Ã÷ºó£¬սÕù¼¼ÊõÆðÁ˴ó±仯¡£ÓÚÊǣ¬ƽʱѵÁ·һ¶¨±ø¶սʱʹÓÃһ¶¨±ø¶ËùÐèµķÑÓ㬶¼½øһ²½Ôö¼ӡ£¾ü¶ÓËùʹÓõÄÎäÆ÷Ó뵯ҩ£¬¶¼±ÈÒÔǰ¸ü¹ó¡£Óëì¼°¹­¼ý±Ƚϣ¬¶ÌǹÊǸü¹óµÄÎäÆ÷£¬ÓëåóÅڻòʯÅڱȽϣ¬´óÅڻò¾ÊÅÚҲÊǸü¹óµÄÎäÆ÷¡£½ü´úÔıøËùÏû·ѵĻðҩ£¬·ÅÉä³öȥ£¬¾Ͳ»¸´·µ£¬Õâ¸ü·Ǿ޶îµķÑÓò»¿ɡ£ÖÁÓÚÍùʱ£¬ÔıøËùͶµÄ죬Ëù·ŵļý£¬¾ùºÜÈÝÒ×Êջأ¬²¢ÇÒÆä¼Ûֵ¼«΢¡£ÓëŬÅÚʯÅڱȽϣ¬´óÅھÊÅڲ»½öΪ¸߼۵Ļúе£¬ÇÒΪ·dz£±¿ÖصĻúе¡£ÕⱿÖػúе£¬ÖÆÔìÆðÀ´£¬Ҫ½ϴóµķÑÓã¬ÖƳɺóÔËÍùս³¡£¬ҲҪ½ϴóµķÑÓᣴËÍ⣬½ü´ú´óÅڵÄ×÷սЧÁ¦£¬·ÇÍùÎôʯåó¿ɱȣ¬ËùÒÔҪ¸øһ¸ö¶¼ÊÐÉè·ÀÀ´µÖÓùÕâ´óÅڵĹ¥»÷£¬ÄÇÅÂֻÊǼ¸¸öÐÇÆÚҲÀ§Äѵö࣬Òò¶ø£¬ÆäËùÐè·ÑÓÃҲºƴóµöࡣ½ü´ú£¬ÓÐÖÖÖÖԭÒòʹ¹ú·À·ÑÓÃÈÕÒæÔö´ó¡£ÔÚÕⷽÃ棬ÊÂÎï×ÔȻÍÆÒƵIJ»¿ɱÜÃ⵼á¹û£¬Óֱ»սÕù¼¼ÊõÉϵĴó¸ïÃü´ٽø²»É٣¬¶øÒýÆðÕâ¸ö´ó¸ïÃüµģ¬Ëƺõ²»¹ýÊÇһ¸öż·¢Ê¼þ£¬¼´»ðҩµķ¢Ã÷¡£ ¡¡¡¡½ü´úսÕù»ðҩ·ÑÓõĺƴó£¬ÏÔȻ¸øÄܹ»¸ºµ£´˺ƴó·ÑÓõĹú¼ÒÌṩÁËһÖÖÀûÒ棬¶øʹÎÄÃ÷¹ú¼ҶÔҰÂù¹ú¼ÒÁ¢ÓÚÓÅʤµĵØλ¡£ÔڹŴú£¬¸»ԣÎÄÃ÷¹ú¼ҺÜÄѷÀÓùƶÇîҰÂù¹ú¼ҵÄÇÖÂԣ»Ôڽü´ú£¬ƶÇîҰÂù¹ú¼ÒȴºÜÄѷÀÓù¸»ԣÎÄÃ÷¹ú¼ҵÄÔ׸»ðÆ÷µķ¢Ã÷£¬է¿´ÆðÀ´£¬ËƶÔÎÄÃ÷µij־ÃÓë¼ÌÐøÓк¦¡£µ«ʵ¼ÊÉϣ¬Ä˶ÔÎÄÃ÷µij־ÃÓë¼ÌÐøÓÐÀû¡£ -µڶþ½ڡ¡ÂÛ˾·¨¾­·Ñ +µڶþ½ڡ¡ÂÛ˾·¨¾­·Ñ ¡¡¡¡¾ýÖ÷µĵڶþ¸öÒåÎñ£¬Ϊ±£»¤ÈËÃñ²»ʹÉç»áÖÐÈκÎÈËÊÜÆäËûÈ˵ÄÆÛÎê»òѹÆȣ¬»»ÑÔ֮£¬¾ÍÊÇÉèÁ¢һ¸öÑÏÕýµÄ˾·¨ÐÐÕþ»ú¹¹¡£ÕâÖÖÒåÎñµÄʵÐУ¬ÒòÉç»á¸÷ʱÆڵIJ»ͬ¶øÓзÑÓôóСµIJîÒ졣 ¡¡¡¡ÔÚá÷ÁÔÃñ×åµÄÉç»ᣬ¼¸ºõ̸²»µ½ÓÐʲô²Ʋú£¬¼´ʹÓУ¬Ҳ²»¹ýֵÁ½ÈýÈÕÀͶ¯¼ÛֵµIJƲú°ÕÁˡ£ÄÇÖÖÉç»ᣬµ±ȻÓò»×źεȹ̶¨µÄÉóÅй٣¬»òÕߺεȾ­³£µÄ˾·¨ÐÐÕþ»ú¹¹¡£ûÓвƲúµÄÈËÃǣ¬ÆäËù»¥Ïà»ÙÉ˵쬶¥¶಻¹ýÊDZ˴˵ÄÃûÓþ»òÉíÌ塣¶øÇң¬±»ÈËɱº¦£¬±»ÈËŹÈ裬±»È˷̰ùµÄÈˣ¬ËäȻ¸е½ʹ¿࣬¶øɱÈËÕߣ¬ŹÈèÈËÕߣ¬·̰ùÈËÕߣ¬ȴµò»µ½ʲôÀûÒ档¿ÉÊÇË𺦲ƲúÇéÐξͲ»ͬÁˡ£¼Ӻ¦ÓÚÈËÕßËùµõÄÀûÒ棬ÍùÍùÓëÃÉÊÜÉ˺¦ÕßËùµÀµÄËðʧÏàµȡ£Äܹ»¼¤ʹÈËÃÇȥ»ÙÉËËûÈËÉíÌå»òÃûÓþµģ¬ΩÓмµ¶ʡ¢Թºޡ¢·ßŭµÈÇéÐ÷£¬¶øÇҴó¶àÊýÈ˲¢²»³£ÊÜÕâЩÇéÐ÷µÄ֧Å䡣ÄÇÅÂ×î¶ñµÄÈˣ¬Ҳ²»¹ýżȻÊÜÕâЩÇéÐ÷µÄӰÏ졣´ËÍ⣬ÕâЩÇéÐ÷µÄÂú×㣬¶ÔijÖÖÈËÎÞÂÛÊÇÈçºÎÓä¿죬µ«ÒòΪËü²»´øÀ´ÈκÎʵ¼ʵĺͳ־õÄÀûÒ棬ËùÒԴó¶àÊýÈË×ÜÊÇÄþԸÉ÷ÖؿËÖƣ¬²»ÇáÇóÆäÂú×㡣¼´ʹÉç»áÉÏûÓÐ˾·¨¹ٴæÔڣ¬±£»¤ÈËÃDz»ÊÜÕâЩÇéÐ÷·¢×÷µÄÇֺ¦£¬ÈËÀàÒÀ×ÅËûµı¾Ðԣ¬Ҳ»¹ÄÜÔÚÏ൱°²¶¨״̬Ϲ²ͬÉú»¿ÉÊǣ¬¸»ÕߵÄ̰ÓûÓëҰÐģ¬ƶÕßÑá¶ñÀͶ¯̰ͼÑÛǰ°²ÀֵÄÐÔÇ飬ȴÔÚ×ãÒԼ¤·¢Çֺ¦ËûÈ˲ƲúµÄÇéÐ÷¡£²¢ÇÒÕâÇéÐ÷ÔÚ×÷ÓÃÉÏԶΪÀι̣¬ÔÚӰÏìÉÏԶΪÆձ顣Óдó²ƲúµÄËùÔڣ¬¾ÍÊÇÓдó²»ƽµȵÄËùÔڡ£ÓÐһ¸ö¾޸»µÄÈˣ¬ͬʱÖÁÉٱØÓÐÎå°ٸöÇîÈˡ£ÉÙÊýÈ˵ĸ»ԣ£¬ÊÇÒԶàÊýÈ˵Äƶ·¦ΪǰÌáµġ£¸»È˵ÄÀ«´£¬»ἤŭƶÕߣ¬ƶÈ˵ÄØҷ¦ºͼµ¶ʣ¬»áÇýʹËûÃÇÇֺ¦¸»ÕߵIJƲú¡£ÄÇЩӵÓÐÓɶàÄêÀͶ¯»òÀÛÊÀÀͶ¯Ðî»ýÆðÀ´µIJƲúµÄÈˣ¬ûÓÐ˾·¨¹ٱ£Õϱӻ¤£¬ÄÄÄܸßÕí¶øÎÔһҹÁ¨¡£¸»ÕßËæʱ¶¼Óв»¿ɲâ֪µĵÐÈËÔڰüΧËû£¬Ëû×ÝûÓм¤ŭµÐÈˣ¬ËûȴÎ޷¨Âú×ãµÐÈ˵ÄÓûÍû¡£ËûÏë±ÜÃâµÐÈ˵ÄÇֺ¦£¬ֻÓÐÒÀÀµǿÓÐÁ¦µÄ˾·¨¹ٵı£»¤£¬˾·¨¹ÙÊǿÉÒԲ»¶ϳÍÖÎһÇзǷ¨ÐÐΪµġ£Òò´ˣ¬´ó×ڼÛֵ²ƲúµĻñµã¬±ØȻҪÇóÃñÕþÕþ¸®µĽ¨Á¢¡£ÔÚûÓвƲú¿ÉÑԣ¬»򶥶àֻÓÐֵÁ½ÈýÈÕÀͶ¯µļÛֵµIJƲúµÄÉç»ᣬ¾Ͳ»ÕâÑùÐèҪÉèÁ¢ÕâÖÖÕþ¸®¡£ ¡¡¡¡һ¸öÃñÕþÕþ¸®£¬±ØÏÈȡµÃÈËÃñµķþ´ӡ£ÃñÕþÕþ¸®µıØҪ³̶ȣ¬¼ÈÊÇÖð½¥Ëæ²Ʋú¼ÛֵµÄÔö´ó¶øÔö´ó£¬ËùÒÔʹÈËÃñ×ÔȻ·þ´ӵÄÖ÷ҪԭÒò£¬ҲÊÇÖð½¥Ëæ²Ʋú¼ÛֵµÄÔö³¤¶ø·¢չ¡£ÈËÃñºÎÒԻáÐγÉÕâÖַþ´ÓÐԣ¬»òÕß˵£¬ÔÚÓÐÈκÎÃñÕþ»ú¹¹ÒÔǰ£¬ºÎÒÔÈô¸ÉÈ˾ͶÔËûÃǵĴ󲿷Öͬ°ûÓÐ֧ÅäȨÁ¦£¬ÕâËƺõÓÐËÄÖÖ×ÔȻԭÒò»òÇé¿ö¡£ @@ -1752,7 +1752,7 @@ ¡¡¡¡µ«Êǣ¬ÎÞÂÛ˾·¨ÐÐÕþ·ÑÓÃÊÇÓÉ˾·¨·½Ãæ×ÔÐÐÉ跨³ï´룬»ò˾·¨ÈËԱµĶ¨¶îнٺÊÇÓÉÆäËû²ÆԴ¿ª֧£¬¹ÜÀíÕâ²ÆԴµÄÔðÈΣ¬֧¸¶ÕâнٺµÄÔðÈΣ¬×ÜÎÞÐëίÖîÐÐÕþµ±¾֡£Õâ²ÆԴÓеÄÊdzöÓڵزúµĵØ×⣬·¨Ժ¼ÈÓÉÕâµØ×âά³֣¬ÄǹÜÀíµزúµÄÔðÈΣ¬¾Ͳ»·ÁÓÉËüÃǸ÷×Էֱ𸺵£¡£Õâ²ÆԴҲÓÐÊdzö×Ôһ¶¨Êý¶îµĻõ±ҵÄÀûϢ£¬·¨Ժ¼ÈÓÉÕâÀûϢά³֣¬³ö´ûÄǻõ±ҵÄÔðÈΣ¬Ҳ¾Ͳ»·ÁÈÃËüÃǸ÷×Էֱ𸺵£¡£ËոñÀ¼ÓÐһÖÖѲ»ط¨Ժ£¬Æ䷨¹ٵÄнٺ£¬¾ÍÓÐһ²¿·֡ª¡ªËäֻ²»¹ýһС²¿·֡ª¡ªÊdzö×Ôһ¶¨¶î»õ±ҵÄÀûϢ¡£µ«Êǣ¬ÏóÕâÑùһÖֲÆԴ£¬ÊDZØȻȱ·¦°²¶¨ÐԵġ£ÒԲ»°²¶¨µIJÆԴ£¬³䵱һÖÖӦµ±ÓÀ¾Ãά³ֵĻú¹¹µľ­·ѣ¬Ëƺõ²»´óÍ׵±¡£ ¡¡¡¡˾·¨ȨºÍÐÐÕþȨµĻ®·֣¬ԭʼËƺõÊÇÓÉÓÚÉç»á½ø²½¡¢Éç»áÊÂÎñÒò¶øÔö¼ӵĽá¹û¡£Éç»áÊÂÎñÈÕÒæ¼Ӷ࣬˾·¨ÐÐÕþ±äµÃÄÇôÂ鷳¸´Ôӣ¬ÓÚÊǵ£µ±ÕâÈÎÎñµÄÈˣ¬¾Ͳ»ÄÜÔٷÖÐÄעÒ⵽ÆäËû·½Ã档ͬʱ£¬µ£µ±ÐÐÕþְÔðµÄÈˣ¬ÒòΪÎÞϾ´¦Àí˽ÈËËßËϰ¸¼þ£¬ËùÒԣ¬¾ÍÈÎÃü´úÀíÈ˴úΪ´¦Àí¡£µ±ÂÞÂíµ۹ú¡ʢʱ£¬´óִÕþ¹ÙÕþÎñ·±æ£¬ÍòÄѷÖÉí¹ýÎÊ˾·¨ÐÐÕþ£¬ÓÚÊǾÍÓдúÐÐÕâÖÖְÎñµÄÃñÕþ¹ٵÄÈÎÃü¡£ºóÀ´£¬ÂÞÂíµ۹úûÂäÁˣ¬ËüµķÏÐæÉϽ¨Á¢ÁËŷÖ޸÷Íõ¹ú¡£ÕâЩÍõ¹úµľýÖ÷¼°´óÁìÖ÷Ãǣ¬¶¼ÏÖ×ԼºִÐÐ˾·¨ÐÐÕþΪһÖֹýÓڷ³ÄѶøÇÒÓÐʧÉí·ֵÄÈÎÎñ¡£Òò´ˣ¬ËûÃÇͨͨίÈδúÀíÕ߻òÉóÅйÙȥִÐУ¬½èÒÔÍÆÍÑÕâÏîÈÎÎñ¡£ ¡¡¡¡˾·¨ȨÈ粻ÍÑÀëÐÐÕþȨ¶ø¶ÀÁ¢£¬ҪÏ빫µÀ²»ΪÊÀË×ËùνÕþÖÎÊÆÁ¦ËùÎþÉü£¬ÄǾÍǧÄÑÍòÄÑÁˡ£¼縺¹ú¼ÒÖØÈεÄÈˣ¬×ÝÎ޺εȸ¯°ܹÛÄÓÐʱҲ»áÈÏΪ£¬ΪÁ˹ú¼ҵÄÖشóÀûº¦¹Øϵ£¬±ØÐëÎþÉü¸öÈ˵ÄȨÀû¡£µ«Êǣ¬¸÷¸öÈ˵Ä×ÔÓɣ¬¸÷¸öÈ˶ÔÓÚ×ԼºËù±§µİ²ȫ¸У¬ȫÀµÓй«ƽµÄ˾·¨ÐÐÕþ¡£Ϊʹ¸÷¹úÈ˸е½×ԼºһÇÐӦÓÐȨÀû£¬ȫÓб£Õϣ¬˾·¨Ȩ²»µ«ÓÐÓëÐÐÕþȨ·ÖÀëµıØҪ£¬ÇÒÓÐÍêȫÍÑÀëÐÐÕþȨ¶ø¶ÀÁ¢µıØҪ¡£ÉóÅйٲ»ӦÓÉÐÐÕþµ±¾ÖÈÎÒâ°ÕÃ⣬ÉóÅйٵı¨³êҲ²»ӦËæÐÐÕþµ±¾ֵÄÒâÏò»򾭼ÃÕþ²߶ø±ä¸ü¡£ -µÚÈý½ڡ¡Â۹«¹²¹¤³̺͹«¹²»ú¹صķÑÓà +µÚÈý½ڡ¡Â۹«¹²¹¤³̺͹«¹²»ú¹صķÑÓà ¡¡¡¡¾ýÖ÷»ò¹ú¼ҵĵÚÈýÖÖÒåÎñ¾ÍÊǽ¨Á¢²¢ά³ÖijЩ¹«¹²»ú¹غ͹«¹²¹¤³̡£ÕâÀà»ú¹غ͹¤³̣¬¶ÔÓÚһ¸ö´óÉç»ᵱȻÊÇÓкܴóÀûÒæµģ¬µ«¾ÍÆäÐÔÖÊ˵£¬ÉèÓɸöÈ˻òÉÙÊýÈ˰ìÀí£¬ÄÇËùµÃÀûÈó¾ö²»Äܳ¥ÆäËù·ѡ£ËùÒÔÕâÖÖÊÂҵ£¬²»ÄÜÆÚÍû¸öÈ˻òÉÙÊýÈ˳öÀ´´´°ì»òά³֡£²¢Çң¬Ëæ×ÅÉç»ᷢ´ïʱÆڵIJ»ͬ£¬ִÐÐÕâÖÖÒåÎñËùÐèµķÑÓõĴóСҲ·dz£²»ͬ¡£ ¡¡¡¡³ýÉÏÊö¹ú·À¼°˾·¨ÐÐÕþÁ½·½ÃæËù±ØÐèµĹ«¹²Éèʩº͹«¹²¹¤³ÌÍ⣬ÓëÆäÐÔÖÊÏàͬµÄÆäËûÉèʩº͹¤³̣¬Ö÷ҪΪ±ãÀûÉç»áÉÌҵ£¬´ٽøÈËÃñ½ÌÓýµĹ«¹²Éèʩº͹¤³̡£½ÌÓýÉϵÄÉèʩ£¬¿ɴó±ðΪÁ½Ö֣ºһÊǹØÓÚÇàÄê½ÌÓýµÄÉèʩ£¬һÊǹØÓÚһÇÐÄêÁäÈËÃñµĽÌÓýµÄÉèʩ¡£·²´ËÖÖÖÖÉèʩº͹¤³ÌËùÐèµķÑÓ㬸ÃÈçºÎ×îÍ×ÉƵØ֧¸¶£¬Ôڱ¾ÕÂÕâһ½ڷÖ×÷ÒÔÏÂÈýÏîÑо¿¡£ ¡¡¡¡µÚһÏîÂ۱ãÀûÉç»áÉÌҵµĹ«¹²¹¤³̺͹«¹²Éèʩ±ãÀûһ°ãÉÌҵµÄ @@ -1878,7 +1878,7 @@ ¡¡¡¡Öλ¯¸Ľø£¬¾üʽÌÁ·£¬±ãÐëÓÉÕþ¸®·ÑÏ൱ÆøÁ¦ÓèÒÔ֧³֣¬·ñÔò²»ÃâÈս¥ËÉи£¬´Ӷø´ó¶àÊýÈËÃñµÄÉÐÎ侫Éñ£¬ͬʱËæ×Å˥Íˣ»¹ØÓÚÕâÖÖÇ÷Êƣ¬½ü´úŷÖÞÊÂÀýÌáʾµÃʮ·ÖÃ÷Ïԡ£¸÷¸öÉç»áµİ²ȫ£¬×ܶàÉÙÒÀÀµ´ó¶àÊýÈËÃñµÄÉÐÎ侫É񡣹ÌȻÔڽü´ú£¬ûÓо«Á·µij£±¸¾ü£¬µ¥¿¿ÉÐÎ侫Éñ£¬ҲÐíÊDz»¹»·ÀÓùÉç»ᡢ±£ÕÏÉç»áµġ£µ«ÊǸ÷¹«ÃñÈ綼¾ßÓоüÈ˾«Éñ£¬ÄÇËùÐèµij£±¸¾ü¾Ϳɼõȥ²»É١£¿öÇң¬ÆÕͨ¶ÔÓг£±¸¾ü»áΣº¦×ÔÓɵÄÓÇÂǣ¬ÎÞÂÛÕâ¸öΣº¦ÊÇÕæµÄΣº¦»òֻÊÇÏëÏóµÄΣº¦£¬Ҳ±ػáÒòÊÐÃñ¾ßÓоüÈ˾«É񣬶ø¼õÉÙÐí¶ࡣÕâÉÐÎ侫É񡢾üÈ˾«Éñ£¬һ·½ÃæÔÚÍâµÐÇÖÂÔʱ£¬¿ÉÒԴó´ó±ãÀû³£±¸¾üµÄÐж¯£»Áíһ·½Ã棬¼Ùʹ²»Ðҳ£±¸¾ü·¢ÉúΥ·´¹ú¼ÒÏܷ¨µÄʹʣ¬ËüÓֿÉÒԴó´óµؼÓÒÔ×èֹ¡£ ¡¡¡¡¾Íά³ִó¶àÊýÈËÃñµÄÉÐÎ侫Éñ˵£¬ϣÀ°¼°ÂÞÂíÍùʱµÄÖƶȣ¬Ëƺõ±Ƚü´úËùνÃñ±øÖƶÈÓÐЧ¶àÁˡ£ǰÖÖÖƶȣ¬¼򵥵öࡣÖƶÈһ¾­ȷÁ¢£¬¼´¿É×ÔÐÐÆäÊ£¬¶øÒÔ×îÍêȫµĻîÁ¦ά³ÖÏÂȥ£¬Õþ¸®µÄעÒ⣬¼¸ºõÊÇȫȻÓò»×ŵġ£ÖÁÓÚҪÔÚÏ൱³̶ÈÉÏά³ֽü´úÃñ±øµĸ´ÔӹæÔ򣬾ÍÐëÕþ¸®²»¶ϵĺͷÑÁ¦µÄעÒ⣻Õþ¸®²»עÒ⣬Õâ¹æÔò¾Ͳ»ÃâÍêȫ±»ºöÊӣ¬»òÕßÍêȫ·϶ø²»Ó᣼Ó֮£¬¹ŴúÖƶȵÄӰÏìԶΪÆձ顣ÔÚÄÇÖÖÖƶÈÏ£¬ÈËÃñȫÌ壬¶¼»áʹÓÃÎäÆ÷¡£½ü´úÔò¿ÖųýÈðʿÍ⣬¸÷¹úÓÉÃñ±ø¹æÔòʩ½̵ķ¶Χ£¬¶¼²»¹ý¼°¸ɹúÃñÖеÄ×îС²¿·֡£µ«Êǣ¬һ¸ö²»ÄܷÀÓù×Լº»òΪ×Լº¸´³ðµÄÇÓųÕߣ¬·ÖÃ÷ȱ·¦ÁËÈËÀà×ÊÐÔÖÐ×îÖØҪµÄһ²¿·֡£ÕâÑù£¬Ôھ«Éñ·½ÃæµIJзϻò»ûÐÎÎÞÒìÓÚijһ×îÖØҪ֫Ìå²ð»ÙÁˡ¢ʧÓÃÁ˵ÄÈËÔÚÈâÌ巽ÃæµIJзÏÓë»ûÐΡ£¶øÇң¬Á½Õß֮ÖУ¬ǰÕßÏÔȻÊǸü²»Ðң¬ÊǸü¿ÉÁ¯¡£ÒòΪ£¬¿àÀֵĸоõ£¬ȫÉúÓÚÐ쬯äÊÜӰÏìÓÚÈâÌåµĽ¡ȫ»򲻽¡ȫ¼´²зϻòÍêȫµÄÉ٣¬¶øÊÜӰÏì¸ɾ«ÉñµĽ¡ȫ»򲻽¡ȫ¼´²зϻòÍêȫµĶࡣÄÇÅÂÔÚÉç»áµķÀÓùÉÏÒÑÓò»×ÅÈËÃñµÄÉÐÎ侫É񣬵«Ϊ·ÀֹÇÓų±ØȻ»áÒýÆðµÄÕâÖ־«ÉñÉϵIJзϡ¢»ûÐμ°³ó¹ÖÔÚÈËÃñ֮¼äÂûÑӴ«²¥£¬Õþ¸®ÈÔӦ¼ÓÒÔ×îÇÐʵµÄעÒ⡣ÕâºÃÏó񲲡¼°ÆäËûÌÖÑáµġ¢ÁîÈ˲»Óä¿ìµļ²²¡£¬Ë䲻»áÖÂËÀ£¬»òûÓÐΣÏգ¬µ«Ϊ·ÀֹÔڴó¶àÊýÈËÃñ֮¼䴫²¥£¬Õþ¸®ÈÔӦ¼ÓÒÔ×îÇÐʵµÄעÒ⡣ÕâעÒ⣬×Ýʹ³ý·ÀֹÉç»áµÄÕâÖִóº¦Í⣬ûÓкεÈÆäËû¹«¹²ÀûÒ棬ÒàÊÂÔڱØÐС£ ¡¡¡¡ͬÑùµÄ˵·¨£¬¿ÉÊÊÓÃÓÚÄdz£³£ʹÎÄÃ÷Éç»áһÇÐϼ¶ÈËÃñµÄÀí½âÁ¦ʧȥ×÷ÓõÄÎÞ֪ºʹóÓ޶ۡ£һ¸öÈ˲»ÄÜÊʵ±ʹÓÃÈ˵ÄÖÇÄܣ¬¼ÙÈç˵Êǿɳܵϰ£¬ÄǾͱÈÇÓųÕ߻¹Ҫ¿ɳܡ£ÄÇÊÇÈËÐÔÖиüÖØҪ²¿·ֵIJзϺͻûÐΡ£¹ú¼Ҽ´ʹÓÉϼ¶ÈËÃñµĽÌÓý£¬µò»µ½ºεÈÀûÒ棬Õâ½ÌÓýÈÔֵµùú¼ÒעÒ⣬ʹϼ¶ÈËÃñ²»ÖÁÏÝÓÚȫÎ޽ÌÓýµÄ״̬¡£ºοö£¬Õâ°ãÈËÃñÓÐÁ˽ÌÓý£¬¹ú¼ҿÉÊÜÒ治dzÄء£ÔÚÎÞ֪µĹúÃñ¼䣬¿ñÈȺÍÃÔÐţ¬ÍùÍùÈÇÆð×î¿ÉŵÄÈÅÂҡ£һ°ãϼ¶ÈËÃñËùÊܽÌÓýÓú¶࣬Óú²»»áÊܿñÈȺÍÃÔÐŵÄÃԻ󡣼Ó֮£¬ÓнÌÓýÓÐ֪ʶµÄÈˣ¬³£±ÈÎÞ֪ʶ¶øÓޱ¿µÄÈˣ¬¸ü֪Àñ½ڣ¬¸üÊØÖÈÐò¡£ËûÃǸ÷¸öÈ˶¼¾õµÃ×ԼºµÄÈ˸ñ¸ü¸ßÉУ¬×Լº¸ü˾¡±Äܵõ½·¨ÂÉÉϡ¢³¤ÉϵÄ×𾴣¬Òò¶øËûÃǾ͸ü¼Ó×ð¾´ÄÇЩ³¤Éϡ£¶ÔÓÚּÔÚɿ¶¯»òÄÖÅɱðµÄÀû¼ºÐÔÖʵIJ»ƽ֮Ãù£¬ËûÃǾ͸üÄܸù¾¿Æäԭί£¬¸üÄܿ´͸Æäµ×ϸ;Òò´ˣ¬·´¶ÔÕþ¸®Õþ²ߵķÅí§µĻ򲻱ØҪµÄÂ۵÷£¬¾ÍÓú¼Ӳ»ÄÜÆۻóËûÃÇÁˡ£ÔÚ×ÔÓɹú¼ÒÖУ¬Õþ¸®µİ²ȫ£¬´ó´óÒÀ´æÓÚÈËÃñ¶ÔÕþ¸®Ðж¯Ëù³ֵÄÓѺÃÒâ¼û£¬ÈËÃñÇãÏòÓڲ»ÇáÂʵء¢²»ÈÎÐԵØÅжÏÕþ¸®µÄÐж¯£¬¶ÔÕþ¸®ȷÊÇһ¼þ·dz£ÖØҪµÄÊ¡£ -µÚÈýÏî Â۸÷ÖÖÄêÁäÈËÃñµĽÌÓý¾­·Ñ +µÚÈýÏî Â۸÷ÖÖÄêÁäÈËÃñµĽÌÓý¾­·Ñ ¡¡¡¡¶Ը÷ÖÖÄêÁäÈËÃñµĽÌÓýÉèʩ£¬Ö÷ҪÊÇ×ڽ̽ÌÓýµÄÉèʩ¡£ÕâһÖֽÌÓý£¬ÆäĿµÄÓëÆä˵ÊÇʹÈËÃñ³ÉΪ½ñÊÀµÄÓÅÁ¼¹«Ã񣬵¹²»Èç˵ÊÇΪÈËÃñ×÷À´ÊÀÉú»¸üºÃÊÀ½çÉú»îµÄ׼±¸¡£½²ÊÚÕâÖֽÌÒåµĽÌʦµÄÉú»î·ѣ¬ҲͬÆäËûÆÕͨ½ÌʦһÑù£¬ÓеÄר¿¿Ìý½²ÕߵÄ×ÔÓɹ±Ïף¬ÓеÄÔòÀ´×Ծ­¹ú¼ҷ¨ÂÉÈϿɵÄijЩ²ÆԴ£¬Èçµزú¡¢ʲһ˰¡¢ÍÁµØ˰¡¢нˮµȡ£ËûÃǵÄŬÁ¦£¬ËûÃǵÄÈÈÐĺÍÇÚÃ㣬ÔÚǰһ³¡ºϣ¬Ëƺõ±Ⱥóһ³¡ºÏҪ´óµöࡣ¾ÍÕâһµã˵£¬Ð½̵ĽÌʦÃǣ¬Ҫ¹¥»÷³ÉÁ¢ÓƾõĹžÉÌåϵ£¬ÍùÍùռÓв»ÉٵıãÒˣ»ÒòΪ£¬¾ɽÌÄÁʦ£¬ÀµÓÐʥٺ£¬ÍùÍù²»´óעÒâά³ִó¶àÊýÈËÃñµÄÐÅÑöº͹éÒÀµÄÈÈÇ飻ËûÃÇÀÁ¶è¹ßÁˣ¬ÉõÖÁ²»Äܷܷ¢ÆðÀ´£¬±£»¤ËûÃÇ×ÔÉíµĽ̻ᡣ¸»ÓоèÔù²ƲúµijÉÁ¢ÓƾõĹú½̣¬ËüµÄÄÁʦÃǣ¬³£³£³ÉΪ²©ѧ¼°ÎÄÑŵÄÈˣ¬¾ßÓÐÉðʿ»ò×ãʹËûÃDz©µÃÉðʿËùÊܵÄ×𾴵ÄƷÖʡ£µ«Áíһ·½Ã棬ËûÃÇÒ×ÓÚɥʧÄÇЩʹËûÃǶÔϼ¶ÈËÃñÓÐȨÍþº͸л¯Á¦µĺõĺͻµµÄƷÖʣ¬¶øÕâЩƷÖʣ¬ҲÐí¾ÍÊÇʹ³ØÃǵÄ×ڽ̵óɹ¦Ϊ¹ú½̵ı¾À´ԭÒò¡£ÕâЩÄÁʦ£¬µ±Óö×ÅһȺÓ¸ҵĿËæÚÖÚÍûµ«ҲÐíÊÇÓ޶øÎÞ֪µĿñÐÅÕߵĹ¥»÷ʱ£¬¾ÍÏóÑÇÖÞÄϲ¿ÀÁ¶èµġ¢ÈáÈõµġ¢±¥ʳµĹúÃñÅö×ÅÁ˻îÆá¢¼áÈ̶ø¿༢µı±·½÷²÷°È˵ÄÇÖÂÔһÑù£¬ȫȻÎÞÒÔ×ÔÎÀ¡£ÔÚÕâÖֽô¼±³¡ºϣ¬ÕâЩÄÁʦͨ³£Ëù²ÉȡµÄΨһÊֶΣ¬¾ÍÊÇÉêËßÓÚÐÐÕþ³¤¹٣¬³Ʒ´¶ÔËûÃǵÄнÌͽÈÅÂҹ«°²£¬¶ø¼ÓÒÔÆȺ¦¡¢ÆËÃð»òÇýÖð¡£ÂÞÂíÌìÖ÷½̽ÌʿÆȺ¦Ð½Ìͽ£¬¾ÍÊÇÕâÑù¼ÙÊÖÐÐÕþ³¤¹٣»Ӣ¸ñÀ¼½̻áÆȺ¦·ǹú½ÌÅɣ¬ҲÊÇÕâÑù¼ÙÊÖÐÐÕþ³¤¹١£Æäʵ£¬һ¸ö¼Ⱦ­±»ÈÏΪ¹ú½̶ø°²°²¾²¾²µضɹýÁËһÁ½ÊÀ¼͵Ä×ڽ̣¬ͨÓÐijÖÖÐÂ×ڽ̶ÔÆä½ÌÒå½ÌÂɼÓÒԹ¥»÷¶ø×ԼºÎ޷¨×÷ÓÐÁ¦µĵֿ¹ʱ£¬һ°㶼ÊÇÇëÕþ¸®³öÃæ×èֹ¡£ÔÚÕâЩ³¡ºϣ¬¾ÍѧÎÊÎÄÕÂ˵£¬ҲÐíÓÐʱ¹ú½ÌÅɷ½ÃæռÓÅÊƣ¬µ«ÐÂÆðµķ´¶ÔÅɣ¬×ÜÊǸü³¤ÓÚÊÕÂòÈËÐ쬏ü³¤ÓÚÀ­£ÐÂÐÅͽµÄһÇм¼Êõ¡£ÔÚӢ¹ú£¬ÕâЩ¼¼Êõ£¬Ô类ÄÇЩӵÓо޶î¾èÔù²ƲúµĹú½̻̽áµÄÄÁʦÃÇÅ×ÔÚһ±ßÁˡ£ÏÖÔÚÅàÑøÕâЩ¼¼Êõµģ¬Ö÷ҪֻÓз´¶Թú½ÌÅɼ°ÃÀÒÔÃÀÅɽÌͽ¡£²»¹ý£¬ÔÚÐí¶àµط½£¬·´¶Թú½ÌÅɽÌʦ£¬Ôø¿¿×ÔÓɾèÔù¡¢ÐÅÍÐȨÀû¼°ÆäËûÌӱܷ¨ÂɵÄÐÐΪ£¬µõ½Á˶ÀÁ¢µÄÉú»î×ÊÁϣ¬ËûÃǵÄÈÈÇéºͻÁ¦£¬ËƺõÒÑÒò´˴ó´ó¼õÉÙÁˡ£ËûÃǺܶàÒѱä³ɷdz£ÓÐѧÎʡ¢·dz£»úÃô¼°·dz£¸ßÉеÄÈËÎËûÃÇһ°ãÒѾ­²»ÊǷdz£æÚÖÚÍûµĴ«µÀÕߡ£¾ͽñÈÕ˵£¬±ȷ´¶Թú½ÌÅÉÄÁʦ¸üµÃÈËÐĵģ¬ÄËÊÇÄÇЩѧÎÊԶ²»È練¶Թú½ÌÅÉÄÁʦÃǵÄÃÀÒÔÃÀÅɽÌͽ¡£ ¡¡¡¡ÔÚÂÞÂí½̻áÖУ¬Ï¼¶ÄÁʦ³öÓÚÓÐÁ¦µÄÀû¼º¶¯»ú£¬ËûÃǵÄÇÚÃãºÍÈÈÐ쬱ÈÈκγÉÁ¢ÓƾõÄҮöս̻̽áµÄÄÁʦ»îԾµöࡣÐí¶à½ÌÇøÄÁʦµÄÉú»î×ÊÁϣ¬ºܴ󲿷ÖÊǵð×ÈËÃñ×ÔԸµĹ±Ïף¬¶øÃØÃÜâã»ÚÓָøÓèËûÃÇÐí¶à»ú»ᣬÀ´Ôö¼ÓÕâÖÖÊÕÈëԴȪ¡£Íв§½ÌÍŵÄÉú»î×ÊÁϣ¬ȫ¶¼³ö×ÔÕâÖֹ±Ïס£ËûÃǺÜÏóÄÇЩÇáÆï¿첽µľü¶ӣ¬²»ÐÐÂӶᣬ¾ÍûÓиøÑø¡£½ÌÇøÄÁʦÓÐÀàËÆÄÇЩһ²¿·ÖÒÔнٺһ²¿·ÖÒÔѧÉúËù½»ÊøÐÞΪ±¨³êµĽÌʦ£¬¶øÕⱨ³êµĻñµã¬¾ͳ£Ðè¶àÉÙÒÀÀµÆäÇÚÃãºÍÃûÉù¡£Íв§½ÌÍţ¬ÓÐÀàËÆÄÇЩר¿¿ÇÚÃãÒԻ»µÃȫ²¿×ÊÁϵĽÌʦ£¬Òò´ˣ¬ËûÃDz»µò»Óþ¡Äܹ»´ٽøÆÕͨÃñÖÚð§ÒÀµÄÖÖÖּ¼Êõ¡£¾ÝÂí»ù¸¥Àû¶û¹۲죬ÔÚʮÈýÊÀ¼ͼ°ʮËÄÊÀ¼ͣ¬ʥ¶àÃ×Äá¿˼°ʥ·ðÀ¼Î÷˹¶þ´óÍв§½ÌÍŵÄÉèÁ¢£¬Ôø°ÑÈËÃñ¶ÔÌìÖ÷½̻̽áÈÕÒæ˥΢µÄÐÅÑöºÍð§ÒÀ¸´»îÁËÆðÀ´¡£ÔÚÂÞÂíÌìÖ÷½̸÷¹ú£¬Õâð§ÒÀ¾«Éñ£¬ȫÀµÐ޵Àɮ¼°ƶ¿àµĽÌÇøÄÁʦµÄ֧³֡£ÖÁÓÚÄÇЩ½̻á´óÈËÎ¾¡¹ÜËûÃǾßÓÐÉðÍÁ¼°ͨ´ïÊÀ¹ʵÄÈ˵ÄһÇÐÒÕÄܣ¬ÓÐʱÇҾßÓÐѧÕߵÄÒÕÄܣ¬²¢¶ÔÓÚά³Öϼ¶ÄÁʦµıØҪ¼ÍÂÉҲʮ·ÖעÒ⣬µ«¹ØÓÚÈËÃñµĽÌÓýȴûÓм¸¸ö¿ϷÑÉñȥ¸ɵġ£ ¡¡¡¡ÓÐһλÏִú×îÖøÃûµÄÕÜѧ¼ҼæÀúʷѧ¼Ò˵£º¡°һ¸ö¹ú¼ҵĴó¶àÊý¼¼Êõ¼°ְҵ£¬¶¼¾ßÓÐÕâÑùÐÔÖʣ¬ÔڴٽøÉç»áÀûÒæµÄͬʱ£¬²¢¶ÔijЩÈËÓÐÓûòÊʺÏÓÚijЩÈˡ£¹ú¼ÒÔÚÕⳡºϣ¬³ýÔÚһÖּ¼Êõ¸ոմ«ÈëµÄʱºò£¬Ëù¶¨Á¢µĹæÔò£¬ӦÌýÈθÃְҵ×ÔÓɣ¬°ѹÄÀø¸ÃְҵµÄÈÎÎ񣬽»¸ø´ÓËüÊջñºô¦µĸöÈˡ£¹¤ÒÕÖÆÔìÕß֪µÀÁËËûÃǵÄÀûÈóÀ´×Թ˿͵Ĺâ¹ˣ¬ËûÃÇÊǻᾡ¿ÉÄÜÔö¼ÓÆäÊìÁ·ÓëÇÚÀ͵ġ£ÊÂÎïÈçδÊÜÓꦵĸÉÉæËùÈÅÂң¬ÄÇÎÞÂۺÎʱ£¬ÉÌƷµĹ©¸ø¶¼»áÓëÆäÐèÇ󱣳ֲ¶àÏà³ƵıÈÀý¡£¡± @@ -1922,7 +1922,7 @@ ¡¡¡¡Ӧ¸Ãָ³ö£¬¸÷¹ú¹ú½̻̽áµÄÊÕÈ룬ÆäÖгýÌض¨ÍÁµػòׯ԰ÊÕÈëÍ⣬ËäȻҲÊǹú¼Òһ°ãÊÕÈëµÄһ²¿·֣¬µ«Õâһ²¿·ÖûÓÃÔڹú·ÀÉϣ¬¶øתÓõ½Óë¹ú·À·dz£ÏàÒìµÄĿµÄÉÏÁˡ£ÀýÈ磬Ïò½̻á½ÉÄɵÄʲһ˰£¬ÊÇһÖÖÕæÕýµÄÍÁµØ˰£»½̻áÈ粻°ÑËüÊÕȥ£¬ÍÁµØËùÓÐÕ߶Թú·ÀËùÄÜÌṩµĹ±Ïף¬ÊÇҪ´óµöàµġ£¹ú¼ҽô¼±֧³öµÄ×ÊԴ£¬ÓÐЩÈË˵ÊÇר¿¿ÍÁµصØ×⣬ÓÐЩÈË˵ÊÇÖ÷ҪÒÀ¿¿ÍÁµصØ×⡣½̻áÓÉÕâ×ÊԴȡȥµIJ¿·ÖÓú¶࣬¹ú¼ÒÄÜÓÉÕâ×ÊԴ·ֵõIJ¿·־ÍÓúÉ٣¬ÕâÊÇÃ÷Ã÷°װ׵ġ£Èç¹ûһÇÐÆäËûÇéÐζ¼һÑù£¬½̻áÓú¸»ÓУ¬¾ýÖ÷ºÍÈËÃñ¾ͱØȻÓúƶ·¦£¬¶ø¹ú¼ҷÀÓùÍâÎêµÄÄÜÁ¦Ҳ¾ÍÓúҪ±¡Èõ£¬ÕâºܿÉ˵ÊÇһ¸öһ¶¨²»±äµÄԭÔò¡£ÔÚÈô¸Éн̹ú¼ң¬ÌرðÊÇÔÚһÇÐÈðʿнÌÖÝÖУ¬ÍùʱÊôÓÚÂÞÂíÌìÖ÷½̻̽áµÄÊÕÈ룬¼´ʲһ˰ºͽ̻áËùÓеصÄÊÕÈëÕâÁ½Õߣ¬Òѱ»·¢ÏÖΪÕâô´óµÄ×ÊԴ£¬²»µ«×㹻Ìṩ¹ú½ÌÄÁʦÃÇÊʵ±µÄнٺ£¬¶øÇÒֻҪÂԼӲ¹³䣬Éõ»ò²»ÐèҪ²¹³䣬²¢×㹻¿ªÏú¹ú¼ÒÆäËûһÇзÑÓá£ÓÈÆäÊÇǿ´óµIJ®¶ûÄáÖÝÕþ¸®£¬Ëü°ÑÒÔǰ¹©¸ø×ڽ̵Ä×ʽð½ÚÖüÆðÀ´£¬ԼÓÐÊý°ÙÍò°÷µÄһ´ó½ð¶ÆäÖÐһ²¿·ִæÖü¹ú¿⣬Áíһ²¿·ÖͶ×ÊÓÚŷÖ޸÷ծÎñ¹úµĹ«ծÉúϢ£¬Ö÷ҪÊǷ¨À¼Î÷¼°´ó²»Áе߹ú¼ҹ«ծ¡£²®¶ûÄá»òÈðʿÆäËûнÌÖݸ÷½̻ᣬ·ѹú¼ҶàÉٷÑÓã¬ÎҲ»¸ÒðÒÔΪ֪¡£¸ù¾Ýһ·dz£ÕýȷµļÆË㣬1755ÄêËոñÀ¼½̻áÄÁʦÃǵÄȫÊÕÈ룬°üÀ¨½̻áËùÓеؼ°ËûÃÇסլµķ¿×⣬ºÏÀí¹À¼ÆÆðÀ´£¬²»¹ýÁùÍò°ËǧÎå°ÙʮËİ÷һÏÈÁîÎåÓÖʮ¶þ·Ö֮һ±ãʿ¡£ÕâÑù¼«ƽ³£µÄÊÕÈ룬ÿÄêҪ¹©¸ø¾ŰÙËÄʮËÄÃûÄÁʦµÄÏ൱Éú»îµÄ×ÊÁϣ¬ÔټÓÉϽÌÌü°ÄÁʦסլ²»ʱÐÞÞǻò½¨ÖþµÄ֧³ö£¬×ܻá¼ÆË㣬ÿÄêÒ಻»ᳬ¹ý°ËÍò°÷ÄËÖÁ°ËÍòÎåǧ°÷¡£ËոñÀ¼½̻á»ù½ð¹ýÓÚƶ·¦£¬ÄÇÊDz»´ýÑԵġ£¿ÉÊǣ¬¾Íά³ִó¶àÊýÈËÃñÐÅÑöµÄͳһ£¬ð§ÒÀµÄÈȳÀ£¬ÄËÖÁÖÈÐ򡢹æÔò¼°ÑÏËàµĵÀµ¾«Éñ˵£¬ûÓÐһ¸ö»ù¶½½̹úµÄ×ԣ½̻ᣬÄܹ»³¬¹ýËոñÀ¼µĽ̻ᡣ·²±»ÈÏΪ¹ú½̻̽áËùÄܲúÉúµÄһÇÐÁ¼ºýá¹û£®ÊôÓÚÉç»᷽ÃæµÄҲºã¬ÊôÓÚ×ڽ̷½ÃæµÄҲºã¬ÆäËû½̻áÄܲú³öµģ¬ËոñÀ¼½̻áҲͬÑùÄܲú³ö¡£¶ø±ÈËոñÀ¼½̻Ტ²»¼ûµøü¸»ԣµÄÈðʿн̻̽ᣬ»¹ÄÜÔڸü´ó³̶ÈÉϲú³öÕâЩ½á¹û¡£ÔÚÈðʿ´󲿷ֵÄнÌÖÝÖУ¬²¶àÕҲ»³öһ¸öÈˣ¬¹«ÑÔËû²»ÊÇн̻̽áµÄÐÅͽ¡£µÄȷ£¬ÈçÓÐÈËÔÎÑÔËûÊÇÆäËû½̻áµÄÐÅͽ£¬·¨ÂɾͻáǿÆÈËûÀ뿪Öݾ³¡£µ«Êǣ¬Ҫ²»ÊÇÄÁʦÃÇÇÚÃ㣬ԤÏÈÓյ¼ÈËÃñȫÌ塪¡ª»òÐíÓÐÉÙÊýÀýÍ⡪¡ª¸ÄÐŹú½̣¬ÏóÕâÑùÑϾþ»òÕßÄþ˵ÊÇѹÆȵķ¨Âɣ¬ÊǾöÄÑÔÚÕâÖÖ×ÔÓɹú¼ÒʵÐеġ£Òò´ˣ¬ÔÚÈðʿijµط½£¬ÒòΪн̹úÓëÂÞÂíÌìÖ÷½̹úżȻµĽáºϣ¬¸Ä×ÚÕ߲»ÏóÆäËûµط½ÄÇôÆձ飬ÕâÁ½ÖÖ×ڽ̣¬¾Ͳ»µ«ͬΪ·¨ÂÉËùĬÈϣ¬¶øÇÒͬ±»ÈÏΪ¹ú½̡£ ¡¡¡¡²»ÂۺÎÖÖְÎñ£¬ҪÆäִÐÐÁ¼ºã¬Æ䱨³ê»òнٺËÆÐ뾡¿ÉÄÜÓë¸ÃְÎñµÄÐÔÖÊÏà³ơ£È籨³ê¹ýÉ٣¬ÄǾͺÜÈÝÒ×ÓɷîְÕߴ󲿷ֵı°ÁÓÎÞÄܶøÊܵ½Ë𺦣»È籨³ê¹ý¶࣬ÄǾͺÜÈÝÒ×ÓÉËûÃǵÄÊèºöµ¡¶è¶øÊܵ½¸ü´óµÄË𺦡£һ¸öÓдó×ÚÊÕÈëµÄÈˣ¬ÎÞÂÛËûËùִºÎҵ£¬Ëû×ܻá¾õµã¬ËûӦµ±ÓëÆäËûÓдóÊÕÈëÕ߹ýͬһµÄÉú»²¢ÇÒÔڻ¶À֡¢ÐéÈټ°·ŵ´ÉÏÃæÉҷÑÆä´󲿷Öʱ¼䡣µ«Êǣ¬¶ÔÓÚһ¸öÄÁʦ£¬ÕâÑùµÄÉú»·¨ÊDz»Ðеģ¬ÕմËÏÂȥ£¬Ëû²»µ«»á°ÑËûӦ¸ÃÓÃÔÚְÎñÉϵÄʱ¼äÏû·ѵô£¬²¢ÇһáʹËûÈ˸ñÉϵÄׯÑϣ¬ÔÚÈËÃñÐÄĿÖÐÍêȫɨµأ¬¶øÈ˸ñµÄ×ðÑϣ¬ÕýÊÇʹËûÄÜÒÔÊʵ±µÄÊÆÁ¦ÓëȨÍþ£¬ִÐÐÆäְÎñµÄΨһƾ½衣 -¡¡¡¡µÚËĽڡ¡ÂÛά³־ýÖ÷×ðÑϵķÑÓà +¡¡¡¡µÚËĽڡ¡ÂÛά³־ýÖ÷×ðÑϵķÑÓà ¡¡¡¡һ¹ú¾ýÖ÷£¬³ýÁËִÐÐÖÖÖÖְÎñËù±ØҪµķÑÓÃÒÔÍ⣬Ϊά³ÖÆä×ðÑϼƣ¬ÒàÐëÓÐһ¶¨µķÑÓá£Õâ·ÑÓõĴóС£¬ËæÉç»ᷢ´ïʱÆڵIJ»ͬ¶ø²»ͬ£¬ËæÕþÌåÐÎ̬µIJ»ͬ¶ø²»ͬ¡£ ¡¡¡¡Ôڸ»ԣ¶ø·¢´ïµÄÉç»áÖУ¬¸÷½׼¶ÈËÃñµķ¿Îݡ¢¼Ҿߡ¢ʳƷ¡¢·þװÒԼ°ÓιÛÍæºÃ֮¾ߣ¬¶¼ÓÉÆÓÖʶøÁ÷ÓÚÉݻª£¬ÔڴËÖÖÇé¿öÏÂҪ¾ýÖ÷¶ÀÄæʱÉУ¬¾öÄÑ×öµ½¡£ËûµÄһÇзþÓÃÎïƷ£¬Ëù·ѱØÈÕÒæ¼ӶࡣÒòΪ²»ÊÇÕâÑù£¬¾Ͳ»ÄÜά³ÖËûµÄ×ðÑϡ£ ¡¡¡¡¾Í×ðÑÏһµã˵£¬һ¹ú¾ýÖ÷¾ýÁÙÓÚÆ䳼Êü£¬±È֮¹²º͹úԪÊ׶ԸÉÆäͬ°ûÊÐÃ񣬸üҪ¸߲»¿ÉÅʣ¬Íû³¾Ī¼°£»ËùÒÔΪҪά³ÖÕâ½ϸߵÄ×ðÑϣ¬ÊƱØҪ½ϴóµķÑÓá£×ܶ½»òÊ㤵ĹÙÇñ£¬×Բ»ÄÜÓë¹úÍõ¹¬͢±ÈÆ仪Àö¡£ @@ -1936,9 +1936,9 @@ -µڶþÕ¡¡ÂÛһ°ãÊÕÈë»򹫹²ÊÕÈëµÄԴȪ +µڶþÕ¡¡ÂÛһ°ãÊÕÈë»򹫹²ÊÕÈëµÄԴȪ ¡¡¡¡һ¹úÿÄê֧³öµķÑÓ㬲»µ«Óйú·À·ѣ¬¾ýÖ÷Ñø×ð·ѣ¬¶øÇÒÓйú¼ÒÏܷ¨δ¹涨ÓɺεÈÌض¨ÊÕÈëÀ´¿ª֧µÄÆäËû±ØҪÕþ·ѡ£ÕâЩ·ÑÓõĿª֧£¬ÓÐÁ½¸öÀ´Դ£ºµÚһ£¬ÌرðÊôÓھýÖ÷»ò¹ú¼ң¬¶øÓëÈËÃñÊÕÈëÎ޺εȹØϵµÄ×ÊԴ£»µڶþ£¬ÈËÃñµÄÊÕÈ롣 -µÚһ½ڡ¡ÌرðÊôÓھýÖ÷»ò¹ú¼ҵÄÊÕÈëԴȪ +µÚһ½ڡ¡ÌرðÊôÓھýÖ÷»ò¹ú¼ҵÄÊÕÈëԴȪ ¡¡¡¡ÌرðÊô¸ɾýÖ÷»ò¹ú¼ҵÄ×ÊԴ»òÊÕÈëԴȪ£¬ÓÉ×ʲƼ°ÍÁµع¹³ɡ£ ¡¡¡¡¾ýÖ÷ÓÉÆä×ʲÆȡµÃÊÕÈëµķ½ʽ£¬ÓëÆäËû×ʲÆËùÓÐÕßͬ£¬¼ÆÓÐÁ½Ö֣¬һÊÇÇ××ÔʹÓÃÕâ±Ê×ʲƣ¬һÊǰÑËü´ûÓëËûÈˡ£ËûµÄÊÕÈëÔÚǰÕßΪÀûÈó£¬ÔںóÕßΪÀûϢ¡£ ¡¡¡¡÷²÷°»ò°¢À­²®Çõ³¤µÄÊÕÈëȫΪÀûÈó£¬ËûÃÇ×ÔÉíÊDZ¾¼¯ÍŻ򱾲¿×åÖеÄÖ÷ҪÄÁÐóÕߣ¬ËûÃÇ×Լº¼ලËÇÑøÉüÐó£¬ÓÉÐóȺµÄÈé֭¼°Ôöֳ»ñȡÊÕÈ롣²»¹ý£¬ÒÔÀûÈóΪÍõ¹úÊÕÈëµÄÖ÷Ҫ²¿·֣¬ֻÊÇ×î³õÆڡ¢×îÓ×ÖÉÕþÖÎ״̬ϵÄÊÂÇ顣 @@ -1960,7 +1960,7 @@ ¡¡¡¡ÎÄÃ÷¹ú¾ýÖ÷£¬ÓÉÆäÁìµػñȡµÄÊÕÈ룬¿´À´ËƶÔÈËÃñ¸öÈËÎÞË𣬵«Æäʵ£¬ÕâËùËðÓÚȫÉç»áµģ¬±ȾýÖ÷ËùÏíÓеÄÆäËûÈκÎͬµÈÊÕÈëÀ´µöࡣËùÒԣ¬ΪÉç»áȫÌåÀûÒæ¼ƣ¬ĪÈôÅÄÂôÍõÊÒÁìµأ¬´Ӷø·ÖÅ䏸ÈËÃ񣬶ø¾ýÖ÷һÏòÓÉÆäÁìµØÏíÓеÄÊÕÈ룬ÔòÓÉÈËÃñÌṩÆäËûͬµÈÊÕÈëÀ´´úÌ档 ¡¡¡¡ÍÁµØÓÃ×÷¹«԰¡¢ÁÖàó¼°ɢ²½³¡Ëù£¬ÆäĿµÄÔڹ©ÓÎÀÖÓë¹ÛÉͣ¬²»½ö·ÇÊÕÈëԴȪ£¬¶øÇÒÐëʱ³£³ö·ÑÝÝÖΡ£Îҿ´£¬ÔڴóµÄÎÄÃ÷¾ýÖ÷¹ú£¬ֻÓÐÕâÖÖÍÁµؿÉÊôÓھýÖ÷¡£ ¡¡¡¡Òò´ˣ¬¹«¹²×ʱ¾ºÍÍÁµأ¬¼´¾ýÖ÷»ò¹ú¼ÒËùÌØÓеĶþÏî´óÊÕÈëȪԴ£¬¼Ȳ»ÒËÓÃÒÔ֧¸¶Ҳ²»¹»֧¸¶һ¸ö´óµÄÎÄÃ÷¹ú¼ҵıØҪ·ÑÓã¬ÄÇĩ£¬Õâ±ØҪ·ÑÓõĴ󲿷֣¬¾ͱØÐëȡ¸øÓÚÕâÖֻòÄÇÖÖ˰Êգ¬»»ÑÔ֮£¬ÈËÃñÐëÄóö×Լºһ²¿·Ö˽µÄÊÕÈ룬¸ø¾ýÖ÷»ò¹ú¼ң¬×÷Ϊһ±ʹ«¹²ÊÕÈ롣 -µڶþ½ڡ¡Â۸³˰ +µڶþ½ڡ¡Â۸³˰ ¡¡¡¡±¾ÊéµÚһƪ˵¹ý£¬¸öÈ˵Ä˽ÊÕÈ룬×îÖÕ×ÜÊdzöÓÚÈý¸ö²»ͬµÄԴȪ£¬¼´µØ×⡢ÀûÈóÓ빤×ʡ£ÿÖָ³˰£¬¹é¸ù½áµף¬±ض¨ÊÇÓÉÕâÈýÖÖÊÕÈëԴȪµÄÕâһÖֻòÄÇһÖֻòÎÞÇø±ðµØÓÉÕâÈýÖÖÊÕÈëԴȪ¹²֧ͬ¸¶µġ£Òò´ˣ¬Îҽ«½߾¡ËùÄܣ¬ÂÛÊöÒÔϸ÷µ㣺µÚһ£¬´òËã¼ÓÓڵØ×âµÄ˰£»µڶþ£¬´òËã¼ÓÓÚÀûÈóµÄ˰£»µÚÈý£¬´òËã¼ÓÓڹ¤×ʵÄ˰£»µÚË쬴òË㲻·ֱ˴˵ؼÓÓÚÕâÈýÏîÊÕÈëԴȪµÄ˰¡£ÓÉÓڷֱ𿼾¿´ËËÄÖָ³˰£¬±¾Õµڶþ½ÚҪ·ÖΪËÄÏÆäÖÐÓÐÈýÏµÃϸ·ÖΪÈô¸ÉСĿ¡£ÎÒÃÇÔںóÃæ¿ÉÒԿ´µ½£¬Ðí¶àÕâЩ¸³˰£¬¿ªʼËäÊǴòËã¼ÓÓÚijÏî»ù½ð»òÊÕÈëԴȪ£¬µ«½á¹ûȴ²»ÊÇÓÉÄÇÏî»ù½ð»òÊÕÈëԴȪÖÐ֧¸¶£¬ËùÒԷÇÏêϸÌÖÂ۲»¿ɡ£ ¡¡¡¡ÔÚÌÖÂ۸÷ÌØÊ⸳˰֮ǰ£¬ÐëÁоٹØÓÚһ¹ɸ³˰µÄËÄÖÖԭÔò£¬×÷ΪǰÌᡣÕâËÄÖÖԭÔòÈçÏ¡£ ¡¡¡¡һ¡¢һ¹ú¹úÃ񣬶¼ÐëÔڿÉÄܷ¶ΧÄڣ¬°´Õո÷×ÔÄÜÁ¦µıÈÀý£¬¼´°´Õո÷×ÔÔڹú¼ұ£»¤ÏÂÏíµõÄÊÕÈëµıÈÀý£¬½ÉÄɹú¸³£¬ά³ÖÕþ¸®¡£һ¸ö´ó¹úµĸ÷¸öÈËÐë½ÉÄÉÕþ¸®·ÑÓã¬ÕýÈçһ¸ö´óµزúµĹ«¹²×âµØÕßÐ밴Õո÷×ÔÔڸõزúÉÏËùÊÜÀûÒæµıÈÀý£¬ÌṩËüµĹÜÀí·ÑÓÃһÑù¡£Ëùν¸³˰µÄƽµȻò²»ƽµȣ¬¾Ϳ´¶ԸÉÕâÖÖԭÔòÊÇ×ðÖػ¹ÊǺöÊӡ£±ØÐëעÒ⣬Èκθ³˰£¬Èç¹û½á¹û½öÓɵØ×⡢ÀûÈ󡢹¤×ÊÈýÕß֮һ¸ºµ££¬ÆäËû¶þÕ߲»ÊÜӰÏ죬ÄDZØȻÊDz»ƽµȵġ£¹ØÓÚÕâÖֲ»ƽµȣ¬ÎҾÍÕâÑùÌáһ´Σ¬²»Äâ¶ི£¬ÒԺó£¬ÎÒֻÌÖÂÛÓÉÓÚijÌØÖָ³˰²»ƽµȵØÂäÔÚËüËùӰÏìµÄÌض¨˽ÈËÊÕÈëÉ϶øÒýÆðµÄÄÇÖֲ»ƽµȡ£ @@ -2210,7 +2210,7 @@ -µÚÈýÕ¡¡Â۹«ծ +µÚÈýÕ¡¡Â۹«ծ ¡¡¡¡ÔÚÉÌҵ먦չ¡¢ÖÆÔìҵδ¸ĽøµÄ먦»¯Éç»ᣬ¶ÔÓڽöÄÜÓÉÉÌҵ¼°ÖÆÔìҵ´øÀ´µĸ߼ÛÉݳÞƷ»¹һÎÞËù֪µÄʱºò£¬ÓдóÊÕÈëµÄÈˣ¬ÏóÎÒÔڵÚÈýƪ˵¹ýµÄÄÇÑù£¬³ýÁ˾¡ÊÕÈëÄÜά³ֶàÉÙÈˣ¬ʹÓÃÒÔά³ֶàÉÙÈËÍ⣬ÔÙҲ²»ÄÜÓÐÆäËûÏû·ѻòÏíÊÜÊÕÈëµķ½·¨¡£һ¸ö´óÊÕÈ룬Ëæʱ¶¼¿É˵ÊǶÔһ´óÁ¿Éú»î±ØÐèƷµÄ֧ÅäÁ¦¡£ÔÚÄÇÖÖ먦»¯Éç»á״̬Ï£¬ÄÇÊÕÈëһ°㶼ÊÇÒÔһ´óÁ¿±ØÐèƷ£¬¼´´ÖÒ´ÖʳµÄԭÁϣ¬Èç¹ÈÎÉüÐó¡¢Ñòë¼°ÉúƤµÈÎïÊսøµġ£µ±ʱ¼ÈÎÞÉÌҵ£¬ÓÖÎÞÖÆÔìҵ£¬ËùÒÔÕâЩÎï×ʵÄËùÓÐÕߣ¬ÕҲ»µ½Èκζ«Î÷£¬¿ÉÒԽ»»»ÆäÏû·Ѳ»Á˵Ĵ󲿷ÖÎï×ʣ»³ýÁ˾¡ÆäËùÓУ¬ÓÃÒԹ©È˳Դ©Í⣬Ëû¼òֱÎ޷¨´¦ÖÃÆäʣÓࡣÔڴËÇé¿öÏ£¬¸»Õ߼°ÓÐȨÊÆÕߵÄÖ÷Ҫ·ÑÓ㬾ÍÊDz»ÉݻªµĿî¿ͺͲ»ìÅҫµĻÝʩ£¬¶øÕâÖֿî¿ͺͻÝʩ£¬ÎÒÔڱ¾ÊéµÚÈýƪҲÔø˵¹ý£¬ÊDz»ÈÝÒ×ʹÈËÏÝÓÚÆƲúµġ£ÖÁÓÚÀû¼ºµÄÏíÀ־Ͳ»ͬÁˣ¬ËäÖÁ΢ĩ£¬׷ÇóµĽá¹û£¬ÖÇÕßÓÐʱÒ಻ÃâÓÚÃðÍö¡£ÀýÈ綷¼¦µĿñÈȣ¬Ôø¾­ʹÐí¶àÈËÆÆÁ˲ú¡£ÎÒÏàÐţ¬ÓÉÉÏÊöÐÔÖʵĿî´ý»ò»Ýʩ¶ø°ܼҵÄÈˣ¬µ±²»ºܶ࣬µ«ÓÉÆÌÕŵĿî¿ͺÍìÅҫµĻÝʩ¶ø°ܼҵÄÔòΪÊý¼«¶ࡣÔÚÎÒÃǷ⽨µÄ׿ÏÈ֮¼䣬ͬһ¼Ò×峤¾üÌÐø±£ÓÐͬһµزúµÄÊÂʵ£¬¿ɳä·ֱíʾËûÃÇÉú»îÉÏÁ¿ÈëΪ³öµÄһ°ãÐÔÏ򡣴óÍÁµØËùÓÐÕ߲»¶ÏÐÐ×ÅÏçÏÂʽµĿî´ý£¬¿´À´ËäÓëÁ¼ºõÄÀí²ÆԭÔ򲻿ɷÖÀëµÄÉú»îÖÈÐòÓÐËù±³À룬µ«ÎÒÃǵóÐÈÏËûÃÇÖÁÉÙҲ֪µÀ²«½ڣ¬û°Ñȫ²¿ÊÕÈ뾡ÐÐÏû·ѵô¡£ËûÃǴó¸ÅÓлú»áÂôµôÆäһ²¿·ÖÑòë»òÉúƤȡµûõ±ҡ£Õâ»õ±ҵÄһ²¿·֣¬ËûÃÇҲÐíÊÇÓÃÒԹºÂòµ±ǰ»·¾³ËùÄÜÌṩµÄijÖÖÐéÈÙƷ¼°ÉݳÞƷÀ´Ïû·ѣ¬µ«»¹ÓÐһ²¿·֣¬Ôò³£ÊÇÕÕԭÑùÐî²ØÆðÀ´¡£ʵ¼ÊÉϣ¬ËûÃdzýÁ˰ѽÚԼµIJ¿·ÖÐî²Ø×ţ¬Ҳ¾Ͳ»ºÃÔÙÔõô´¦Ö᣾­Ḛ́ɣ¬ÄǶÔÓÚһ¸öÉðʿÊDz»ÃûÓþµģ»·Åծ°ɣ¬µ±ʱÔçÊÓΪ·ÇÒ壬¶øÇÒΪ·¨ÂÉËù²»Ðí£¬ÄÇÊǸü²»ÃûÓþµġ£¼Ó֮£¬ÔÚÄÇÖÖǿ±©»ìÂҵÄʱ´ú£¬˵²»¶¨ÓÐһÌì»ᱻ¸ϳö×ԼºµÄסլ£¬ËùÒԣ¬ÔÚÊֱ߲ØÐîһµã»õ±ң¬ÒԱãÄÇʱºòЯ´øһЩ¹«ÈÏΪÓмÛֵµĶ«Î÷£¬ÌÓÍù°²ȫµشø£¬ÊǵüƵġ£ʹ¸öÈËÒԲØÐî»õ±ÒΪµüƵÄǿ±©£¬¸üʹ¸öÈËÒÔÒþÄäÆä²ØÐîµĻõ±ÒΪµüơ£¶¯²»¶¯¾ÍÓÐÂñ²ØÎ﷢Ï֣¬ÎÞÖ÷²Ʊ¦·¢Ï֣¬Äǿɳä·Ö֤Ã÷£¬µ±ʱ²ØÐî»õ±Ҽ°ÒþÄ䲨Ðî֮Ê£¬ÊǷdz£Á÷Ðеġ£ÓÐһ¸öʱºò£¬Âñ²ØÎï¼òֱ³ÉÁ˾ýÖ÷µÄһ¸öÖØҪÊÕÈ벿·֡£ȻÔڽñÈգ¬ÄÄÅÂȫÍõ¹úµÄһÇÐÂñ²ØÎÒà¿ֲ»¹»³ÉΪһ¸ö¶à²ÆÉðʿµÄÖ÷ҪÊÕÈ벿ÃÅÁˡ£ ¡¡¡¡½ÚԼÓë²ØÐîµÄÇãÏò£¬Á÷ÐÐÓÚÈËÃñ֮¼䣬ҲͬÑùÁ÷ÐÐÓھýÖ÷֮¼䡣ÎÒÔڱ¾ÊéµÚËÄƪ˵¹ý£¬ÔÚûÓÐʲôÉÌҵ¼°ÖÆÔìҵ¿ÉÑԵĹú¼ң¬¾ýÖ÷Ëù´¦¾³µأ¬×ÔȻ»áʹËû·îÐÐÐî»ýËù±ØҪµĽÚԼ¡£ÔÚÄÇÖ־³µأ¬¾ÍÊǾýÖ÷µķÑÓã¬Ò಻ÄÜÓÉËûµÄÐéÈÙÐÄ֧Å䣻Ëûϲ»¶ÓÐһ¸ö»ªÀöװÊεŬ͢£¬µ«ÄǸöÎÞ֪µÄʱ´ú£¬ȴֻÄܸøËûÌṩһµãÎÞÉõ¼ÛֵµÄСÍæÒâ¶ù¡£¶øÕâ¾͹¹³ÉËû¹¬͢µÄȫ²¿װÊΡ£µ±ʱÊÇÎ޳£±¸¾üµıØҪµģ¬ËùÒԣ¬ÏóÆäËû´óÁìÖ÷µķÑÓÃһÑù£¬¾ÍÁ¬¾ýÖ÷µķÑÓ㬳ýÁËÓÃÒԽ±ÀøÆäµ軧£¬¿î´ýÆä¼ҳ¼Í⣬¼¸ºõûÓÐÓô¦¡£µ«Êǽ±Àø¼°¿î´ý£¬ºÜÉٻáÁ÷ÓÚÎ޽ÚÖƣ¬¶øÐéÈÙÔ򼸺õ¶¼»áÁ÷ÓÚÎ޽ÚÖƣ¬Òò´ˣ¬ŷÖÞһÇйŴú¾ýÖ÷£¬Î޲»ÉÆÓвƱ¦¡£¼´ÔڽñÈգ¬Ìý˵ÿ¸ö÷²÷°Çõ³¤£¬»¹ÊǻýÓвƱ¦¡£ ¡¡¡¡Ôڸ»Óи÷Öָ߼ÛÉݳÞƷµÄÉÌҵ¹úÄڣ¬¾ýÖ÷×ÔȻ»á°ÑËûµÄÊÕÈë´󲿷֣¬ÓÃÒԹºÂòÕâЩÉݳÞƷ£¬ÏóÆä°æͼÄÚһÇдóÍÁµØËùÓÐÕßһÑù¡£Ëû±¾¹ú¼°Áڽü¸÷¹ú£¬¹©¸øËûÐíÐí¶à¶àµĸ÷Öָ߼ÛװÊÎÎÕâЩװÊÎÎÐγÉÁ˹¬͢»ªÀöµ«ÎÞÒâÒåµÄ׳¹ۡ£¾ýÖ÷ÊôϵĹó×åÃǣ¬ΪÁË׷Çó´ÎһµȵÄͬÖÖ׳¹ۣ¬һ·½Ãæ´ò·¢Æä¼ҳ¼£¬һ·½ÃæÈÃ×âµØÈ˶ÀÁ¢£¬ÕâһÀ´£¬ËûÃǾͽ¥´ÎʧµôÁËȨÍþ£¬ÒÔÖÂÓë¾ýÖ÷ÁìÍÁÄÚÆäËû´󲿷ָ»ԣÊÐÃñ£¬ûÓÐÇø±ðÁˡ£×óÓÒËûÃÇÐÐΪµĸ¡±¡ÈÈÍû£¬Ҳ×óÓÒËûÃǾýÖ÷µÄÐÐΪ¡£ÔÚËûÁìÍÁÄڣ¬¸ö¸ö¸»ÓÐÕ߶¼ÔÚÕ÷ÖðÕâÖÖÏíÀ֣¬ÔõÄܽÐËûһ¸öÈ˸»¶ø²»ÒùÄأ¿¼ÙʹËûû°ÑÔõô´óµIJ¿·ֵÄÊÕÈëÓÃÓÚÏíÀ֣¨Ëû¶à°ëÊÇÈç´ˣ©£¬ÒÔÖ¼õÈõ¹ú·ÀÁ¦Á¿£¬ÄÇô£¬³¬¹ýά³ֹú·ÀÐèҪÄÇһ²¿·ֵÄÊÕÈ룬ÊDz»ÄÜÆÚÍûËû²»Ïû·ѵġ£Ëûƽ³£µķÑÓ㬾͵ÈÓÚËûƽ³£µÄÊÕÈ룻·ÑÓò»³¬¹ýÊÕÈ룬¾ÍËãÍòÐÒÁˡ£²Ʊ¦µÄÐî»ý£¬ÔÙÎÞϣÍû£»һµ©ÓÐÌرð¼±Ð裬ÐèҪÌرð·ÑÓã¬Ëû¶¨ȻҪÏòÈËÃñҪÇóÌرðµÄԮÖú¡£1610Ä귨À¼Î÷¹úÍõºàÀûËÄÊÀËÀºó£¬ŷÖ޴ó¾ýÖ÷ÖÐÐîÓкܶà²Ʊ¦µģ¬¾ÝÍƲâֻÓÐÆÕ³ʿÏֹúÍõ¼°ǰ¹úÍõ¡£¾ýÖ÷Õþ¸®²»˵£¬¹²ºÍÕþ¸®£¬ΪÐî»ý¶øÐнÚԼµÄÊÂÒ༸ºõÊÇͬÑùº±¼ûµġ£Òâ´óÀû¸÷¹²º͹ú¡¢ÄáµÃÀ¼¹²º͹ú¶¼¸ºÓÐծÎ񡣲®¶ûÄáÁª°î»ýÓв»ÉٵIJƱ¦£¬µ«ÔÚŷÖÞÊǽö¼ûµġ£Èðʿ¹²º͹úÆäËûÁª°ȫÎÞÐî»ý¿ÉÑԡ£³çÉÐijÖÖÃÀ¹ۣ¬ÖÁÉ٣¬³çÉÐÌûʵĽ¨ÖþÎPÆäËû¹«¹²װÊÎÎ×î´ó¹úÍõµķŵ´µĹ¬͢£¬×Բ»±Ø˵£¬¾ÍÁ¬ÄÇЩС¹²º͹ú¿´ËÆÖÊÆӵÄÒé»áÒéÊÂÌÃҲÍùÍùÈç´ˡ£ diff --git a/docs/chapter-detection-plan.md b/docs/chapter-detection-plan.md new file mode 100644 index 0000000..a5deebf --- /dev/null +++ b/docs/chapter-detection-plan.md @@ -0,0 +1,112 @@ +# TXT 章节识别与标题提取 — 实施计划 + +> 分支:`feat/txt-chapter-detection` +> 目标:对用户导入的任意格式 txt,自动识别章节边界并提取标题。 +> 架构:三层规则流水线为基座,mDeBERTa-v3-base(浏览器端 ONNX 推理)作为候选生成的增强层。 +> 制定日期:2026-07-16 + +## 总体架构 + +``` +txt 文本 + │ + ├─ 1. 候选生成(每行打分) + │ ├─ 规则模式库(零成本,始终启用) + │ └─ mDeBERTa 行分类器(可选增强,模型已缓存时启用) + │ + ├─ 2. 全局验证(语言无关,始终启用) + │ ├─ 模式家族分组 + 编号递增序列检查 + │ ├─ 章节间距均匀性检查 + │ └─ 总数 sanity check(过少/过多 → 降级下一家族) + │ + └─ 3. 兜底(无任何命中) + └─ 空行分块 / 固定字数切分(保留现有整本一章逻辑) +``` + +关键原则:**模型只替换/增强第 1 层**。第 2 层全局验证是精度的真正来源且语言无关, +无论模型是否启用都必须经过。 + +## Phase 1 — 规则层(可独立上线) + +新增 `lib/chapter/` 模块: + +- `patterns.ts` — 多语言标题模式库: + - 中文:`第[一二两三四五六七八九十百千零〇0-9]+[章节卷回部集话篇幕]`(行首锚定 + `m`)、 + 特殊章节词(序章/楔子/引子/前言/后记/尾声/番外/终章)、编号式(`一、` `1.` `01 ` `【】`) + - 英文:`Chapter/CHAPTER/Section/Part + 数字`、罗马数字独行 + - 日文:`第X話/章`;其他语言按需补充(参考 Legado 社区规则库、calibre structure detection) +- `candidates.ts` — 按行切分,行长过滤(≤ 50 字符)+ 模式匹配,输出候选行及其特征 + (行长、模式家族、编号值、前后空行、文中偏移) +- `validate.ts` — 全局验证:家族分组 → 编号单调性评分 → 间距均匀性 → 选最优家族,剔除离群点 +- `index.ts` — 入口 `detectChapters(text: string): ChapterItem[]`,串联三层 + +改造现有代码: + +- 修复 `lib/transformText.ts` 中 `extractChapters` 的正则空格 bug 与行首锚定缺失(或直接废弃,指向新模块) +- `transformTextToExpectedFormat`:无 `` 标签时调用 `detectChapters` 而非整本一章 + +测试: + +- 引入 vitest(当前项目无测试框架) +- fixtures:中文网络小说、英文 Gutenberg、无格式纯文、伪标题干扰样本(正文含「第二天」「看到第三章」) + +**验收**:对 fixtures 集合章节边界准确率 ≥ 95%,无网络依赖,可直接合入主干上线。 + +## Phase 2 — 浏览器推理基础设施(模型无关,可先用占位模型打通) + +- 依赖:`onnxruntime-web`(或 `@huggingface/transformers`,二选一,选前者更可控体积) +- 新增 `workers/nlpWorker.ts`: + - 模型下载(带进度回调)→ OPFS 缓存(Cache API 兜底),版本化文件名支持热更新 + - Execution provider:WebGPU 优先,WASM SIMD + threads 兜底 + - 批量推理 API:`classifyLines(lines: string[]): Promise`(返回标题概率) +- 加载策略:**懒加载**。规则层置信度高时完全不下载模型;置信度低(无主模式家族/序列断裂多) + 或用户手动触发「增强解析」时才拉取 +- 移动端:UA/内存探测,iOS 上默认只用规则层或提供裁剪版模型(见 Phase 3) + +**验收**:占位模型(任意 HF 上现成的 deberta-v2 ONNX)在 worker 内完成加载→缓存→批量推理→ +离线二次加载全链路,桌面 Chrome/Safari + iOS Safari 真机通过。 + +## Phase 3 — 训练管线(仓库外 Python,产物回流) + +独立目录 `ml/`(不进 npm 构建): + +- `data/`:epub 语料 → txt + 行级标签自动生成(epub 目录即真值);规则层上线后收集的 + bad case 人工标注集(目标数百条疑难样本) +- `train/`:mDeBERTa-v3-base 微调,任务为行级二分类,输入 = 目标行 + 前后各 1–2 行上下文窗口 +- `eval/`:多语言 held-out 集,重点考察零样本迁移语言(日/法/德/俄) +- `export/`:optimum 导出 ONNX → int8 动态量化 → 两个产物: + - `full`(全量 250k 词表,~280MB,桌面端,100 语言覆盖) + - `pruned`(按 CJK + 拉丁 + 西里尔裁剪词表,~150–200MB,移动端) +- 模型托管:HF Hub 或自有 CDN,**不进 git 仓库**;`public/` 只放模型清单 JSON(版本、URL、校验和) + +**验收**:held-out 集上行分类 F1 显著高于纯规则候选层;zh/en 微调后日语零样本可用。 + +## Phase 4 — 集成与数据回流 + +- 决策流水线落地:规则候选 →(低置信度时)模型增强 → 全局验证 → 兜底 +- 解析结果持久化到 IndexedDB(复用 `lib/indexedDB.ts`),一本书只解析一次 +- 目录手动编辑 UI:用户可增删改章节点;**用户修正即标注数据**,本地留存, + (可选、需用户同意)匿名回传作为下一轮训练语料 +- i18n:新增文案走 `locales/` + +## 里程碑与顺序 + +| 阶段 | 依赖 | 独立价值 | +|------|------|----------| +| P1 规则层 | 无 | 可直接上线,覆盖 ~95% 常规书 | +| P2 推理设施 | 无(与 P1 并行) | 链路验证,为任意 NLP 能力铺路 | +| P3 训练管线 | P1 的 bad case 积累 | 产出模型文件 | +| P4 集成 | P1+P2+P3 | 完整体验 + 数据飞轮 | + +**P3 的启动前提是 P1 上线后攒到足量真实 bad case**——如果规则层实际准确率已满足需求, +P3/P4 的模型部分可以推迟或取消,P2 的基础设施投入依然保值。 + +## 风险登记 + +1. **iOS 内存**(高):280MB 模型 + ORT 运行时峰值可能触顶。缓解:移动端用 pruned 版 + + 真机压测;最坏情况移动端仅规则层。 +2. **训练数据同义反复**(高):epub 自动标签只覆盖规则可解样本。缓解:bad case 人工标注 + 作为硬性启动条件;用户修正数据回流。 +3. **WebGPU 兼容长尾**(中):旧设备回退 WASM 后推理变慢。缓解:懒加载 + 规则层先出结果, + 模型结果异步刷新目录。 +4. **模型托管成本**(低):280MB × 用户量的 CDN 流量。缓解:懒加载天然限流;HF Hub 免费托管起步。 diff --git a/package.json b/package.json index 459580a..fff2844 100644 --- a/package.json +++ b/package.json @@ -21,40 +21,40 @@ "author": "", "license": "MIT", "devDependencies": { - "@eslint/js": "^9.39.1", - "@tailwindcss/oxide-darwin-arm64": "^4.1.17", - "@tailwindcss/postcss": "^4.1.17", - "@tailwindcss/vite": "^4.1.17", + "@eslint/js": "^10.0.1", + "@tailwindcss/oxide-darwin-arm64": "^4.3.2", + "@tailwindcss/postcss": "^4.3.2", + "@tailwindcss/vite": "^4.3.2", "@types/crypto-js": "^4.2.2", - "@types/node": "^25.0.0", - "@types/react": "^19.2.7", + "@types/node": "^26.1.1", + "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", - "@typescript-eslint/parser": "^8.49.0", - "@vitejs/plugin-react": "^5.1.2", - "autoprefixer": "^10.4.22", - "eslint": "^9.39.1", - "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-n": "^17.23.1", - "eslint-plugin-regexp": "^2.10.0", - "globals": "^16.5.0", - "postcss": "^8.5.6", - "prettier": "^3.7.4", - "react": "^19.2.1", - "react-dom": "^19.2.1", - "react-router-dom": "^7.10.1", - "sass-embedded": "^1.96.0", - "tailwindcss": "^4.1.17", - "tsx": "^4.21.0", - "typescript": "^5.9.3", - "typescript-eslint": "^8.49.0", - "vite": "^7.2.7" + "@typescript-eslint/parser": "^8.64.0", + "@vitejs/plugin-react": "^6.0.3", + "autoprefixer": "^10.5.3", + "eslint": "^10.7.0", + "eslint-plugin-import-x": "^4.17.1", + "eslint-plugin-n": "^18.2.2", + "eslint-plugin-regexp": "^3.1.1", + "globals": "^17.7.0", + "postcss": "^8.5.19", + "prettier": "^3.9.5", + "react": "^19.2.7", + "react-dom": "^19.2.7", + "react-router-dom": "^7.18.1", + "sass-embedded": "^1.100.0", + "tailwindcss": "^4.3.2", + "tsx": "^4.23.1", + "typescript": "^7.0.2", + "typescript-eslint": "^8.64.0", + "vite": "^8.1.4" }, "dependencies": { - "@khmyznikov/pwa-install": "^0.6.0", + "@khmyznikov/pwa-install": "^0.6.4", "crypto-js": "^4.2.0", "jschardet": "^3.1.4", - "lit": "^3.3.1", - "ranui": "0.1.10-alpha-27", - "ranuts": "0.1.0-alpha-23" + "lit": "^3.3.3", + "ranui": "0.2.1-alpha.1", + "ranuts": "0.2.0-alpha.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08f5a8f..9ac4a8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,8 +9,8 @@ importers: .: dependencies: '@khmyznikov/pwa-install': - specifier: ^0.6.0 - version: 0.6.0(@lit/react@1.0.7(@types/react@19.2.7))(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.1) + specifier: ^0.6.4 + version: 0.6.4(@lit/react@1.0.8(@types/react@19.2.17))(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.3) crypto-js: specifier: ^4.2.0 version: 4.2.0 @@ -18,96 +18,96 @@ importers: specifier: ^3.1.4 version: 3.1.4 lit: - specifier: ^3.3.1 - version: 3.3.1 + specifier: ^3.3.3 + version: 3.3.3 ranui: - specifier: 0.1.10-alpha-27 - version: 0.1.10-alpha-27 + specifier: 0.2.1-alpha.1 + version: 0.2.1-alpha.1 ranuts: - specifier: 0.1.0-alpha-23 - version: 0.1.0-alpha-23 + specifier: 0.2.0-alpha.1 + version: 0.2.0-alpha.1 devDependencies: '@eslint/js': - specifier: ^9.39.1 - version: 9.39.1 + specifier: ^10.0.1 + version: 10.0.1(eslint@10.7.0(jiti@2.7.0)) '@tailwindcss/oxide-darwin-arm64': - specifier: ^4.1.17 - version: 4.1.17 + specifier: ^4.3.2 + version: 4.3.2 '@tailwindcss/postcss': - specifier: ^4.1.17 - version: 4.1.17 + specifier: ^4.3.2 + version: 4.3.2 '@tailwindcss/vite': - specifier: ^4.1.17 - version: 4.1.17(vite@7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0)) + specifier: ^4.3.2 + version: 4.3.2(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1)) '@types/crypto-js': specifier: ^4.2.2 version: 4.2.2 '@types/node': - specifier: ^25.0.0 - version: 25.0.0 + specifier: ^26.1.1 + version: 26.1.1 '@types/react': - specifier: ^19.2.7 - version: 19.2.7 + specifier: ^19.2.17 + version: 19.2.17 '@types/react-dom': specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.7) + version: 19.2.3(@types/react@19.2.17) '@typescript-eslint/parser': - specifier: ^8.49.0 - version: 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.64.0 + version: 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) '@vitejs/plugin-react': - specifier: ^5.1.2 - version: 5.1.2(vite@7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0)) + specifier: ^6.0.3 + version: 6.0.3(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1)) autoprefixer: - specifier: ^10.4.22 - version: 10.4.22(postcss@8.5.6) + specifier: ^10.5.3 + version: 10.5.3(postcss@8.5.19) eslint: - specifier: ^9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: ^10.7.0 + version: 10.7.0(jiti@2.7.0) eslint-plugin-import-x: - specifier: ^4.16.1 - version: 4.16.1(@typescript-eslint/utils@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)) + specifier: ^4.17.1 + version: 4.17.1(@typescript-eslint/utils@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2))(eslint@10.7.0(jiti@2.7.0)) eslint-plugin-n: - specifier: ^17.23.1 - version: 17.23.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^18.2.2 + version: 18.2.2(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) eslint-plugin-regexp: - specifier: ^2.10.0 - version: 2.10.0(eslint@9.39.1(jiti@2.6.1)) + specifier: ^3.1.1 + version: 3.1.1(eslint@10.7.0(jiti@2.7.0)) globals: - specifier: ^16.5.0 - version: 16.5.0 + specifier: ^17.7.0 + version: 17.7.0 postcss: - specifier: ^8.5.6 - version: 8.5.6 + specifier: ^8.5.19 + version: 8.5.19 prettier: - specifier: ^3.7.4 - version: 3.7.4 + specifier: ^3.9.5 + version: 3.9.5 react: - specifier: ^19.2.1 - version: 19.2.1 + specifier: ^19.2.7 + version: 19.2.7 react-dom: - specifier: ^19.2.1 - version: 19.2.1(react@19.2.1) + specifier: ^19.2.7 + version: 19.2.7(react@19.2.7) react-router-dom: - specifier: ^7.10.1 - version: 7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + specifier: ^7.18.1 + version: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) sass-embedded: - specifier: ^1.96.0 - version: 1.96.0 + specifier: ^1.100.0 + version: 1.100.0 tailwindcss: - specifier: ^4.1.17 - version: 4.1.17 + specifier: ^4.3.2 + version: 4.3.2 tsx: - specifier: ^4.21.0 - version: 4.21.0 + specifier: ^4.23.1 + version: 4.23.1 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^7.0.2 + version: 7.0.2 typescript-eslint: - specifier: ^8.49.0 - version: 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.64.0 + version: 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) vite: - specifier: ^7.2.7 - version: 7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0) + specifier: ^8.1.4 + version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1) packages: @@ -115,415 +115,185 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} - engines: {node: '>=6.9.0'} + '@bufbuild/protobuf@2.12.1': + resolution: {integrity: sha512-BvAMfS6LrgZiryOAZ4pBYucu4wG/Ei/9o9DZ9akbREnMLbPJiom2i8b9C8IsKErQoiKqVhrerzt3kOT/RrzLHg==} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} - engines: {node: '>=6.9.0'} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} - engines: {node: '>=6.9.0'} - - '@bufbuild/protobuf@2.10.1': - resolution: {integrity: sha512-ckS3+vyJb5qGpEYv/s1OebUHDi/xSNtfgw1wqKZo7MR9F2z+qXr0q5XagafAG/9O0QPVIUfST0smluYSTpYFkg==} - - '@emnapi/core@1.7.1': - resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} - - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.27.1': - resolution: {integrity: sha512-HHB50pdsBX6k47S4u5g/CaLjqS3qwaOVE5ILsq64jyzgMhLuCuZ8rGzM9yhsAjfjkbgUPMzZEPa7DAp7yz6vuA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.27.1': - resolution: {integrity: sha512-45fuKmAJpxnQWixOGCrS+ro4Uvb4Re9+UTieUY2f8AEc+t7d4AaZ6eUJ3Hva7dtrxAAWHtlEFsXFMAgNnGU9uQ==} + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-arm@0.27.1': - resolution: {integrity: sha512-kFqa6/UcaTbGm/NncN9kzVOODjhZW8e+FRdSeypWe6j33gzclHtwlANs26JrupOntlcWmB0u8+8HZo8s7thHvg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.27.1': - resolution: {integrity: sha512-LBEpOz0BsgMEeHgenf5aqmn/lLNTFXVfoWMUox8CtWWYK9X4jmQzWjoGoNb8lmAYml/tQ/Ysvm8q7szu7BoxRQ==} + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.27.1': - resolution: {integrity: sha512-veg7fL8eMSCVKL7IW4pxb54QERtedFDfY/ASrumK/SbFsXnRazxY4YykN/THYqFnFwJ0aVjiUrVG2PwcdAEqQQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.27.1': - resolution: {integrity: sha512-+3ELd+nTzhfWb07Vol7EZ+5PTbJ/u74nC6iv4/lwIU99Ip5uuY6QoIf0Hn4m2HoV0qcnRivN3KSqc+FyCHjoVQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.27.1': - resolution: {integrity: sha512-/8Rfgns4XD9XOSXlzUDepG8PX+AVWHliYlUkFI3K3GB6tqbdjYqdhcb4BKRd7C0BhZSoaCxhv8kTcBrcZWP+xg==} + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.1': - resolution: {integrity: sha512-GITpD8dK9C+r+5yRT/UKVT36h/DQLOHdwGVwwoHidlnA168oD3uxA878XloXebK4Ul3gDBBIvEdL7go9gCUFzQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.27.1': - resolution: {integrity: sha512-W9//kCrh/6in9rWIBdKaMtuTTzNj6jSeG/haWBADqLLa9P8O5YSRDzgD5y9QBok4AYlzS6ARHifAb75V6G670Q==} + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.27.1': - resolution: {integrity: sha512-ieMID0JRZY/ZeCrsFQ3Y3NlHNCqIhTprJfDgSB3/lv5jJZ8FX3hqPyXWhe+gvS5ARMBJ242PM+VNz/ctNj//eA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.27.1': - resolution: {integrity: sha512-VIUV4z8GD8rtSVMfAj1aXFahsi/+tcoXXNYmXgzISL+KB381vbSTNdeZHHHIYqFyXcoEhu9n5cT+05tRv13rlw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.27.1': - resolution: {integrity: sha512-l4rfiiJRN7sTNI//ff65zJ9z8U+k6zcCg0LALU5iEWzY+a1mVZ8iWC1k5EsNKThZ7XCQ6YWtsZ8EWYm7r1UEsg==} + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.27.1': - resolution: {integrity: sha512-U0bEuAOLvO/DWFdygTHWY8C067FXz+UbzKgxYhXC0fDieFa0kDIra1FAhsAARRJbvEyso8aAqvPdNxzWuStBnA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.27.1': - resolution: {integrity: sha512-NzdQ/Xwu6vPSf/GkdmRNsOfIeSGnh7muundsWItmBsVpMoNPVpM61qNzAVY3pZ1glzzAxLR40UyYM23eaDDbYQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.27.1': - resolution: {integrity: sha512-7zlw8p3IApcsN7mFw0O1Z1PyEk6PlKMu18roImfl3iQHTnr/yAfYv6s4hXPidbDoI2Q0pW+5xeoM4eTCC0UdrQ==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.27.1': - resolution: {integrity: sha512-cGj5wli+G+nkVQdZo3+7FDKC25Uh4ZVwOAK6A06Hsvgr8WqBBuOy/1s+PUEd/6Je+vjfm6stX0kmib5b/O2Ykw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.27.1': - resolution: {integrity: sha512-z3H/HYI9MM0HTv3hQZ81f+AKb+yEoCRlUby1F80vbQ5XdzEMyY/9iNlAmhqiBKw4MJXwfgsh7ERGEOhrM1niMA==} + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.27.1': - resolution: {integrity: sha512-wzC24DxAvk8Em01YmVXyjl96Mr+ecTPyOuADAvjGg+fyBpGmxmcr2E5ttf7Im8D0sXZihpxzO1isus8MdjMCXQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.1': - resolution: {integrity: sha512-1YQ8ybGi2yIXswu6eNzJsrYIGFpnlzEWRl6iR5gMgmsrR0FcNoV1m9k9sc3PuP5rUBLshOZylc9nqSgymI+TYg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-arm64@0.27.1': - resolution: {integrity: sha512-5Z+DzLCrq5wmU7RDaMDe2DVXMRm2tTDvX2KU14JJVBN2CT/qov7XVix85QoJqHltpvAOZUAc3ndU56HSMWrv8g==} + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.1': - resolution: {integrity: sha512-Q73ENzIdPF5jap4wqLtsfh8YbYSZ8Q0wnxplOlZUOyZy7B4ZKW8DXGWgTCZmF8VWD7Tciwv5F4NsRf6vYlZtqg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/openharmony-arm64@0.27.1': - resolution: {integrity: sha512-ajbHrGM/XiK+sXM0JzEbJAen+0E+JMQZ2l4RR4VFwvV9JEERx+oxtgkpoKv1SevhjavK2z2ReHk32pjzktWbGg==} + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.27.1': - resolution: {integrity: sha512-IPUW+y4VIjuDVn+OMzHc5FV4GubIwPnsz6ubkvN8cuhEqH81NovB53IUlrlBkPMEPxvNnf79MGBoz8rZ2iW8HA==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.27.1': - resolution: {integrity: sha512-RIVRWiljWA6CdVu8zkWcRmGP7iRRIIwvhDKem8UMBjPql2TXM5PkDVvvrzMtj1V+WFPB4K7zkIGM7VzRtFkjdg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.27.1': - resolution: {integrity: sha512-2BR5M8CPbptC1AK5JbJT1fWrHLvejwZidKx3UMSF0ecHMa+smhi16drIrCEggkgviBwLYd5nwrFLSl5Kho96RQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.27.1': - resolution: {integrity: sha512-d5X6RMYv6taIymSk8JBP+nxv8DQAMY6A51GPgusqLdK9wBz5wWIXy1KjTck6HnjE9hqJzJRdk+1p/t5soSbCtw==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -532,40 +302,45 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-helpers@0.6.0': + resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true - '@eslint/js@9.39.1': - resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/plugin-kit@0.7.2': + resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -576,14 +351,6 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -600,282 +367,283 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@khmyznikov/pwa-install@0.6.0': - resolution: {integrity: sha512-t3m6SMCck4gL/W5eFTe7QzKJOuQreI4qfwrFEO3W6ATu44P6DU1WvhjKSjq2TVS3LEFxfVW+vN0ZzQOc2mhRWg==} + '@khmyznikov/pwa-install@0.6.4': + resolution: {integrity: sha512-Ks80e6Ltzdq0qnz8csuTtIaxjJz0RxPvbi2CBt997g4mm21evq+kRp4ima9lqhFhRCxbwmzBwnu2B3to9lxdhw==} peerDependencies: - '@lit/react': ^1.0.7 + '@lit/react': ^1.0.8 '@types/dom-chromium-installation-events': ^101.0.4 '@types/web-app-manifest': ^1.0.9 - lit: ^3.3.0 + lit: ^3.3.3 - '@lit-labs/ssr-dom-shim@1.4.0': - resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} + '@lit-labs/ssr-dom-shim@1.6.0': + resolution: {integrity: sha512-VHb0ALPMTlgKjM6yIxxoQNnpKyUKLD04VzeQdsiXkMqkvYlAHxq9glGLmgbb889/1GsohSOAjvQYoiBppXFqrQ==} - '@lit/react@1.0.7': - resolution: {integrity: sha512-cencnwwLXQKiKxjfFzSgZRngcWJzUDZi/04E0fSaF86wZgchMdvTyu+lE36DrUfvuus3bH8+xLPrhM1cTjwpzw==} + '@lit/react@1.0.8': + resolution: {integrity: sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==} peerDependencies: '@types/react': 17 || 18 || 19 - '@lit/reactive-element@2.1.1': - resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==} + '@lit/reactive-element@2.1.2': + resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} + + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 - '@napi-rs/wasm-runtime@0.2.12': - resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@oxc-project/types@0.139.0': + resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} - '@parcel/watcher-android-arm64@2.5.1': - resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==} + '@parcel/watcher-android-arm64@2.5.6': + resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [android] - '@parcel/watcher-darwin-arm64@2.5.1': - resolution: {integrity: sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==} + '@parcel/watcher-darwin-arm64@2.5.6': + resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [darwin] - '@parcel/watcher-darwin-x64@2.5.1': - resolution: {integrity: sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==} + '@parcel/watcher-darwin-x64@2.5.6': + resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [darwin] - '@parcel/watcher-freebsd-x64@2.5.1': - resolution: {integrity: sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==} + '@parcel/watcher-freebsd-x64@2.5.6': + resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [freebsd] - '@parcel/watcher-linux-arm-glibc@2.5.1': - resolution: {integrity: sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==} + '@parcel/watcher-linux-arm-glibc@2.5.6': + resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-arm-musl@2.5.1': - resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} + '@parcel/watcher-linux-arm-musl@2.5.6': + resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] - '@parcel/watcher-linux-arm64-glibc@2.5.1': - resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} + '@parcel/watcher-linux-arm64-glibc@2.5.6': + resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-arm64-musl@2.5.1': - resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} + '@parcel/watcher-linux-arm64-musl@2.5.6': + resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] - '@parcel/watcher-linux-x64-glibc@2.5.1': - resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} + '@parcel/watcher-linux-x64-glibc@2.5.6': + resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] - '@parcel/watcher-linux-x64-musl@2.5.1': - resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} + '@parcel/watcher-linux-x64-musl@2.5.6': + resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] - '@parcel/watcher-win32-arm64@2.5.1': - resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} + '@parcel/watcher-win32-arm64@2.5.6': + resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [win32] - '@parcel/watcher-win32-ia32@2.5.1': - resolution: {integrity: sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==} + '@parcel/watcher-win32-ia32@2.5.6': + resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} engines: {node: '>= 10.0.0'} cpu: [ia32] os: [win32] - '@parcel/watcher-win32-x64@2.5.1': - resolution: {integrity: sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==} + '@parcel/watcher-win32-x64@2.5.6': + resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [win32] - '@parcel/watcher@2.5.1': - resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} + '@parcel/watcher@2.5.6': + resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} engines: {node: '>= 10.0.0'} - '@rolldown/pluginutils@1.0.0-beta.53': - resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} - - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + '@rolldown/binding-android-arm64@1.1.5': + resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + '@rolldown/binding-darwin-arm64@1.1.5': + resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + '@rolldown/binding-darwin-x64@1.1.5': + resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + '@rolldown/binding-freebsd-x64@1.1.5': + resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + '@rolldown/binding-linux-arm64-gnu@1.1.5': + resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + '@rolldown/binding-linux-arm64-musl@1.1.5': + resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + '@rolldown/binding-linux-s390x-gnu@1.1.5': + resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + '@rolldown/binding-linux-x64-gnu@1.1.5': + resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + '@rolldown/binding-linux-x64-musl@1.1.5': + resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + '@rolldown/binding-openharmony-arm64@1.1.5': + resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} - cpu: [arm64] - os: [win32] + '@rolldown/binding-wasm32-wasi@1.1.5': + resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} - cpu: [ia32] + '@rolldown/binding-win32-arm64-msvc@1.1.5': + resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + '@rolldown/binding-win32-x64-msvc@1.1.5': + resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} - cpu: [x64] - os: [win32] + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@tailwindcss/node@4.1.17': - resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} + '@tailwindcss/node@4.3.2': + resolution: {integrity: sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==} - '@tailwindcss/oxide-android-arm64@4.1.17': - resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-android-arm64@4.3.2': + resolution: {integrity: sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==} + engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.17': - resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-arm64@4.3.2': + resolution: {integrity: sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==} + engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.17': - resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-x64@4.3.2': + resolution: {integrity: sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==} + engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.17': - resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-freebsd-x64@4.3.2': + resolution: {integrity: sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==} + engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': - resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': + resolution: {integrity: sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==} + engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': - resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': + resolution: {integrity: sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': - resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': + resolution: {integrity: sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': - resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': + resolution: {integrity: sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.1.17': - resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-musl@4.3.2': + resolution: {integrity: sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.1.17': - resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} + '@tailwindcss/oxide-wasm32-wasi@4.3.2': + resolution: {integrity: sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -886,44 +654,32 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': - resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': + resolution: {integrity: sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==} + engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': - resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': + resolution: {integrity: sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==} + engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.17': - resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide@4.3.2': + resolution: {integrity: sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==} + engines: {node: '>= 20'} - '@tailwindcss/postcss@4.1.17': - resolution: {integrity: sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==} + '@tailwindcss/postcss@4.3.2': + resolution: {integrity: sha512-rjVWYCa7Ngbi5AarT6k8TkxUG3Wl1QKzHdIZVsjZSzf36Jmo2IKZt/NHRAwly8oDkbBOH0YTu+CHuf9jPxMc+g==} - '@tailwindcss/vite@4.1.17': - resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==} + '@tailwindcss/vite@4.3.2': + resolution: {integrity: sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 - - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + vite: ^5.2.0 || ^6 || ^7 || ^8 - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/crypto-js@4.2.2': resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==} @@ -931,22 +687,25 @@ packages: '@types/dom-chromium-installation-events@101.0.4': resolution: {integrity: sha512-jV4HXmW5D18bpndzAPF1REGE5xagQqrAexHgX9WoWIPpNaaHtsHQgu5uFbL2z0NIc9fOD0TIC1TRpJhYA1OPxw==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@25.0.0': - resolution: {integrity: sha512-rl78HwuZlaDIUSeUKkmogkhebA+8K1Hy7tddZuJ3D0xV8pZSfsYGTsliGUol1JPzu9EKnTxPC4L1fiWouStRew==} + '@types/node@26.1.1': + resolution: {integrity: sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==} '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: '@types/react': ^19.2.0 - '@types/react@19.2.7': - resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -954,256 +713,370 @@ packages: '@types/web-app-manifest@1.0.9': resolution: {integrity: sha512-aVz1aXTubyL6nvVRyz9W7QR60zHLTiCGAafqYRc/RYUjA1GFc4npUUr7RlfO1+yP6gVvxzFmIVp8ULLYqhBRdA==} - '@typescript-eslint/eslint-plugin@8.49.0': - resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} + '@typescript-eslint/eslint-plugin@8.64.0': + resolution: {integrity: sha512-CGvQPBxN3wZLu6Rz2kFUpZeoCm78xUic92ck39KPePkO1NPOwjCqdQnm5Q87tpWw9vcBvW8XLrDXjH9PWYtJ3Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.49.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser': ^8.64.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.49.0': - resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} + '@typescript-eslint/parser@8.64.0': + resolution: {integrity: sha512-KA0OshtlcCCXmbfqyZkM5pV3/WNraJf7DkJRLpyrmwPtud57H5BDX7C3k0LPSPxpprfRL+cJDGabF10mvNCoCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.49.0': - resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==} + '@typescript-eslint/project-service@8.64.0': + resolution: {integrity: sha512-tk4WpOJ6IEbGrVHaNmM0YRrwAD3exZlIK3iadQNAxh4YKk6jvUQ4ecq18n+v7+meh+cJ3j+D8nbk8sRKhlwLQg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.49.0': - resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} + '@typescript-eslint/scope-manager@8.64.0': + resolution: {integrity: sha512-CXEaFdYXjSTgKhisNkwCcJwTP8Pl+fmRrEQrri4nm3vU743bALrxzLmq7fHG/7e6a5xO0lDYeURpZmBuhHk54w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.49.0': - resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==} + '@typescript-eslint/tsconfig-utils@8.64.0': + resolution: {integrity: sha512-2yo8rRNKuzbVWQp5kslhANqZ2uDAeROQHBRZNPu8JDsHmeFNj/XJJhX/FhNUWmkHHvoNsKa6+tHJiig87EzsQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.49.0': - resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} + '@typescript-eslint/type-utils@8.64.0': + resolution: {integrity: sha512-XWG4Fmmv/6SvyS9nH8jWrKs6terwJvE8cyRt1CzYYqzp9OrPhCT4cMc/f7C6RZCwG+qMmiffJS1/qJP8G1URtg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.49.0': - resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} + '@typescript-eslint/types@8.64.0': + resolution: {integrity: sha512-qjhfuTfLXjA4IOzXvz0rTjT01BqEiIgPoUeMwiEjnaHKJMTNo8rH5pYW1a2L/0Dnux2fPC85AeyJoWaGa8WxTA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.49.0': - resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} + '@typescript-eslint/typescript-estree@8.64.0': + resolution: {integrity: sha512-Pztpsn1aCE1oWDvDEfUk31nngvvF7vUB5SwHFEaZIFpvw7WJtqUHHL4plBZDA9HfWJJjL13BdG0YrJInTUvoVA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.49.0': - resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} + '@typescript-eslint/utils@8.64.0': + resolution: {integrity: sha512-aJUGVB3+U0htrrCjoA8qukw8cm8fNCGAxK/tVoS70k8aeb7DETKeFozRiVFIwEeN9WJLsjaP3ph8I60tY2XZoQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.49.0': - resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} + '@typescript-eslint/visitor-keys@8.64.0': + resolution: {integrity: sha512-mrtuL8Nsn6gi2H4mo5KMTp823M+3Q19Ew/i+Zlikq20tIMm99C3Ez0dCmkWWnxut20esQvTg8aUSEhMcAOXhEw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} cpu: [arm] os: [android] - '@unrs/resolver-binding-android-arm64@1.11.1': - resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} cpu: [arm64] os: [android] - '@unrs/resolver-binding-darwin-arm64@1.11.1': - resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} cpu: [arm64] os: [darwin] - '@unrs/resolver-binding-darwin-x64@1.11.1': - resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} cpu: [x64] os: [darwin] - '@unrs/resolver-binding-freebsd-x64@1.11.1': - resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} cpu: [x64] os: [freebsd] - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} cpu: [arm] os: [linux] - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} cpu: [arm] os: [linux] - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} cpu: [arm64] os: [linux] + libc: [glibc] - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} cpu: [arm64] os: [linux] + libc: [musl] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + libc: [musl] - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} cpu: [ppc64] os: [linux] + libc: [glibc] - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} cpu: [riscv64] os: [linux] + libc: [glibc] - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} cpu: [riscv64] os: [linux] + libc: [musl] - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} cpu: [s390x] os: [linux] + libc: [glibc] - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} cpu: [x64] os: [linux] + libc: [glibc] - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} cpu: [x64] os: [linux] + libc: [musl] - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} cpu: [arm64] os: [win32] - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} cpu: [ia32] os: [win32] - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} cpu: [x64] os: [win32] - '@vitejs/plugin-react@5.1.2': - resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} + '@vitejs/plugin-react@6.0.3': + resolution: {integrity: sha512-vmFvco5/QuC2f9Oj+wTk0+9XeDFkHxSamwZKYc7MxYwKICfvUvlMhqKI0VuICPltGqh1neqBKDvO4kes1ya8vg==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} hasBin: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - autoprefixer@10.4.22: - resolution: {integrity: sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==} + autoprefixer@10.5.3: + resolution: {integrity: sha512-bJRzflk8GgE4JX+iZNEwz9f9p460NCHnU7bd+CZ9vIjIlZuTkt6F3WSl2oNO8StZBFx17nLEsiQ6H2wcZiY7nA==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.9.6: - resolution: {integrity: sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==} + baseline-browser-mapping@2.10.43: + resolution: {integrity: sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==} + engines: {node: '>=6.0.0'} hasBin: true - bmp-js@0.1.0: - resolution: {integrity: sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + brace-expansion@5.0.7: + resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} + engines: {node: 18 || 20 || >=22} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + browserslist@4.28.6: + resolution: {integrity: sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer-builder@0.2.0: - resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001760: - resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + caniuse-lite@1.0.30001805: + resolution: {integrity: sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA==} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} colorjs.io@0.5.2: resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} - comment-parser@1.4.1: - resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + comment-parser@1.4.7: + resolution: {integrity: sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==} engines: {node: '>= 12.0.0'} - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie@1.1.1: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} @@ -1218,14 +1091,6 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -1238,32 +1103,26 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} - hasBin: true - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - earcut@3.0.2: - resolution: {integrity: sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==} + earcut@3.2.3: + resolution: {integrity: sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==} - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + electron-to-chromium@1.5.392: + resolution: {integrity: sha512-1yQq3VQCZRwsnYc67Oc+1fge6Lwtn0hzi6zmEVkB61Zx21kTbwJAW4dFLadl5Rc1tKhG/kSpYXnfiAhu0f0a1g==} - enhanced-resolve@5.18.3: - resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} engines: {node: '>=10.13.0'} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true + enhanced-resolve@5.24.2: + resolution: {integrity: sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw==} + engines: {node: '>=10.13.0'} - esbuild@0.27.1: - resolution: {integrity: sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA==} + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} hasBin: true @@ -1290,21 +1149,18 @@ packages: unrs-resolver: optional: true - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-plugin-es-x@7.8.0: resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' - eslint-plugin-import-x@4.16.1: - resolution: {integrity: sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==} + eslint-plugin-import-x@4.17.1: + resolution: {integrity: sha512-4cdstYkKCyjumM2Q9NSI03K8D2a9F4Ssz33K2lv2hQa4KmR9jPLwk3uWGtNvclfqBrPGfGuMBwsGMbe6dMRbfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/utils': ^8.0.0 - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/utils': ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 eslint-import-resolver-node: '*' peerDependenciesMeta: '@typescript-eslint/utils': @@ -1312,33 +1168,40 @@ packages: eslint-import-resolver-node: optional: true - eslint-plugin-n@17.23.1: - resolution: {integrity: sha512-68PealUpYoHOBh332JLLD9Sj7OQUDkFpmcfqt8R9sySfFSeuGJjMTJQvCRRB96zO3A/PELRLkPrzsHmzEFQQ5A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-plugin-n@18.2.2: + resolution: {integrity: sha512-gOO0lIqwEjZ750kv9/SptCWArUoAZXJoBr0vYWTO2dCBxctHUXlBIigiC8xuxxr/NKqgIT6Ehz1xRcilj8a5cA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: '>=8.23.0' + eslint: '>=8.57.1' + ts-declaration-location: ^1.0.6 + typescript: '>=5.0.0' + peerDependenciesMeta: + ts-declaration-location: + optional: true + typescript: + optional: true - eslint-plugin-regexp@2.10.0: - resolution: {integrity: sha512-ovzQT8ESVn5oOe5a7gIDPD5v9bCSjIFJu57sVPDqgPRXicQzOnYfFN21WoQBQF18vrhT5o7UMKFwJQVVjyJ0ng==} - engines: {node: ^18 || >=20} + eslint-plugin-regexp@3.1.1: + resolution: {integrity: sha512-MxR5nqoQCtVWmJwia0D2+NlXX1xzdpkslsVOZLEYQ4PQWEaL65PCZXURxaBc3lPnkNFpNxzMIRmYVxdl8giXRA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} peerDependencies: - eslint: '>=8.44.0' + eslint: '>=9.38.0' - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@9.39.1: - resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@10.7.0: + resolution: {integrity: sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: jiti: '*' @@ -1346,12 +1209,12 @@ packages: jiti: optional: true - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -1388,10 +1251,6 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1400,8 +1259,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -1411,30 +1270,19 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - globals@15.15.0: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} - globals@16.5.0: - resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + globals@17.7.0: + resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} engines: {node: '>=18'} globrex@0.1.2: @@ -1447,36 +1295,21 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - idb-keyval@6.2.2: - resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + ignore@7.0.6: + resolution: {integrity: sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==} engines: {node: '>= 4'} - immutable@5.1.4: - resolution: {integrity: sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} + immutable@5.1.9: + resolution: {integrity: sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -1485,39 +1318,20 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-url@1.2.4: - resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} hasBin: true jschardet@3.1.4: resolution: {integrity: sha512-/kmVISmrwVwtyYU40iQUOp3SUPk2dhNCMsZBQX0R1/jZ8maaXJ/oZIzUOiyOqcgtLnETFKYChbJ5iDC/eWmFHg==} engines: {node: '>=0.1.90'} - jsdoc-type-pratt-parser@4.8.0: - resolution: {integrity: sha512-iZ8Bdb84lWRuGHamRXFyML07r21pcwBrLkHEuHgEY5UbCouBwv7ECknDRKzsQIXMiqpPymqtIf8TC/shYKB5rw==} - engines: {node: '>=12.0.0'} - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true + jsdoc-type-pratt-parser@7.2.0: + resolution: {integrity: sha512-dh140MMgjyg3JhJZY/+iEzW+NO5xR2gpbDFKHqotCmexElVntw7GjWjt511+C/Ef02RU5TKYrJo/Xlzk+OLaTw==} + engines: {node: '>=20.0.0'} json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -1528,11 +1342,6 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1540,118 +1349,105 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - lit-element@4.2.1: - resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==} + lit-element@4.2.2: + resolution: {integrity: sha512-aFKhNToWxoyhkNDmWZwEva2SlQia+jfG0fjIWV//YeTaWrVnOxD89dPKfigCUspXFmjzOEUQpOkejH5Ly6sG0w==} - lit-html@3.3.1: - resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==} + lit-html@3.3.3: + resolution: {integrity: sha512-el8M6jK2o3RXBnrSHX3ZKrsN8zEV63pSExTO1wYJz7QndGYZ8353e2a5PPX+qHe2aGayfnchQmkAojaWAREOIA==} - lit@3.3.1: - resolution: {integrity: sha512-Ksr/8L3PTapbdXJCk+EJVB78jDodUMaP54gD24W186zGRARvwrsPfS60wae/SSCTCNZVPd1chXqio1qHQmu4NA==} + lit@3.3.3: + resolution: {integrity: sha512-fycuvZg/hkpozL00lm1pEJH5nN/lr9ZXd6mJI2HSN4+Bzc+LDNdEApJ6HFbPkdFNHLvOplIIuJvxkS4XUxqirw==} locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -1666,25 +1462,9 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - - normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - - opencollective-postinstall@2.0.3: - resolution: {integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==} - hasBin: true + node-releases@2.0.51: + resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} + engines: {node: '>=18'} optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} @@ -1698,10 +1478,6 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1710,33 +1486,26 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.19: + resolution: {integrity: sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + prettier@3.9.5: + resolution: {integrity: sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==} engines: {node: '>=14'} hasBin: true @@ -1744,32 +1513,28 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - ranui@0.1.10-alpha-27: - resolution: {integrity: sha512-UtS2m0ipKG4Pqe5B/Ta5XcTMx2gOBIpEcwTeuZ9P/cQqkk0uf5MDUF4LVIoOUzVEU83ROXw1oWOzibt/sW4E5A==} - engines: {node: '>=23.10.0'} + ranui@0.2.1-alpha.1: + resolution: {integrity: sha512-3Tud2tvzKiAUMd8SjQrdTCdwdjoNdJ/yW1kbkHUP21Ff3rk0pFIDgIfR36jxy67yVm6wsfX/FcZ16SUfzicZEA==} + engines: {node: '>=20.19.0'} - ranuts@0.1.0-alpha-23: - resolution: {integrity: sha512-E6IlFEO2Ya07nPDOIOMe56cL/J6Rs2mHczzSN18GYJTKJS8p9EA054ef3MECcdtoKSlBodbMJZrO+in3u+cBEg==} + ranuts@0.2.0-alpha.1: + resolution: {integrity: sha512-cDqJigkrlQTeJq4Xthf2WmVUNTkLMF1ZEXmKSArF9xHKGaml4YfwXpYkz8ksk9MOMMugG1D2NYmcvaqR+ZXH4A==} engines: {node: '>=23.10.0'} - react-dom@19.2.1: - resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} + react-dom@19.2.7: + resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} peerDependencies: - react: ^19.2.1 - - react-refresh@0.18.0: - resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} - engines: {node: '>=0.10.0'} + react: ^19.2.7 - react-router-dom@7.10.1: - resolution: {integrity: sha512-JNBANI6ChGVjA5bwsUIwJk7LHKmqB4JYnYfzFwyp2t12Izva11elds2jx7Yfoup2zssedntwU0oZ5DEmk5Sdaw==} + react-router-dom@7.18.1: + resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.10.1: - resolution: {integrity: sha512-gHL89dRa3kwlUYtRQ+m8NmxGI6CgqN+k4XyGjwcFoQwwCWF6xXpOCUlDovkXClS0d0XJN/5q7kc5W3kiFEd0Yw==} + react-router@7.18.1: + resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -1778,157 +1543,153 @@ packages: react-dom: optional: true - react@19.2.1: - resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} engines: {node: '>=0.10.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} refa@0.12.1: resolution: {integrity: sha512-J8rn6v4DBb2nnFqkqwy6/NnTYMcgLA+sLr0iIO41qpv0n+ngb7ksag2tMRl0inb1bbO/esUwzW1vbJi7K0sI0g==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - regexp-ast-analysis@0.7.1: resolution: {integrity: sha512-sZuz1dYW/ZsfG17WSAG7eS85r5a0dDsvg+7BiiYR5o6lKCAtUrEwdmRmaGF6rwVj3LcmAeYkOWKEPlbPzN3Y3A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + rolldown@1.1.5: + resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - sass-embedded-all-unknown@1.96.0: - resolution: {integrity: sha512-UfUHoWZtxmsDjDfK+fKCy0aJe6zThu7oaIQx0c/vnHgvprcddEPIay01qTXhiUa3cFcsMmvlBvPTVw0gjKVtVQ==} + sass-embedded-all-unknown@1.100.0: + resolution: {integrity: sha512-auFtXY/kwYILmSVjtBDwyj0axcLbYYiffOKWoaXHnI5bsYwiRbBh3EneR1rpbX2ZIZCrwX93i5pxKLTZF/662Q==} cpu: ['!arm', '!arm64', '!riscv64', '!x64'] - sass-embedded-android-arm64@1.96.0: - resolution: {integrity: sha512-TJiebTo4TBF5Wrn+lFkUfSN3wazvl8kkFm9a1nA9ZtRdaE0nsJLGnMM6KLQLP2Vl+IOf6ovetZseISkClRoGXw==} + sass-embedded-android-arm64@1.100.0: + resolution: {integrity: sha512-W+Ru9JwTnfU0UX3jSZcbqFdtKFMcYdfFwytc57h2DgnqCOIiAqI2E06mABZBZC+r3LwXCBuS5GbXAGeVgvVDkA==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [android] - sass-embedded-android-arm@1.96.0: - resolution: {integrity: sha512-0mwVRBFig9hH8vFcRExBuBoR+CfUOcWdwarZwbxIFGI1IyH4BLBGiX85vVn6ssSCVNydpE6lFGm45CN8O0tQig==} + sass-embedded-android-arm@1.100.0: + resolution: {integrity: sha512-70f3HgX2pFNmzpGQ86n5e6QfWn2fP4QUQGfFQK0P1XH73ZLIzLo2YqygrGKGKeeqtc5eU2Wl1/xQzhzuKnO4kw==} engines: {node: '>=14.0.0'} cpu: [arm] os: [android] - sass-embedded-android-riscv64@1.96.0: - resolution: {integrity: sha512-7AVu/EeJqKN3BGNhm+tc1XzmoqbOtCwHG2VgN6j6Lyqh1JZlx0dglRtyQuKDZ7odTKiWmotEIuYZ6OxLmr2Ejg==} + sass-embedded-android-riscv64@1.100.0: + resolution: {integrity: sha512-icU3o0V/uCSytSpf+tX5Lf51BvyQEbLzDUJfUi9etSauYBGHpPKkdtdZH0si4v98phq11Kl8rSV1SggksxF1Hg==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [android] - sass-embedded-android-x64@1.96.0: - resolution: {integrity: sha512-ei/UsT0q8rF5JzWhn1A7B0M1y/IiWVY3l4zibQrXk5MGaOXHlCM6ffZD+2j7C613Jm9/KAQ7yX1NIIu72LPgDQ==} + sass-embedded-android-x64@1.100.0: + resolution: {integrity: sha512-mevF9VQk6gEYByy8+jusaHGmd7Usb2ytX/DsEOd0JtOGCtcf1kh575xJ6OUBDIcJ15uLnbau/0iy1eP6WVBvWA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [android] - sass-embedded-darwin-arm64@1.96.0: - resolution: {integrity: sha512-OMvN5NWcrrisC24ZR3GyaWJ1uFxw25qLnUkpEso9TSlaMWiomjU82/uQ/AkQvIMl+EMlJqeYLxZWvq/byLH5Xg==} + sass-embedded-darwin-arm64@1.100.0: + resolution: {integrity: sha512-1PVlYi61POo93IT/FfrG1mc1tAHxeSTyUALF2aOFmXGWjVXr3bQzEQiBGCOvQbj/ix+5hNyXFXcEMEyKvtUJJA==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [darwin] - sass-embedded-darwin-x64@1.96.0: - resolution: {integrity: sha512-J/R5sv0eW+/DU98rccHPO1f3lsTFjVTpdkU9d3P1yB7BFmQjw5PYde9BVRlXeOawPwfgT3p/hvY4RELScICdww==} + sass-embedded-darwin-x64@1.100.0: + resolution: {integrity: sha512-x97o3JnGyImZNCIVs9wQHJUE5QCvmVIKaH1cwrz/5dK7OT1FpeNiW+u9TUomP9hG6Ekjd8EL8NBHpxTfIhdjmg==} engines: {node: '>=14.0.0'} cpu: [x64] os: [darwin] - sass-embedded-linux-arm64@1.96.0: - resolution: {integrity: sha512-VcbVjK0/O/mru0h0FC1WSUWIzMqRrzuJ8eZNMXTs4vApfkh28pxNaUodwU81f1L1nngJ3vpFDBniUKpW6NwJhw==} + sass-embedded-linux-arm64@1.100.0: + resolution: {integrity: sha512-Dwjmj8Z6VRy7rAi53JAdEwIyUjpfl7PhpSc2/LpQPQx+aO5Dp7Spaipkax0ufJl1SoDUdchCsM4y/88YaluorQ==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] + libc: glibc - sass-embedded-linux-arm@1.96.0: - resolution: {integrity: sha512-XuQvV6gNld5Bz3rX0SFLtKPGMu4UQdXNp//9A+bDmtVGZ6yu8REIqphQBxOMpgkAKsA4JZLKKk1N97woeVsIlA==} + sass-embedded-linux-arm@1.100.0: + resolution: {integrity: sha512-9Ul7O1eKrc5YlhwWjkp8tZPSe3UEwSZ1uwUZOQom1HL0pRlBA6F/IlGZYFTLwnHMIP1fc77MMNaBRfc05mKMpw==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] + libc: glibc - sass-embedded-linux-musl-arm64@1.96.0: - resolution: {integrity: sha512-lVyLObEeu8Wgw8riC6dSMlkF7jVNAjdZ1jIBhvX1yDsrQwwaI60pM21YXmnZSFyCE6KVFkKAgwRQNO/IkoCwMA==} + sass-embedded-linux-musl-arm64@1.100.0: + resolution: {integrity: sha512-XpACJB2KjSLjf2e9uuvGVdOURsoNrFqgRiihhXyUHK9W0t3LIHb7z5MA/7XGPIT9bWSOO2zyw+rH/FHtDV/Yrg==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [linux] + libc: musl - sass-embedded-linux-musl-arm@1.96.0: - resolution: {integrity: sha512-qK7FrnczCVECZXtyYOoI3azFlMDZn70GI1yJPPuZLpWvwIPYoZOLv3u6JSec5o3wT6KeKyWG3ZpGIpigLUjPig==} + sass-embedded-linux-musl-arm@1.100.0: + resolution: {integrity: sha512-sl0JgbGloPyJg66XXx5UDSDScZ0oU85DpMQU4JU/sCUCFj1Z8zZ69SJWKTCNE4/jwnce7WI2zPCV5AG+RHOZJw==} engines: {node: '>=14.0.0'} cpu: [arm] os: [linux] + libc: musl - sass-embedded-linux-musl-riscv64@1.96.0: - resolution: {integrity: sha512-Y+DuGVRsM2zGl268QN5aF/Y6OFYTILb3f+6huEXKlGL6FK2MXadsmeoVbmKVrTamQHzyA2bWWMU1C0jhVFtlzg==} + sass-embedded-linux-musl-riscv64@1.100.0: + resolution: {integrity: sha512-ShvI0Kx04mwoCARwZ0UjiT97isQvzO80tAt91zmFyHLN9kelc/IrQi940farSm2xQVPCKdeVyeG0ekBsokSpYQ==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] + libc: musl - sass-embedded-linux-musl-x64@1.96.0: - resolution: {integrity: sha512-sAQtUQ8fFNxnxSf3fncOh892Hfxa4PW4e5qrnSE0Y1IGV/wsTzk7m5Z6IeT7sa3BsvXh5TFN6+JGbUoOJ5RigA==} + sass-embedded-linux-musl-x64@1.100.0: + resolution: {integrity: sha512-TDBCRWNuS4RDLQXvRc1gjZlWiWTWaWGp0Bwu/IKwJxov81lsvrCs3TihTyNXtW7V5aoN4Ky3r0QOkNb3mwmBnA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] + libc: musl - sass-embedded-linux-riscv64@1.96.0: - resolution: {integrity: sha512-Bf6bAjuUm6sfGHo0XoZEstjVkEWwmmtOSomGoPuAwXFS9GQnFcqDz9EXKNkZEOsQi2D+aDeDxs8HcU9/OLMT9g==} + sass-embedded-linux-riscv64@1.100.0: + resolution: {integrity: sha512-j4ENJGOheO+fm3j/yorLxCjBP6/XskrZx7dTLlT+lXYwN/qqCqoA/gsNLI0McS3DFM6GBwPiffzWsdWS8t6sEQ==} engines: {node: '>=14.0.0'} cpu: [riscv64] os: [linux] + libc: glibc - sass-embedded-linux-x64@1.96.0: - resolution: {integrity: sha512-U4GROkS0XM6ekqs/ubroWwFAGY9N35wqrt5q6Y+MJCpTK5bHPHlgFo7J75ZUSaEObL+UrDqvMDQkCdYEFiiQbg==} + sass-embedded-linux-x64@1.100.0: + resolution: {integrity: sha512-0vUSN8j0WGtCJIOPh//EmUvYGHW0QOe5iul8qyhPk50MAcw49MA0r34AhftjDdx94ILPF6vApFs0gwHPQRlpVA==} engines: {node: '>=14.0.0'} cpu: [x64] os: [linux] + libc: glibc - sass-embedded-unknown-all@1.96.0: - resolution: {integrity: sha512-OHzGEr2VElK2SaQdkkTX0O0KwTbiv1N/EhnHgzXYaZWOTvv0gxEfR7q7x/oScCBIZc2x8dSfvThfBnohIClo/w==} + sass-embedded-unknown-all@1.100.0: + resolution: {integrity: sha512-c+naBgWId4MIpToXcI0DgqetjdAkwTTAxFAuOaBz7HUXLdyG1oZRrEvSsbe41nEdQOKH0vgofVFCeSQgoXOG9A==} os: ['!android', '!darwin', '!linux', '!win32'] - sass-embedded-win32-arm64@1.96.0: - resolution: {integrity: sha512-KKz1h5pr45fwrKcxrxHsujo3f/HgVkX64YNJ9PRPuOuX7lU8g18IEgDxoTGQ64PPBQ5RXOt6jxpT+x2OLPVnCw==} + sass-embedded-win32-arm64@1.100.0: + resolution: {integrity: sha512-iE+yxj+hUXwwbqpHkXxgAWTzeRfcWxJ7SSTQEPMk48lwq3oCrWLlz5sQuWHbuTK/i0GKQfROdP+hOmPi89yjUg==} engines: {node: '>=14.0.0'} cpu: [arm64] os: [win32] - sass-embedded-win32-x64@1.96.0: - resolution: {integrity: sha512-MDreKaWcgiyKD5YPShaRvUBoe5dC2y8IPJK49G7iQjoMfw9INDCBkDdLcz00Mn0eJq4nJJp5UEE98M6ljIrBRg==} + sass-embedded-win32-x64@1.100.0: + resolution: {integrity: sha512-qI4F8MI7/KYoy9NdjJfhSspG42WPkADSNDvwEV7qWvCSFC83koJssRsKO2/PfY+niZz6BG65Ic/D+A11h959hw==} engines: {node: '>=14.0.0'} cpu: [x64] os: [win32] - sass-embedded@1.96.0: - resolution: {integrity: sha512-z9PQ7owvdhn7UuZGrpPccdkcH9xJd9iCv+UQhcPqppBslYEp0R9LRQVyyPTZg7jfA77bGxz/I8V48LXJR5LjXQ==} + sass-embedded@1.100.0: + resolution: {integrity: sha512-Ut8wlQSk19tm7jMK6mz6cF1+e+E7tUnW2tM02zQDPnOTcVbV8qCQG8UWxZkkNlY50+hV3hqP24OOkUlMz8xBpw==} engines: {node: '>=16.0.0'} hasBin: true - sass@1.96.0: - resolution: {integrity: sha512-8u4xqqUeugGNCYwr9ARNtQKTOj4KmYiJAVKXf2CTIivTCR51j96htbMKWDru8H5SaQWpyVgTfOF8Ylyf5pun1Q==} - engines: {node: '>=14.0.0'} + sass@1.100.0: + resolution: {integrity: sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==} + engines: {node: '>=20.19.0'} hasBin: true scheduler@0.27.0: @@ -1938,12 +1699,8 @@ packages: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true @@ -1966,70 +1723,40 @@ packages: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - sync-child-process@1.0.2: resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} engines: {node: '>=16.0.0'} - sync-message-port@1.1.3: - resolution: {integrity: sha512-GTt8rSKje5FilG+wEdfCkOcLL7LWqpMlr2c3LRuKt/YXxcJ52aGSbGBAdI4L3aaqfrBt6y711El53ItyH1NWzg==} + sync-message-port@1.2.0: + resolution: {integrity: sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==} engines: {node: '>=16.0.0'} - tailwindcss@4.1.17: - resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + tailwindcss@4.3.2: + resolution: {integrity: sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tesseract.js-core@6.1.1: - resolution: {integrity: sha512-sKF1bIctAoPr5CoooDN6Hvab32zCK2a2NfsXSgxjyHsS+LcwNz8WwwcULuqoQUpYa3SO5ScbrMgH6hEN1T3srg==} - - tesseract.js@6.0.1: - resolution: {integrity: sha512-/sPvMvrCtgxnNRCjbTYbr7BRu0yfWDsMZQ2a/T5aN/L1t8wUQN6tTWv6p6FwzpoEBA0jrN2UD2SX4QQFRdoDbA==} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' - ts-declaration-location@1.0.7: - resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} - peerDependencies: - typescript: '>=4.0.0' - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.21.0: - resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + tsx@4.23.1: + resolution: {integrity: sha512-GQHnkIfxyx1wYCOS/wonik5MVRZU9hi1TEZmzGZSCJB1y9YgoZ8H6itNE/u4suE+yLmOzuE4E5S4TZ/ZX2wcWQ==} engines: {node: '>=18.0.0'} hasBin: true @@ -2037,26 +1764,26 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.49.0: - resolution: {integrity: sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==} + typescript-eslint@8.64.0: + resolution: {integrity: sha512-0qg+pDNMnqYzqH9AnNK+39tejHvsShUOUUoRUgtnTGE7QuMZhiFDnozq8nHJVq+Wae6NMLKNWLg5WmkcC/ndyQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} hasBin: true - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - unrs-resolver@1.11.1: - resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -2067,15 +1794,16 @@ packages: varint@6.0.0: resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} - vite@7.2.7: - resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} + vite@8.1.4: + resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.0 + esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 - lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -2086,12 +1814,14 @@ packages: peerDependenciesMeta: '@types/node': optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true jiti: optional: true less: optional: true - lightningcss: - optional: true sass: optional: true sass-embedded: @@ -2107,15 +1837,6 @@ packages: yaml: optional: true - wasm-feature-detect@1.8.0: - resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2125,369 +1846,176 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zlibjs@0.3.1: - resolution: {integrity: sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==} - snapshots: - '@alloc/quick-lru@5.2.0': {} - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.5': {} - - '@babel/core@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.5': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.4': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - - '@babel/parser@7.28.5': - dependencies: - '@babel/types': 7.28.5 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - - '@babel/traverse@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.5': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@alloc/quick-lru@5.2.0': {} - '@bufbuild/protobuf@2.10.1': {} + '@bufbuild/protobuf@2.12.1': {} - '@emnapi/core@1.7.1': + '@emnapi/core@1.10.0': dependencies: - '@emnapi/wasi-threads': 1.1.0 + '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/core@1.11.1': dependencies: + '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.1.0': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.12': - optional: true - - '@esbuild/aix-ppc64@0.27.1': - optional: true - - '@esbuild/android-arm64@0.25.12': - optional: true - - '@esbuild/android-arm64@0.27.1': - optional: true - - '@esbuild/android-arm@0.25.12': - optional: true - - '@esbuild/android-arm@0.27.1': - optional: true - - '@esbuild/android-x64@0.25.12': - optional: true - - '@esbuild/android-x64@0.27.1': - optional: true - - '@esbuild/darwin-arm64@0.25.12': - optional: true - - '@esbuild/darwin-arm64@0.27.1': - optional: true - - '@esbuild/darwin-x64@0.25.12': - optional: true - - '@esbuild/darwin-x64@0.27.1': - optional: true - - '@esbuild/freebsd-arm64@0.25.12': - optional: true - - '@esbuild/freebsd-arm64@0.27.1': - optional: true - - '@esbuild/freebsd-x64@0.25.12': - optional: true - - '@esbuild/freebsd-x64@0.27.1': - optional: true - - '@esbuild/linux-arm64@0.25.12': - optional: true - - '@esbuild/linux-arm64@0.27.1': - optional: true - - '@esbuild/linux-arm@0.25.12': - optional: true - - '@esbuild/linux-arm@0.27.1': - optional: true - - '@esbuild/linux-ia32@0.25.12': - optional: true - - '@esbuild/linux-ia32@0.27.1': - optional: true - - '@esbuild/linux-loong64@0.25.12': - optional: true - - '@esbuild/linux-loong64@0.27.1': + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/linux-mips64el@0.25.12': + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/linux-mips64el@0.27.1': + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 optional: true - '@esbuild/linux-ppc64@0.25.12': + '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/linux-ppc64@0.27.1': + '@esbuild/android-arm64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.25.12': + '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/linux-riscv64@0.27.1': + '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/linux-s390x@0.25.12': + '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/linux-s390x@0.27.1': + '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/linux-x64@0.25.12': + '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/linux-x64@0.27.1': + '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.25.12': + '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.27.1': + '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/netbsd-x64@0.25.12': + '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/netbsd-x64@0.27.1': + '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.25.12': + '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.27.1': + '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.25.12': + '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.27.1': + '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.25.12': + '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.27.1': + '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.25.12': + '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/sunos-x64@0.27.1': + '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/win32-arm64@0.25.12': + '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.27.1': + '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.25.12': + '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-ia32@0.27.1': + '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-x64@0.25.12': + '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.27.1': + '@esbuild/win32-x64@0.28.1': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.7.0(jiti@2.7.0))': dependencies: - eslint: 9.39.1(jiti@2.6.1) + eslint: 10.7.0(jiti@2.7.0) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.23.5': dependencies: - '@eslint/object-schema': 2.1.7 + '@eslint/object-schema': 3.0.5 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 10.2.5 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.4.2': + '@eslint/config-helpers@0.6.0': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 - '@eslint/core@0.17.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.3': - dependencies: - ajv: 6.12.6 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.1': {} + '@eslint/js@10.0.1(eslint@10.7.0(jiti@2.7.0))': + optionalDependencies: + eslint: 10.7.0(jiti@2.7.0) - '@eslint/object-schema@2.1.7': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.4.1': + '@eslint/plugin-kit@0.7.2': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 levn: 0.4.1 - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2507,277 +2035,250 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@khmyznikov/pwa-install@0.6.0(@lit/react@1.0.7(@types/react@19.2.7))(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.1)': + '@khmyznikov/pwa-install@0.6.4(@lit/react@1.0.8(@types/react@19.2.17))(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.3)': dependencies: - '@lit/react': 1.0.7(@types/react@19.2.7) + '@lit/react': 1.0.8(@types/react@19.2.17) '@types/dom-chromium-installation-events': 101.0.4 '@types/web-app-manifest': 1.0.9 - lit: 3.3.1 + lit: 3.3.3 + + '@lit-labs/ssr-dom-shim@1.6.0': {} - '@lit-labs/ssr-dom-shim@1.4.0': {} + '@lit/react@1.0.8(@types/react@19.2.17)': + dependencies: + '@types/react': 19.2.17 - '@lit/react@1.0.7(@types/react@19.2.7)': + '@lit/reactive-element@2.1.2': dependencies: - '@types/react': 19.2.7 + '@lit-labs/ssr-dom-shim': 1.6.0 - '@lit/reactive-element@2.1.1': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@lit-labs/ssr-dom-shim': 1.4.0 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.3 + optional: true - '@napi-rs/wasm-runtime@0.2.12': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 - '@tybys/wasm-util': 0.10.1 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 optional: true - '@parcel/watcher-android-arm64@2.5.1': + '@oxc-project/types@0.139.0': {} + + '@parcel/watcher-android-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-arm64@2.5.1': + '@parcel/watcher-darwin-arm64@2.5.6': optional: true - '@parcel/watcher-darwin-x64@2.5.1': + '@parcel/watcher-darwin-x64@2.5.6': optional: true - '@parcel/watcher-freebsd-x64@2.5.1': + '@parcel/watcher-freebsd-x64@2.5.6': optional: true - '@parcel/watcher-linux-arm-glibc@2.5.1': + '@parcel/watcher-linux-arm-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm-musl@2.5.1': + '@parcel/watcher-linux-arm-musl@2.5.6': optional: true - '@parcel/watcher-linux-arm64-glibc@2.5.1': + '@parcel/watcher-linux-arm64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-arm64-musl@2.5.1': + '@parcel/watcher-linux-arm64-musl@2.5.6': optional: true - '@parcel/watcher-linux-x64-glibc@2.5.1': + '@parcel/watcher-linux-x64-glibc@2.5.6': optional: true - '@parcel/watcher-linux-x64-musl@2.5.1': + '@parcel/watcher-linux-x64-musl@2.5.6': optional: true - '@parcel/watcher-win32-arm64@2.5.1': + '@parcel/watcher-win32-arm64@2.5.6': optional: true - '@parcel/watcher-win32-ia32@2.5.1': + '@parcel/watcher-win32-ia32@2.5.6': optional: true - '@parcel/watcher-win32-x64@2.5.1': + '@parcel/watcher-win32-x64@2.5.6': optional: true - '@parcel/watcher@2.5.1': + '@parcel/watcher@2.5.6': dependencies: - detect-libc: 1.0.3 + detect-libc: 2.1.2 is-glob: 4.0.3 - micromatch: 4.0.8 node-addon-api: 7.1.1 + picomatch: 4.0.5 optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.1 - '@parcel/watcher-darwin-arm64': 2.5.1 - '@parcel/watcher-darwin-x64': 2.5.1 - '@parcel/watcher-freebsd-x64': 2.5.1 - '@parcel/watcher-linux-arm-glibc': 2.5.1 - '@parcel/watcher-linux-arm-musl': 2.5.1 - '@parcel/watcher-linux-arm64-glibc': 2.5.1 - '@parcel/watcher-linux-arm64-musl': 2.5.1 - '@parcel/watcher-linux-x64-glibc': 2.5.1 - '@parcel/watcher-linux-x64-musl': 2.5.1 - '@parcel/watcher-win32-arm64': 2.5.1 - '@parcel/watcher-win32-ia32': 2.5.1 - '@parcel/watcher-win32-x64': 2.5.1 - optional: true - - '@rolldown/pluginutils@1.0.0-beta.53': {} - - '@rollup/rollup-android-arm-eabi@4.53.3': - optional: true - - '@rollup/rollup-android-arm64@4.53.3': - optional: true - - '@rollup/rollup-darwin-arm64@4.53.3': - optional: true - - '@rollup/rollup-darwin-x64@4.53.3': - optional: true - - '@rollup/rollup-freebsd-arm64@4.53.3': - optional: true - - '@rollup/rollup-freebsd-x64@4.53.3': + '@parcel/watcher-android-arm64': 2.5.6 + '@parcel/watcher-darwin-arm64': 2.5.6 + '@parcel/watcher-darwin-x64': 2.5.6 + '@parcel/watcher-freebsd-x64': 2.5.6 + '@parcel/watcher-linux-arm-glibc': 2.5.6 + '@parcel/watcher-linux-arm-musl': 2.5.6 + '@parcel/watcher-linux-arm64-glibc': 2.5.6 + '@parcel/watcher-linux-arm64-musl': 2.5.6 + '@parcel/watcher-linux-x64-glibc': 2.5.6 + '@parcel/watcher-linux-x64-musl': 2.5.6 + '@parcel/watcher-win32-arm64': 2.5.6 + '@parcel/watcher-win32-ia32': 2.5.6 + '@parcel/watcher-win32-x64': 2.5.6 optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + '@rolldown/binding-android-arm64@1.1.5': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.3': + '@rolldown/binding-darwin-arm64@1.1.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.3': + '@rolldown/binding-darwin-x64@1.1.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.3': + '@rolldown/binding-freebsd-x64@1.1.5': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.3': + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.3': + '@rolldown/binding-linux-arm64-gnu@1.1.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.3': + '@rolldown/binding-linux-arm64-musl@1.1.5': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.3': + '@rolldown/binding-linux-ppc64-gnu@1.1.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.3': + '@rolldown/binding-linux-s390x-gnu@1.1.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.3': + '@rolldown/binding-linux-x64-gnu@1.1.5': optional: true - '@rollup/rollup-linux-x64-musl@4.53.3': + '@rolldown/binding-linux-x64-musl@1.1.5': optional: true - '@rollup/rollup-openharmony-arm64@4.53.3': + '@rolldown/binding-openharmony-arm64@1.1.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.3': + '@rolldown/binding-wasm32-wasi@1.1.5': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.3': + '@rolldown/binding-win32-arm64-msvc@1.1.5': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.3': + '@rolldown/binding-win32-x64-msvc@1.1.5': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.3': - optional: true + '@rolldown/pluginutils@1.0.1': {} - '@tailwindcss/node@4.1.17': + '@tailwindcss/node@4.3.2': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.3 - jiti: 2.6.1 - lightningcss: 1.30.2 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.1.17 + tailwindcss: 4.3.2 - '@tailwindcss/oxide-android-arm64@4.1.17': + '@tailwindcss/oxide-android-arm64@4.3.2': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.17': {} + '@tailwindcss/oxide-darwin-arm64@4.3.2': {} - '@tailwindcss/oxide-darwin-x64@4.1.17': + '@tailwindcss/oxide-darwin-x64@4.3.2': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.17': + '@tailwindcss/oxide-freebsd-x64@4.3.2': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.2': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + '@tailwindcss/oxide-linux-arm64-gnu@4.3.2': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + '@tailwindcss/oxide-linux-arm64-musl@4.3.2': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + '@tailwindcss/oxide-linux-x64-gnu@4.3.2': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.17': + '@tailwindcss/oxide-linux-x64-musl@4.3.2': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.17': + '@tailwindcss/oxide-wasm32-wasi@4.3.2': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + '@tailwindcss/oxide-win32-arm64-msvc@4.3.2': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + '@tailwindcss/oxide-win32-x64-msvc@4.3.2': optional: true - '@tailwindcss/oxide@4.1.17': + '@tailwindcss/oxide@4.3.2': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-x64': 4.1.17 - '@tailwindcss/oxide-freebsd-x64': 4.1.17 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-x64-musl': 4.1.17 - '@tailwindcss/oxide-wasm32-wasi': 4.1.17 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 - - '@tailwindcss/postcss@4.1.17': + '@tailwindcss/oxide-android-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-arm64': 4.3.2 + '@tailwindcss/oxide-darwin-x64': 4.3.2 + '@tailwindcss/oxide-freebsd-x64': 4.3.2 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.2 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.2 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.2 + '@tailwindcss/oxide-linux-x64-musl': 4.3.2 + '@tailwindcss/oxide-wasm32-wasi': 4.3.2 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.2 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.2 + + '@tailwindcss/postcss@4.3.2': dependencies: '@alloc/quick-lru': 5.2.0 - '@tailwindcss/node': 4.1.17 - '@tailwindcss/oxide': 4.1.17 - postcss: 8.5.6 - tailwindcss: 4.1.17 + '@tailwindcss/node': 4.3.2 + '@tailwindcss/oxide': 4.3.2 + postcss: 8.5.19 + tailwindcss: 4.3.2 - '@tailwindcss/vite@4.1.17(vite@7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0))': + '@tailwindcss/vite@4.3.2(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1))': dependencies: - '@tailwindcss/node': 4.1.17 - '@tailwindcss/oxide': 4.1.17 - tailwindcss: 4.1.17 - vite: 7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0) + '@tailwindcss/node': 4.3.2 + '@tailwindcss/oxide': 4.3.2 + tailwindcss: 4.3.2 + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1) - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 optional: true - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.5 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.5 - '@types/crypto-js@4.2.2': {} '@types/dom-chromium-installation-events@101.0.4': {} - '@types/estree@1.0.8': {} + '@types/esrecurse@4.3.1': {} + + '@types/estree@1.0.9': {} '@types/json-schema@7.0.15': {} - '@types/node@25.0.0': + '@types/node@26.1.1': dependencies: - undici-types: 7.16.0 + undici-types: 8.3.0 - '@types/react-dom@19.2.3(@types/react@19.2.7)': + '@types/react-dom@19.2.3(@types/react@19.2.17)': dependencies: - '@types/react': 19.2.7 + '@types/react': 19.2.17 - '@types/react@19.2.7': + '@types/react@19.2.17': dependencies: csstype: 3.2.3 @@ -2785,254 +2286,280 @@ snapshots: '@types/web-app-manifest@1.0.9': {} - '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.64.0(@typescript-eslint/parser@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2))(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.49.0 - eslint: 9.39.1(jiti@2.6.1) - ignore: 7.0.5 + '@typescript-eslint/parser': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) + '@typescript-eslint/scope-manager': 8.64.0 + '@typescript-eslint/type-utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) + '@typescript-eslint/utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) + '@typescript-eslint/visitor-keys': 8.64.0 + eslint: 10.7.0(jiti@2.7.0) + ignore: 7.0.6 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.5.0(typescript@7.0.2) + typescript: 7.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2)': dependencies: - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/scope-manager': 8.64.0 + '@typescript-eslint/types': 8.64.0 + '@typescript-eslint/typescript-estree': 8.64.0(typescript@7.0.2) + '@typescript-eslint/visitor-keys': 8.64.0 debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) - typescript: 5.9.3 + eslint: 10.7.0(jiti@2.7.0) + typescript: 7.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.49.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.64.0(typescript@7.0.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) - '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/tsconfig-utils': 8.64.0(typescript@7.0.2) + '@typescript-eslint/types': 8.64.0 debug: 4.4.3 - typescript: 5.9.3 + typescript: 7.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.49.0': + '@typescript-eslint/scope-manager@8.64.0': dependencies: - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/types': 8.64.0 + '@typescript-eslint/visitor-keys': 8.64.0 - '@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.64.0(typescript@7.0.2)': dependencies: - typescript: 5.9.3 + typescript: 7.0.2 - '@typescript-eslint/type-utils@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2)': dependencies: - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.64.0 + '@typescript-eslint/typescript-estree': 8.64.0(typescript@7.0.2) + '@typescript-eslint/utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 + eslint: 10.7.0(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@7.0.2) + typescript: 7.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.49.0': {} + '@typescript-eslint/types@8.64.0': {} - '@typescript-eslint/typescript-estree@8.49.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.64.0(typescript@7.0.2)': dependencies: - '@typescript-eslint/project-service': 8.49.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/project-service': 8.64.0(typescript@7.0.2) + '@typescript-eslint/tsconfig-utils': 8.64.0(typescript@7.0.2) + '@typescript-eslint/types': 8.64.0 + '@typescript-eslint/visitor-keys': 8.64.0 debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.3 - tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 + minimatch: 10.2.5 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@7.0.2) + typescript: 7.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) - typescript: 5.9.3 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.64.0 + '@typescript-eslint/types': 8.64.0 + '@typescript-eslint/typescript-estree': 8.64.0(typescript@7.0.2) + eslint: 10.7.0(jiti@2.7.0) + typescript: 7.0.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.49.0': + '@typescript-eslint/visitor-keys@8.64.0': dependencies: - '@typescript-eslint/types': 8.49.0 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.64.0 + eslint-visitor-keys: 5.0.1 - '@unrs/resolver-binding-android-arm-eabi@1.11.1': + '@typescript/typescript-aix-ppc64@7.0.2': optional: true - '@unrs/resolver-binding-android-arm64@1.11.1': + '@typescript/typescript-darwin-arm64@7.0.2': optional: true - '@unrs/resolver-binding-darwin-arm64@1.11.1': + '@typescript/typescript-darwin-x64@7.0.2': optional: true - '@unrs/resolver-binding-darwin-x64@1.11.1': + '@typescript/typescript-freebsd-arm64@7.0.2': optional: true - '@unrs/resolver-binding-freebsd-x64@1.11.1': + '@typescript/typescript-freebsd-x64@7.0.2': optional: true - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + '@typescript/typescript-linux-arm64@7.0.2': optional: true - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + '@typescript/typescript-linux-arm@7.0.2': optional: true - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + '@typescript/typescript-linux-loong64@7.0.2': optional: true - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + '@typescript/typescript-linux-mips64el@7.0.2': optional: true - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + '@typescript/typescript-linux-ppc64@7.0.2': optional: true - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + '@typescript/typescript-linux-riscv64@7.0.2': optional: true - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + '@typescript/typescript-linux-s390x@7.0.2': optional: true - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + '@typescript/typescript-linux-x64@7.0.2': optional: true - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + '@typescript/typescript-netbsd-arm64@7.0.2': optional: true - '@unrs/resolver-binding-linux-x64-musl@1.11.1': + '@typescript/typescript-netbsd-x64@7.0.2': optional: true - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - dependencies: - '@napi-rs/wasm-runtime': 0.2.12 + '@typescript/typescript-openbsd-arm64@7.0.2': optional: true - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + '@typescript/typescript-openbsd-x64@7.0.2': optional: true - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + '@typescript/typescript-sunos-x64@7.0.2': optional: true - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + '@typescript/typescript-win32-arm64@7.0.2': optional: true - '@vitejs/plugin-react@5.1.2(vite@7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0))': - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.53 - '@types/babel__core': 7.20.5 - react-refresh: 0.18.0 - vite: 7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0) - transitivePeerDependencies: - - supports-color + '@typescript/typescript-win32-x64@7.0.2': + optional: true - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true - acorn@8.15.0: {} + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true - argparse@2.0.1: {} + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true - autoprefixer@10.4.22(postcss@8.5.6): - dependencies: - browserslist: 4.28.1 - caniuse-lite: 1.0.30001760 - fraction.js: 5.3.4 - normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true - balanced-match@1.0.2: {} + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true - baseline-browser-mapping@2.9.6: {} + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true - bmp-js@0.1.0: {} + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true - braces@3.0.3: - dependencies: - fill-range: 7.1.1 + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': optional: true - browserslist@4.28.1: + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': dependencies: - baseline-browser-mapping: 2.9.6 - caniuse-lite: 1.0.30001760 - electron-to-chromium: 1.5.267 - node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true - buffer-builder@0.2.0: {} + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true - callsites@3.1.0: {} + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true - caniuse-lite@1.0.30001760: {} + '@vitejs/plugin-react@6.0.3(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1) - chalk@4.1.2: + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 + acorn: 8.17.0 - chokidar@4.0.3: + acorn@8.17.0: {} + + ajv@6.15.0: dependencies: - readdirp: 4.1.2 - optional: true + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 - color-convert@2.0.1: + autoprefixer@10.5.3(postcss@8.5.19): dependencies: - color-name: 1.1.4 + browserslist: 4.28.6 + caniuse-lite: 1.0.30001805 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.19 + postcss-value-parser: 4.2.0 - color-name@1.1.4: {} + balanced-match@4.0.4: {} - colorjs.io@0.5.2: {} + baseline-browser-mapping@2.10.43: {} - comment-parser@1.4.1: {} + brace-expansion@5.0.7: + dependencies: + balanced-match: 4.0.4 + + browserslist@4.28.6: + dependencies: + baseline-browser-mapping: 2.10.43 + caniuse-lite: 1.0.30001805 + electron-to-chromium: 1.5.392 + node-releases: 2.0.51 + update-browserslist-db: 1.2.3(browserslist@4.28.6) + + caniuse-lite@1.0.30001805: {} - concat-map@0.0.1: {} + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + optional: true + + colorjs.io@0.5.2: {} - convert-source-map@2.0.0: {} + comment-parser@1.4.7: {} cookie@1.1.1: {} @@ -3046,197 +2573,153 @@ snapshots: csstype@3.2.3: {} - debug@3.2.7: - dependencies: - ms: 2.1.3 - optional: true - debug@4.4.3: dependencies: ms: 2.1.3 deep-is@0.1.4: {} - detect-libc@1.0.3: - optional: true - detect-libc@2.1.2: {} - earcut@3.0.2: {} + earcut@3.2.3: {} - electron-to-chromium@1.5.267: {} + electron-to-chromium@1.5.392: {} - enhanced-resolve@5.18.3: + enhanced-resolve@5.21.6: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.3 - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - - esbuild@0.27.1: + enhanced-resolve@5.24.2: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + esbuild@0.28.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.1 - '@esbuild/android-arm': 0.27.1 - '@esbuild/android-arm64': 0.27.1 - '@esbuild/android-x64': 0.27.1 - '@esbuild/darwin-arm64': 0.27.1 - '@esbuild/darwin-x64': 0.27.1 - '@esbuild/freebsd-arm64': 0.27.1 - '@esbuild/freebsd-x64': 0.27.1 - '@esbuild/linux-arm': 0.27.1 - '@esbuild/linux-arm64': 0.27.1 - '@esbuild/linux-ia32': 0.27.1 - '@esbuild/linux-loong64': 0.27.1 - '@esbuild/linux-mips64el': 0.27.1 - '@esbuild/linux-ppc64': 0.27.1 - '@esbuild/linux-riscv64': 0.27.1 - '@esbuild/linux-s390x': 0.27.1 - '@esbuild/linux-x64': 0.27.1 - '@esbuild/netbsd-arm64': 0.27.1 - '@esbuild/netbsd-x64': 0.27.1 - '@esbuild/openbsd-arm64': 0.27.1 - '@esbuild/openbsd-x64': 0.27.1 - '@esbuild/openharmony-arm64': 0.27.1 - '@esbuild/sunos-x64': 0.27.1 - '@esbuild/win32-arm64': 0.27.1 - '@esbuild/win32-ia32': 0.27.1 - '@esbuild/win32-x64': 0.27.1 + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-compat-utils@0.5.1(eslint@9.39.1(jiti@2.6.1)): + eslint-compat-utils@0.5.1(eslint@10.7.0(jiti@2.7.0)): dependencies: - eslint: 9.39.1(jiti@2.6.1) - semver: 7.7.3 + eslint: 10.7.0(jiti@2.7.0) + semver: 7.8.5 - eslint-import-context@0.1.9(unrs-resolver@1.11.1): + eslint-import-context@0.1.9(unrs-resolver@1.12.2): dependencies: - get-tsconfig: 4.13.0 + get-tsconfig: 4.14.0 stable-hash-x: 0.2.0 optionalDependencies: - unrs-resolver: 1.11.1 - - eslint-import-resolver-node@0.3.9: - dependencies: - debug: 3.2.7 - is-core-module: 2.16.1 - resolve: 1.22.11 - transitivePeerDependencies: - - supports-color - optional: true + unrs-resolver: 1.12.2 - eslint-plugin-es-x@7.8.0(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-es-x@7.8.0(eslint@10.7.0(jiti@2.7.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 - eslint: 9.39.1(jiti@2.6.1) - eslint-compat-utils: 0.5.1(eslint@9.39.1(jiti@2.6.1)) + eslint: 10.7.0(jiti@2.7.0) + eslint-compat-utils: 0.5.1(eslint@10.7.0(jiti@2.7.0)) - eslint-plugin-import-x@4.16.1(@typescript-eslint/utils@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-import-x@4.17.1(@typescript-eslint/utils@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2))(eslint@10.7.0(jiti@2.7.0)): dependencies: - '@typescript-eslint/types': 8.49.0 - comment-parser: 1.4.1 + '@typescript-eslint/types': 8.64.0 + comment-parser: 1.4.7 debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) - eslint-import-context: 0.1.9(unrs-resolver@1.11.1) + eslint: 10.7.0(jiti@2.7.0) + eslint-import-context: 0.1.9(unrs-resolver@1.12.2) is-glob: 4.0.3 - minimatch: 10.1.1 - semver: 7.7.3 + minimatch: 10.2.5 + semver: 7.8.5 stable-hash-x: 0.2.0 - unrs-resolver: 1.11.1 + unrs-resolver: 1.12.2 optionalDependencies: - '@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint-import-resolver-node: 0.3.9 + '@typescript-eslint/utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) transitivePeerDependencies: - supports-color - eslint-plugin-n@17.23.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + eslint-plugin-n@18.2.2(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) - enhanced-resolve: 5.18.3 - eslint: 9.39.1(jiti@2.6.1) - eslint-plugin-es-x: 7.8.0(eslint@9.39.1(jiti@2.6.1)) - get-tsconfig: 4.13.0 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) + enhanced-resolve: 5.24.2 + eslint: 10.7.0(jiti@2.7.0) + eslint-plugin-es-x: 7.8.0(eslint@10.7.0(jiti@2.7.0)) + get-tsconfig: 4.14.0 globals: 15.15.0 globrex: 0.1.2 ignore: 5.3.2 - semver: 7.7.3 - ts-declaration-location: 1.0.7(typescript@5.9.3) - transitivePeerDependencies: - - typescript + semver: 7.8.5 + optionalDependencies: + typescript: 7.0.2 - eslint-plugin-regexp@2.10.0(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-regexp@3.1.1(eslint@10.7.0(jiti@2.7.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 - comment-parser: 1.4.1 - eslint: 9.39.1(jiti@2.6.1) - jsdoc-type-pratt-parser: 4.8.0 + comment-parser: 1.4.7 + eslint: 10.7.0(jiti@2.7.0) + jsdoc-type-pratt-parser: 7.2.0 refa: 0.12.1 regexp-ast-analysis: 0.7.1 scslre: 0.3.0 - eslint-scope@8.4.0: + eslint-scope@9.1.2: dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.2.1: {} + eslint-visitor-keys@5.0.1: {} - eslint@9.39.1(jiti@2.6.1): + eslint@10.7.0(jiti@2.7.0): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.1 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@eslint/config-array': 0.23.5 + '@eslint/config-helpers': 0.6.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.2 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 + '@types/estree': 1.0.9 + ajv: 6.15.0 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 @@ -3246,22 +2729,21 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 10.2.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: - jiti: 2.6.1 + jiti: 2.7.0 transitivePeerDependencies: - supports-color - espree@10.4.0: + espree@11.2.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 5.0.1 - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -3279,19 +2761,14 @@ snapshots: fast-levenshtein@2.0.6: {} - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.5 file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - optional: true - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -3299,22 +2776,17 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 - flatted@3.3.3: {} + flatted@3.4.2: {} fraction.js@5.3.4: {} fsevents@2.3.3: optional: true - function-bind@1.1.2: - optional: true - - gensync@1.0.0-beta.2: {} - - get-tsconfig@4.13.0: + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -3322,11 +2794,9 @@ snapshots: dependencies: is-glob: 4.0.3 - globals@14.0.0: {} - globals@15.15.0: {} - globals@16.5.0: {} + globals@17.7.0: {} globrex@0.1.2: {} @@ -3334,57 +2804,27 @@ snapshots: has-flag@4.0.0: {} - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - optional: true - - idb-keyval@6.2.2: {} - ignore@5.3.2: {} - ignore@7.0.5: {} + ignore@7.0.6: {} - immutable@5.1.4: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 + immutable@5.1.9: {} imurmurhash@0.1.4: {} - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - optional: true - is-extglob@2.1.1: {} is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - is-number@7.0.0: - optional: true - - is-url@1.2.4: {} - isexe@2.0.0: {} - jiti@2.6.1: {} - - js-tokens@4.0.0: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 + jiti@2.7.0: {} jschardet@3.1.4: {} - jsdoc-type-pratt-parser@4.8.0: {} - - jsesc@3.1.0: {} + jsdoc-type-pratt-parser@7.2.0: {} json-buffer@3.0.1: {} @@ -3392,8 +2832,6 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - json5@2.2.3: {} - keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -3403,106 +2841,86 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.30.2: + lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.30.2: + lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.30.2: + lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.30.2: + lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: + lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.30.2: + lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.30.2: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.30.2: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.30.2: + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.30.2: + lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.30.2: + lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - - lit-element@4.2.1: - dependencies: - '@lit-labs/ssr-dom-shim': 1.4.0 - '@lit/reactive-element': 2.1.1 - lit-html: 3.3.1 - - lit-html@3.3.1: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lit-element@4.2.2: + dependencies: + '@lit-labs/ssr-dom-shim': 1.6.0 + '@lit/reactive-element': 2.1.2 + lit-html: 3.3.3 + + lit-html@3.3.3: dependencies: '@types/trusted-types': 2.0.7 - lit@3.3.1: + lit@3.3.3: dependencies: - '@lit/reactive-element': 2.1.1 - lit-element: 4.2.1 - lit-html: 3.3.1 + '@lit/reactive-element': 2.1.2 + lit-element: 4.2.2 + lit-html: 3.3.3 locate-path@6.0.0: dependencies: p-locate: 5.0.0 - lodash.merge@4.6.2: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - optional: true - - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimatch@9.0.5: + minimatch@10.2.5: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 5.0.7 ms@2.1.3: {} - nanoid@3.3.11: {} + nanoid@3.3.16: {} napi-postinstall@0.3.4: {} @@ -3511,15 +2929,7 @@ snapshots: node-addon-api@7.1.1: optional: true - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-releases@2.0.27: {} - - normalize-range@0.1.2: {} - - opencollective-postinstall@2.0.3: {} + node-releases@2.0.51: {} optionator@0.9.4: dependencies: @@ -3538,228 +2948,192 @@ snapshots: dependencies: p-limit: 3.1.0 - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - path-exists@4.0.0: {} path-key@3.1.1: {} - path-parse@1.0.7: - optional: true - picocolors@1.1.1: {} - picomatch@2.3.1: - optional: true - - picomatch@4.0.3: {} + picomatch@4.0.5: {} postcss-value-parser@4.2.0: {} - postcss@8.5.6: + postcss@8.5.19: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.16 picocolors: 1.1.1 source-map-js: 1.2.1 prelude-ls@1.2.1: {} - prettier@3.7.4: {} + prettier@3.9.5: {} punycode@2.3.1: {} - ranui@0.1.10-alpha-27: + ranui@0.2.1-alpha.1: dependencies: - ranuts: 0.1.0-alpha-23 - transitivePeerDependencies: - - encoding + ranuts: 0.2.0-alpha.1 - ranuts@0.1.0-alpha-23: + ranuts@0.2.0-alpha.1: dependencies: - earcut: 3.0.2 + earcut: 3.2.3 jschardet: 3.1.4 magic-string: 0.30.21 - tesseract.js: 6.0.1 - transitivePeerDependencies: - - encoding - react-dom@19.2.1(react@19.2.1): + react-dom@19.2.7(react@19.2.7): dependencies: - react: 19.2.1 + react: 19.2.7 scheduler: 0.27.0 - react-refresh@0.18.0: {} - - react-router-dom@7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-router-dom@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - react-router: 7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-router: 7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) - react-router@7.10.1(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + react-router@7.18.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: cookie: 1.1.1 - react: 19.2.1 + react: 19.2.7 set-cookie-parser: 2.7.2 optionalDependencies: - react-dom: 19.2.1(react@19.2.1) + react-dom: 19.2.7(react@19.2.7) - react@19.2.1: {} + react@19.2.7: {} - readdirp@4.1.2: + readdirp@5.0.0: optional: true refa@0.12.1: dependencies: '@eslint-community/regexpp': 4.12.2 - regenerator-runtime@0.13.11: {} - regexp-ast-analysis@0.7.1: dependencies: '@eslint-community/regexpp': 4.12.2 refa: 0.12.1 - resolve-from@4.0.0: {} - resolve-pkg-maps@1.0.0: {} - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - optional: true - - rollup@4.53.3: + rolldown@1.1.5: dependencies: - '@types/estree': 1.0.8 + '@oxc-project/types': 0.139.0 + '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 - fsevents: 2.3.3 + '@rolldown/binding-android-arm64': 1.1.5 + '@rolldown/binding-darwin-arm64': 1.1.5 + '@rolldown/binding-darwin-x64': 1.1.5 + '@rolldown/binding-freebsd-x64': 1.1.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 + '@rolldown/binding-linux-arm64-gnu': 1.1.5 + '@rolldown/binding-linux-arm64-musl': 1.1.5 + '@rolldown/binding-linux-ppc64-gnu': 1.1.5 + '@rolldown/binding-linux-s390x-gnu': 1.1.5 + '@rolldown/binding-linux-x64-gnu': 1.1.5 + '@rolldown/binding-linux-x64-musl': 1.1.5 + '@rolldown/binding-openharmony-arm64': 1.1.5 + '@rolldown/binding-wasm32-wasi': 1.1.5 + '@rolldown/binding-win32-arm64-msvc': 1.1.5 + '@rolldown/binding-win32-x64-msvc': 1.1.5 rxjs@7.8.2: dependencies: tslib: 2.8.1 - sass-embedded-all-unknown@1.96.0: + sass-embedded-all-unknown@1.100.0: dependencies: - sass: 1.96.0 + sass: 1.100.0 optional: true - sass-embedded-android-arm64@1.96.0: + sass-embedded-android-arm64@1.100.0: optional: true - sass-embedded-android-arm@1.96.0: + sass-embedded-android-arm@1.100.0: optional: true - sass-embedded-android-riscv64@1.96.0: + sass-embedded-android-riscv64@1.100.0: optional: true - sass-embedded-android-x64@1.96.0: + sass-embedded-android-x64@1.100.0: optional: true - sass-embedded-darwin-arm64@1.96.0: + sass-embedded-darwin-arm64@1.100.0: optional: true - sass-embedded-darwin-x64@1.96.0: + sass-embedded-darwin-x64@1.100.0: optional: true - sass-embedded-linux-arm64@1.96.0: + sass-embedded-linux-arm64@1.100.0: optional: true - sass-embedded-linux-arm@1.96.0: + sass-embedded-linux-arm@1.100.0: optional: true - sass-embedded-linux-musl-arm64@1.96.0: + sass-embedded-linux-musl-arm64@1.100.0: optional: true - sass-embedded-linux-musl-arm@1.96.0: + sass-embedded-linux-musl-arm@1.100.0: optional: true - sass-embedded-linux-musl-riscv64@1.96.0: + sass-embedded-linux-musl-riscv64@1.100.0: optional: true - sass-embedded-linux-musl-x64@1.96.0: + sass-embedded-linux-musl-x64@1.100.0: optional: true - sass-embedded-linux-riscv64@1.96.0: + sass-embedded-linux-riscv64@1.100.0: optional: true - sass-embedded-linux-x64@1.96.0: + sass-embedded-linux-x64@1.100.0: optional: true - sass-embedded-unknown-all@1.96.0: + sass-embedded-unknown-all@1.100.0: dependencies: - sass: 1.96.0 + sass: 1.100.0 optional: true - sass-embedded-win32-arm64@1.96.0: + sass-embedded-win32-arm64@1.100.0: optional: true - sass-embedded-win32-x64@1.96.0: + sass-embedded-win32-x64@1.100.0: optional: true - sass-embedded@1.96.0: + sass-embedded@1.100.0: dependencies: - '@bufbuild/protobuf': 2.10.1 - buffer-builder: 0.2.0 + '@bufbuild/protobuf': 2.12.1 colorjs.io: 0.5.2 - immutable: 5.1.4 + immutable: 5.1.9 rxjs: 7.8.2 supports-color: 8.1.1 sync-child-process: 1.0.2 varint: 6.0.0 optionalDependencies: - sass-embedded-all-unknown: 1.96.0 - sass-embedded-android-arm: 1.96.0 - sass-embedded-android-arm64: 1.96.0 - sass-embedded-android-riscv64: 1.96.0 - sass-embedded-android-x64: 1.96.0 - sass-embedded-darwin-arm64: 1.96.0 - sass-embedded-darwin-x64: 1.96.0 - sass-embedded-linux-arm: 1.96.0 - sass-embedded-linux-arm64: 1.96.0 - sass-embedded-linux-musl-arm: 1.96.0 - sass-embedded-linux-musl-arm64: 1.96.0 - sass-embedded-linux-musl-riscv64: 1.96.0 - sass-embedded-linux-musl-x64: 1.96.0 - sass-embedded-linux-riscv64: 1.96.0 - sass-embedded-linux-x64: 1.96.0 - sass-embedded-unknown-all: 1.96.0 - sass-embedded-win32-arm64: 1.96.0 - sass-embedded-win32-x64: 1.96.0 - - sass@1.96.0: - dependencies: - chokidar: 4.0.3 - immutable: 5.1.4 + sass-embedded-all-unknown: 1.100.0 + sass-embedded-android-arm: 1.100.0 + sass-embedded-android-arm64: 1.100.0 + sass-embedded-android-riscv64: 1.100.0 + sass-embedded-android-x64: 1.100.0 + sass-embedded-darwin-arm64: 1.100.0 + sass-embedded-darwin-x64: 1.100.0 + sass-embedded-linux-arm: 1.100.0 + sass-embedded-linux-arm64: 1.100.0 + sass-embedded-linux-musl-arm: 1.100.0 + sass-embedded-linux-musl-arm64: 1.100.0 + sass-embedded-linux-musl-riscv64: 1.100.0 + sass-embedded-linux-musl-x64: 1.100.0 + sass-embedded-linux-riscv64: 1.100.0 + sass-embedded-linux-x64: 1.100.0 + sass-embedded-unknown-all: 1.100.0 + sass-embedded-win32-arm64: 1.100.0 + sass-embedded-win32-x64: 1.100.0 + + sass@1.100.0: + dependencies: + chokidar: 5.0.0 + immutable: 5.1.9 source-map-js: 1.2.1 optionalDependencies: - '@parcel/watcher': 2.5.1 + '@parcel/watcher': 2.5.6 optional: true scheduler@0.27.0: {} @@ -3770,9 +3144,7 @@ snapshots: refa: 0.12.1 regexp-ast-analysis: 0.7.1 - semver@6.3.1: {} - - semver@7.7.3: {} + semver@7.8.5: {} set-cookie-parser@2.7.2: {} @@ -3786,72 +3158,34 @@ snapshots: stable-hash-x@0.2.0: {} - strip-json-comments@3.1.1: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - supports-color@8.1.1: dependencies: has-flag: 4.0.0 - supports-preserve-symlinks-flag@1.0.0: - optional: true - sync-child-process@1.0.2: dependencies: - sync-message-port: 1.1.3 - - sync-message-port@1.1.3: {} - - tailwindcss@4.1.17: {} - - tapable@2.3.0: {} - - tesseract.js-core@6.1.1: {} - - tesseract.js@6.0.1: - dependencies: - bmp-js: 0.1.0 - idb-keyval: 6.2.2 - is-url: 1.2.4 - node-fetch: 2.7.0 - opencollective-postinstall: 2.0.3 - regenerator-runtime: 0.13.11 - tesseract.js-core: 6.1.1 - wasm-feature-detect: 1.8.0 - zlibjs: 0.3.1 - transitivePeerDependencies: - - encoding + sync-message-port: 1.2.0 - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + sync-message-port@1.2.0: {} - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - optional: true + tailwindcss@4.3.2: {} - tr46@0.0.3: {} + tapable@2.3.3: {} - ts-api-utils@2.1.0(typescript@5.9.3): + tinyglobby@0.2.17: dependencies: - typescript: 5.9.3 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 - ts-declaration-location@1.0.7(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@7.0.2): dependencies: - picomatch: 4.0.3 - typescript: 5.9.3 + typescript: 7.0.2 tslib@2.8.1: {} - tsx@4.21.0: + tsx@4.23.1: dependencies: - esbuild: 0.27.1 - get-tsconfig: 4.13.0 + esbuild: 0.28.1 optionalDependencies: fsevents: 2.3.3 @@ -3859,48 +3193,72 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2): dependencies: - '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) - typescript: 5.9.3 + '@typescript-eslint/eslint-plugin': 8.64.0(@typescript-eslint/parser@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2))(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) + '@typescript-eslint/parser': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) + '@typescript-eslint/typescript-estree': 8.64.0(typescript@7.0.2) + '@typescript-eslint/utils': 8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) + eslint: 10.7.0(jiti@2.7.0) + typescript: 7.0.2 transitivePeerDependencies: - supports-color - typescript@5.9.3: {} - - undici-types@7.16.0: {} - - unrs-resolver@1.11.1: + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 + + undici-types@8.3.0: {} + + unrs-resolver@1.12.2: dependencies: napi-postinstall: 0.3.4 optionalDependencies: - '@unrs/resolver-binding-android-arm-eabi': 1.11.1 - '@unrs/resolver-binding-android-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-arm64': 1.11.1 - '@unrs/resolver-binding-darwin-x64': 1.11.1 - '@unrs/resolver-binding-freebsd-x64': 1.11.1 - '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 - '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 - '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 - '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 - '@unrs/resolver-binding-linux-x64-musl': 1.11.1 - '@unrs/resolver-binding-wasm32-wasi': 1.11.1 - '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 - '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 - '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - - update-browserslist-db@1.2.2(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + + update-browserslist-db@1.2.3(browserslist@4.28.6): + dependencies: + browserslist: 4.28.6 escalade: 3.2.0 picocolors: 1.1.1 @@ -3910,31 +3268,21 @@ snapshots: varint@6.0.0: {} - vite@7.2.7(@types/node@25.0.0)(jiti@2.6.1)(lightningcss@1.30.2)(sass-embedded@1.96.0)(sass@1.96.0)(tsx@4.21.0): + vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1): dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.53.3 - tinyglobby: 0.2.15 + lightningcss: 1.32.0 + picomatch: 4.0.5 + postcss: 8.5.19 + rolldown: 1.1.5 + tinyglobby: 0.2.17 optionalDependencies: - '@types/node': 25.0.0 + '@types/node': 26.1.1 + esbuild: 0.28.1 fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - sass: 1.96.0 - sass-embedded: 1.96.0 - tsx: 4.21.0 - - wasm-feature-detect@1.8.0: {} - - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 + jiti: 2.7.0 + sass: 1.100.0 + sass-embedded: 1.100.0 + tsx: 4.23.1 which@2.0.2: dependencies: @@ -3942,8 +3290,4 @@ snapshots: word-wrap@1.2.5: {} - yallist@3.1.1: {} - yocto-queue@0.1.0: {} - - zlibjs@0.3.1: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..1972257 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +allowBuilds: + esbuild: set this to true or false + unrs-resolver: set this to true or false From c986090aff418c9fe070d4ab5194ab8e508a77d4 Mon Sep 17 00:00:00 2001 From: chaxus Date: Thu, 16 Jul 2026 22:41:42 +0800 Subject: [PATCH 02/54] feat: add rule-based txt chapter detection (P1) - lib/chapter/: pattern library, per-line candidates, global validation (family competition, LIS de-noising, min-gap filter) - wire detectChapters into transformTextToExpectedFormat as fallback when no markup exists - remove buggy unused extractChapters/extractRomanChapters/romanToArabic - add vitest with 12 cases (zh/en/roman/enum, TOC noise, fake titles) - drop tsconfig baseUrl (removed in TS7; paths works standalone) Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-plan.md | 12 +- lib/chapter/__tests__/detect.test.ts | 167 ++++++++++++++++++ lib/chapter/candidates.ts | 74 ++++++++ lib/chapter/index.ts | 30 ++++ lib/chapter/patterns.ts | 186 ++++++++++++++++++++ lib/chapter/validate.ts | 148 ++++++++++++++++ lib/transformText.ts | 72 +------- package.json | 4 +- pnpm-lock.yaml | 247 +++++++++++++++++++++++++++ tsconfig.json | 1 - vitest.config.ts | 8 + 11 files changed, 876 insertions(+), 73 deletions(-) create mode 100644 lib/chapter/__tests__/detect.test.ts create mode 100644 lib/chapter/candidates.ts create mode 100644 lib/chapter/index.ts create mode 100644 lib/chapter/patterns.ts create mode 100644 lib/chapter/validate.ts create mode 100644 vitest.config.ts diff --git a/docs/chapter-detection-plan.md b/docs/chapter-detection-plan.md index a5deebf..5997eb6 100644 --- a/docs/chapter-detection-plan.md +++ b/docs/chapter-detection-plan.md @@ -91,12 +91,12 @@ txt 文本 ## 里程碑与顺序 -| 阶段 | 依赖 | 独立价值 | -|------|------|----------| -| P1 规则层 | 无 | 可直接上线,覆盖 ~95% 常规书 | -| P2 推理设施 | 无(与 P1 并行) | 链路验证,为任意 NLP 能力铺路 | -| P3 训练管线 | P1 的 bad case 积累 | 产出模型文件 | -| P4 集成 | P1+P2+P3 | 完整体验 + 数据飞轮 | +| 阶段 | 依赖 | 独立价值 | +| ----------- | ------------------- | ----------------------------- | +| P1 规则层 | 无 | 可直接上线,覆盖 ~95% 常规书 | +| P2 推理设施 | 无(与 P1 并行) | 链路验证,为任意 NLP 能力铺路 | +| P3 训练管线 | P1 的 bad case 积累 | 产出模型文件 | +| P4 集成 | P1+P2+P3 | 完整体验 + 数据飞轮 | **P3 的启动前提是 P1 上线后攒到足量真实 bad case**——如果规则层实际准确率已满足需求, P3/P4 的模型部分可以推迟或取消,P2 的基础设施投入依然保值。 diff --git a/lib/chapter/__tests__/detect.test.ts b/lib/chapter/__tests__/detect.test.ts new file mode 100644 index 0000000..a77c906 --- /dev/null +++ b/lib/chapter/__tests__/detect.test.ts @@ -0,0 +1,167 @@ +import { describe, expect, it } from 'vitest'; +import { detectChapters, parseChineseNumber, parseRomanNumber } from '../index'; + +/** 中文正文填充:短句行,不命中任何标题模式 */ +const filler = (chars: number): string => { + const sentence = '春天的风从山谷里吹过来,带着潮湿的泥土气息,她沿着旧铁轨慢慢往前走。'; + let out = ''; + while (out.length < chars) { + out += sentence + '\n'; + } + return out; +}; + +/** 英文正文填充:行长超过标题上限,直接被行长过滤跳过 */ +const fillerEn = (chars: number): string => { + const sentence = 'The wind was cold and the road stretched far beyond the quiet hills of the north.'; + let out = ''; + while (out.length < chars) { + out += sentence + '\n'; + } + return out; +}; + +describe('detectChapters 中文章节', () => { + it('识别「第X章 标题」并给出正确边界', () => { + const text = [ + filler(300), + '第一章 风雪夜', + filler(400), + '第二章 山路', + filler(400), + '第三章 灯火', + filler(400), + ].join('\n'); + const chapters = detectChapters(text); + expect(chapters.map((chapter) => chapter.title)).toEqual(['第一章 风雪夜', '第二章 山路', '第三章 灯火']); + // 边界成链:每章 end 是下一章 start,最后一章到文本末尾 + expect(chapters[0].end).toBe(chapters[1].start); + expect(chapters[1].end).toBe(chapters[2].start); + expect(chapters[2].end).toBe(text.length); + expect(chapters[0].start).toBe(text.indexOf('第一章')); + }); + + it('以章节词开头的正文短句不会误报', () => { + const noise = '第三章的内容他没看'; + const text = [ + filler(300), + '第一章 风雪夜', + filler(200), + noise, + filler(200), + '第二章 山路', + filler(400), + '第三章 灯火', + filler(400), + ].join('\n'); + const chapters = detectChapters(text); + expect(chapters.map((chapter) => chapter.title)).toEqual(['第一章 风雪夜', '第二章 山路', '第三章 灯火']); + }); + + it('文件开头的目录页输给正文里的真实章节行', () => { + const toc = ['第一章 风雪夜', '第二章 山路', '第三章 灯火', '第四章 归途', '第五章 远方'].join('\n'); + const body = ['第一章 风雪夜', '第二章 山路', '第三章 灯火', '第四章 归途', '第五章 远方'] + .map((title) => `${title}\n${filler(400)}`) + .join('\n'); + const text = `${toc}\n${filler(300)}\n${body}`; + const chapters = detectChapters(text); + expect(chapters).toHaveLength(5); + expect(chapters[0].start).toBe(text.lastIndexOf('第一章 风雪夜')); + }); + + it('序章/番外/后记等特殊章节并入结果', () => { + const text = [ + '序章', + filler(400), + '第一章 起点', + filler(400), + '第二章 转折', + filler(400), + '第三章 结局', + filler(400), + '番外 若干年后', + filler(400), + '后记', + filler(300), + ].join('\n'); + const chapters = detectChapters(text); + expect(chapters.map((chapter) => chapter.title)).toEqual([ + '序章', + '第一章 起点', + '第二章 转折', + '第三章 结局', + '番外 若干年后', + '后记', + ]); + }); + + it('识别「一、」式编号', () => { + const text = [filler(250), '一、初见', filler(400), '二、重逢', filler(400), '三、离别', filler(400)].join('\n'); + const chapters = detectChapters(text); + expect(chapters.map((chapter) => chapter.title)).toEqual(['一、初见', '二、重逢', '三、离别']); + }); +}); + +describe('detectChapters 英文与罗马数字', () => { + it('识别 Chapter N 及数词、罗马编号', () => { + const text = [ + fillerEn(300), + 'Chapter 1: The Beginning', + fillerEn(400), + 'Chapter 2: The Road', + fillerEn(400), + 'Chapter 3: The End', + fillerEn(400), + ].join('\n'); + const chapters = detectChapters(text); + expect(chapters.map((chapter) => chapter.title)).toEqual([ + 'Chapter 1: The Beginning', + 'Chapter 2: The Road', + 'Chapter 3: The End', + ]); + }); + + it('识别罗马数字独立成行', () => { + const text = ['I', fillerEn(400), 'II', fillerEn(400), 'III', fillerEn(400), 'IV', fillerEn(400)].join('\n'); + const chapters = detectChapters(text); + expect(chapters.map((chapter) => chapter.title)).toEqual(['I', 'II', 'III', 'IV']); + }); +}); + +describe('detectChapters 抗噪与兜底', () => { + it('无任何章节格式时返回空数组', () => { + expect(detectChapters(filler(2000))).toEqual([]); + }); + + it('紧凑的编号列表不会被当成章节', () => { + const list = ['1. 苹果', '2. 香蕉', '3. 橙子', '4. 葡萄'].join('\n'); + const text = `${filler(400)}\n${list}\n${filler(400)}`; + expect(detectChapters(text)).toEqual([]); + }); + + it('章节只挤在文本开头的极小前缀时判定失败', () => { + const text = ['第一章 开头', filler(220), '第二章 然后', filler(220), filler(5000)].join('\n'); + expect(detectChapters(text)).toEqual([]); + }); +}); + +describe('数字解析', () => { + it('中文数字', () => { + expect(parseChineseNumber('十五')).toBe(15); + expect(parseChineseNumber('二十三')).toBe(23); + expect(parseChineseNumber('一百零三')).toBe(103); + expect(parseChineseNumber('两百')).toBe(200); + expect(parseChineseNumber('一千零一')).toBe(1001); + expect(parseChineseNumber('三万')).toBe(30000); + expect(parseChineseNumber('12')).toBe(12); + expect(parseChineseNumber('12')).toBe(12); + expect(parseChineseNumber('abc')).toBeNull(); + }); + + it('罗马数字', () => { + expect(parseRomanNumber('IV')).toBe(4); + expect(parseRomanNumber('XIX')).toBe(19); + expect(parseRomanNumber('iv')).toBe(4); + expect(parseRomanNumber('ABC')).toBeNull(); + }); +}); diff --git a/lib/chapter/candidates.ts b/lib/chapter/candidates.ts new file mode 100644 index 0000000..974bd98 --- /dev/null +++ b/lib/chapter/candidates.ts @@ -0,0 +1,74 @@ +import type { PatternFamily } from './patterns'; +import { PATTERN_FAMILIES } from './patterns'; + +/** 标题行的最大长度(去除首尾空白后),超过的行直接跳过,不做正则匹配 */ +export const MAX_TITLE_LENGTH = 50; + +export interface Candidate { + familyId: string; + special: boolean; + /** 标题文本(整行去除首尾空白) */ + title: string; + /** 行首在原文中的偏移 */ + start: number; + /** 行号(0 起) */ + lineIndex: number; + /** 从编号模式中解析出的序号,无编号家族为 null */ + seq: number | null; +} + +/** + * 按行扫描文本,生成所有家族的候选标题行。 + * 一行可能同时命中多个家族(如「一、」同时是 cn-enum),全部记录,由全局验证挑选胜出家族。 + * 文本应已将换行统一为 \n(transformText 的调用链保证了这一点), + * 为稳妥起见此处仍兼容残留的 \r。 + */ +export const collectCandidates = (text: string): Candidate[] => { + const candidates: Candidate[] = []; + let offset = 0; + let lineIndex = 0; + while (offset <= text.length) { + const newlineIndex = text.indexOf('\n', offset); + const lineEnd = newlineIndex === -1 ? text.length : newlineIndex; + const rawLine = text.slice(offset, lineEnd); + const line = rawLine.replace(/\r/g, '').trim(); + if (line.length > 0 && line.length <= MAX_TITLE_LENGTH) { + matchLine(line, offset, lineIndex, candidates); + } + if (newlineIndex === -1) { + break; + } + offset = newlineIndex + 1; + lineIndex++; + } + return candidates; +}; + +const matchLine = (line: string, start: number, lineIndex: number, candidates: Candidate[]): void => { + for (const family of PATTERN_FAMILIES) { + const match = line.match(family.regex); + if (!match) { + continue; + } + const seq = resolveSeq(family, match); + // 编号家族解析不出编号说明匹配质量存疑(如非法罗马数字组合),丢弃 + if (family.parseSeq && seq === null) { + continue; + } + candidates.push({ + familyId: family.id, + special: family.special === true, + title: line, + start, + lineIndex, + seq, + }); + } +}; + +const resolveSeq = (family: PatternFamily, match: RegExpMatchArray): number | null => { + if (!family.parseSeq) { + return null; + } + return family.parseSeq(match); +}; diff --git a/lib/chapter/index.ts b/lib/chapter/index.ts new file mode 100644 index 0000000..2bbc6f0 --- /dev/null +++ b/lib/chapter/index.ts @@ -0,0 +1,30 @@ +import { collectCandidates } from './candidates'; +import { selectChapters } from './validate'; + +export interface DetectedChapter { + title: string; + start: number; + end: number; +} + +/** + * @description: 从无固定格式的 txt 文本中识别章节边界并提取标题。 + * 流程:按行生成候选(多语言模式库)→ 全局验证(编号递增序列 + 间距过滤 + 家族竞争)。 + * 无法可靠识别时返回空数组,调用方应走兜底逻辑(整本一章或按空行分块)。 + * @param {string} text 已将换行统一为 \n 的全文 + * @return {DetectedChapter[]} 按出现顺序排列的章节,end 为下一章起点或文本末尾 + */ +export const detectChapters = (text: string): DetectedChapter[] => { + const candidates = collectCandidates(text); + const selected = selectChapters(candidates, text.length); + return selected.map((chapter, index) => ({ + title: chapter.title, + start: chapter.start, + end: selected[index + 1]?.start ?? text.length, + })); +}; + +export { collectCandidates } from './candidates'; +export type { Candidate } from './candidates'; +export { selectChapters, MIN_CHAPTER_GAP } from './validate'; +export { parseChineseNumber, parseRomanNumber, PATTERN_FAMILIES } from './patterns'; diff --git a/lib/chapter/patterns.ts b/lib/chapter/patterns.ts new file mode 100644 index 0000000..344ebc6 --- /dev/null +++ b/lib/chapter/patterns.ts @@ -0,0 +1,186 @@ +/** + * 章节标题模式库。 + * 每个 PatternFamily 描述一类标题格式,regex 作用于「去除首尾空白后的单行」。 + * numbered 家族通过 parseSeq 提取编号,供全局验证做递增序列检查; + * unnumbered 家族(特殊章节、括号标题)只能靠数量与间距验证,优先级更低。 + */ + +export interface PatternFamily { + id: string; + regex: RegExp; + /** 从 regex 匹配结果中解析章节编号,无编号家族不提供 */ + parseSeq?: (match: RegExpMatchArray) => number | null; + /** 特殊章节(序章/番外/后记等),不参与家族竞争,仅并入胜出家族 */ + special?: boolean; +} + +const CN_DIGITS: Record = { + 零: 0, + 〇: 0, + 一: 1, + 二: 2, + 两: 2, + 三: 3, + 四: 4, + 五: 5, + 六: 6, + 七: 7, + 八: 8, + 九: 9, +}; + +const CN_UNITS: Record = { + 十: 10, + 百: 100, + 千: 1000, +}; + +/** 全角数字转半角 */ +const toHalfWidth = (value: string): string => { + return value.replace(/[0-9]/g, (char) => String.fromCharCode(char.charCodeAt(0) - 0xfee0)); +}; + +/** + * 中文数字转阿拉伯数字,支持「十五」「二十三」「一百零三」「一千零一」「三万」等。 + * 混入无法识别的字符时返回 null。 + */ +export const parseChineseNumber = (value: string): number | null => { + const text = toHalfWidth(value.trim()); + if (/^\d+$/.test(text)) { + return Number.parseInt(text, 10); + } + let result = 0; + let section = 0; + let current = 0; + for (const char of text) { + if (CN_DIGITS[char] !== undefined) { + current = CN_DIGITS[char]; + } else if (CN_UNITS[char] !== undefined) { + // 「十五」的「十」前面没有数字,按 1 处理 + section += (current || (char === '十' ? 1 : 0)) * CN_UNITS[char]; + current = 0; + } else if (char === '万' || char === '萬') { + result = (result + section + current) * 10000; + section = 0; + current = 0; + } else { + return null; + } + } + return result + section + current; +}; + +const ROMAN_VALUES: Record = { + I: 1, + V: 5, + X: 10, + L: 50, + C: 100, + D: 500, + M: 1000, +}; + +/** 罗马数字转阿拉伯数字,非法输入返回 null */ +export const parseRomanNumber = (value: string): number | null => { + const text = value.trim().toUpperCase(); + if (!/^[IVXLCDM]+$/.test(text)) { + return null; + } + let result = 0; + for (let i = 0; i < text.length; i++) { + const current = ROMAN_VALUES[text[i]]; + const next = ROMAN_VALUES[text[i + 1]]; + if (next && current < next) { + result -= current; + } else { + result += current; + } + } + return result; +}; + +const EN_NUMBER_WORDS: Record = { + one: 1, + two: 2, + three: 3, + four: 4, + five: 5, + six: 6, + seven: 7, + eight: 8, + nine: 9, + ten: 10, + eleven: 11, + twelve: 12, + thirteen: 13, + fourteen: 14, + fifteen: 15, + sixteen: 16, + seventeen: 17, + eighteen: 18, + nineteen: 19, + twenty: 20, +}; + +/** 英文序号:阿拉伯数字 / 罗马数字 / 英文数词 */ +const parseEnglishSeq = (value: string): number | null => { + const text = value.trim().toLowerCase(); + if (/^\d+$/.test(text)) { + return Number.parseInt(text, 10); + } + if (EN_NUMBER_WORDS[text] !== undefined) { + return EN_NUMBER_WORDS[text]; + } + return parseRomanNumber(text); +}; + +/** + * 模式说明: + * - cn-chapter:「第X章 标题」。编号后必须是分隔符或行尾, + * 避免「第三章的内容他没看」这类以章节词开头的正文短句误报。 + * - en-chapter:「Chapter 1: Title」「PART IV」等。 + * - cn-enum / num-enum:「一、标题」「1. 标题」。num-enum 噪声较大(易命中列表), + * 依赖全局验证的序列与间距检查兜底。 + * - roman-line:罗马数字独立成行(仅大写,降低误报)。 + * - cn-special:序章/楔子/番外/后记等无编号特殊章节。 + * - bracket:「【标题】」,无编号,仅在没有任何 numbered 家族胜出时启用。 + */ +export const PATTERN_FAMILIES: PatternFamily[] = [ + { + id: 'cn-chapter', + regex: + /^第\s*([0-90-9一二两三四五六七八九十百千万萬零〇]{1,12})\s*[章节節卷巻回部集话話篇幕册冊](?:[::..、\-—\s].{0,40})?$/, + parseSeq: (match) => parseChineseNumber(match[1]), + }, + { + id: 'en-chapter', + regex: + /^(?:chapter|section|part|book|act)\s+(\d{1,4}|[ivxlcdm]{1,7}|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)\b(?:[::..\-—\s].{0,50})?$/i, + parseSeq: (match) => parseEnglishSeq(match[1]), + }, + { + id: 'cn-enum', + regex: /^([一二两三四五六七八九十百千]{1,8})[、..::]\s*\S.{0,40}$/, + parseSeq: (match) => parseChineseNumber(match[1]), + }, + { + id: 'num-enum', + regex: /^([0-90-9]{1,4})[、..::]\s*\S.{0,40}$/, + parseSeq: (match) => Number.parseInt(toHalfWidth(match[1]), 10), + }, + { + id: 'roman-line', + regex: /^([IVXLCDM]{1,7})(?:[..::\s].{0,40})?$/, + parseSeq: (match) => parseRomanNumber(match[1]), + }, + { + id: 'cn-special', + regex: + /^(?:序章|序言|自序|代序|楔子|引子|前言|导读|導讀|后记|後記|尾声|尾聲|终章|終章|完本感言|作品相关|内容简介|內容簡介|番外(?:[::..、\s].{0,30}|[一二三四五六七八九十0-9]{0,3})?)$/, + special: true, + }, + { + id: 'bracket', + regex: /^[【[]\s*(.{1,30}?)\s*[】\]]$/, + }, +]; diff --git a/lib/chapter/validate.ts b/lib/chapter/validate.ts new file mode 100644 index 0000000..0873224 --- /dev/null +++ b/lib/chapter/validate.ts @@ -0,0 +1,148 @@ +import type { Candidate } from './candidates'; + +/** 相邻章节起点的最小间距(字符数),小于该值的候选视为误报(列表、正文引用等) */ +export const MIN_CHAPTER_GAP = 200; + +/** 家族权重:模式本身精度越高权重越大,噪声大的家族需要更多成员才能胜出 */ +const FAMILY_WEIGHTS: Record = { + 'cn-chapter': 1, + 'en-chapter': 1, + 'cn-enum': 0.9, + 'roman-line': 0.8, + 'num-enum': 0.7, + bracket: 0.5, +}; + +export interface ValidatedChapter { + title: string; + start: number; +} + +interface FamilyResult { + familyId: string; + kept: Candidate[]; + score: number; +} + +/** + * 全局验证:按家族分组竞争,编号家族用「最长递增子序列 + 间距过滤」剔除误报, + * 选得分最高的家族作为主模式,再把特殊章节(序章/番外/后记)并入结果。 + * 没有任何家族胜出时返回空数组,由调用方走兜底逻辑。 + */ +export const selectChapters = (candidates: Candidate[], textLength: number): ValidatedChapter[] => { + const specials = candidates.filter((item) => item.special); + const regulars = candidates.filter((item) => !item.special); + + const groups = new Map(); + for (const candidate of regulars) { + const group = groups.get(candidate.familyId); + if (group) { + group.push(candidate); + } else { + groups.set(candidate.familyId, [candidate]); + } + } + + let best: FamilyResult | null = null; + for (const [familyId, group] of groups) { + const result = evaluateFamily(familyId, group); + if (result && (!best || result.score > best.score)) { + best = result; + } + } + + const accepted = best ? [...best.kept] : []; + mergeSpecials(accepted, specials); + + if (accepted.length < 2) { + return []; + } + // 结果不应挤在文本的极小前缀里(如仅命中开头的目录页),要求覆盖到文本中段 + const last = accepted[accepted.length - 1]; + if (textLength > 0 && last.start < textLength * 0.3) { + return []; + } + return accepted.map((item) => ({ title: item.title, start: item.start })); +}; + +const evaluateFamily = (familyId: string, group: Candidate[]): FamilyResult | null => { + const sorted = [...group].sort((a, b) => a.start - b.start); + const numbered = sorted.every((item) => item.seq !== null); + // 先做间距过滤再找递增序列:目录页的密集条目会被间距过滤压缩掉, + // 不会先占住递增序列再被间距过滤清空、拖垮整个家族 + const spaced = filterByGap(sorted); + const kept = numbered ? longestIncreasingRun(spaced) : spaced; + const minCount = numbered ? 2 : 3; + if (kept.length < minCount) { + return null; + } + const contiguity = numbered ? contiguityScore(kept) : 0; + const weight = FAMILY_WEIGHTS[familyId] ?? 0.5; + const score = kept.length * (0.6 + 0.4 * contiguity) * weight; + return { familyId, kept, score }; +}; + +/** + * 最长严格递增子序列(按 seq),保留数量最多的自洽编号序列,剔除正文引用等离群点。 + * 长度相同时偏向位置靠后的前驱:文件开头残留的目录条目会输给正文里的真实章节行。 + */ +const longestIncreasingRun = (sorted: Candidate[]): Candidate[] => { + const n = sorted.length; + const lengths = new Array(n).fill(1); + const prev = new Array(n).fill(-1); + let bestEnd = 0; + for (let i = 1; i < n; i++) { + for (let j = 0; j < i; j++) { + if ((sorted[j].seq as number) < (sorted[i].seq as number) && lengths[j] + 1 >= lengths[i]) { + lengths[i] = lengths[j] + 1; + prev[i] = j; + } + } + if (lengths[i] > lengths[bestEnd]) { + bestEnd = i; + } + } + const result: Candidate[] = []; + for (let i = bestEnd; i !== -1; i = prev[i]) { + result.push(sorted[i]); + } + return result.reverse(); +}; + +/** 相邻候选间距过滤:与上一个保留项距离过近的丢弃 */ +const filterByGap = (sorted: Candidate[]): Candidate[] => { + const kept: Candidate[] = []; + for (const candidate of sorted) { + const last = kept[kept.length - 1]; + if (!last || candidate.start - last.start >= MIN_CHAPTER_GAP) { + kept.push(candidate); + } + } + return kept; +}; + +/** 相邻编号恰好 +1 的比例,衡量序列连贯性 */ +const contiguityScore = (kept: Candidate[]): number => { + if (kept.length < 2) { + return 0; + } + let adjacent = 0; + for (let i = 1; i < kept.length; i++) { + if ((kept[i].seq as number) - (kept[i - 1].seq as number) === 1) { + adjacent++; + } + } + return adjacent / (kept.length - 1); +}; + +/** 把特殊章节并入结果:与已有章节起点距离足够远才接受,避免正文中孤立出现的「楔子」等词误入 */ +const mergeSpecials = (accepted: Candidate[], specials: Candidate[]): void => { + const sortedSpecials = [...specials].sort((a, b) => a.start - b.start); + for (const special of sortedSpecials) { + const farEnough = accepted.every((item) => Math.abs(item.start - special.start) >= MIN_CHAPTER_GAP); + if (farEnough) { + accepted.push(special); + } + } + accepted.sort((a, b) => a.start - b.start); +}; diff --git a/lib/transformText.ts b/lib/transformText.ts index a131ecd..b43af67 100644 --- a/lib/transformText.ts +++ b/lib/transformText.ts @@ -1,5 +1,6 @@ import jschardet from 'jschardet'; import { Locales, t } from '@/locales'; +import { detectChapters } from '@/lib/chapter'; export interface TransformText { encoding: string; @@ -300,16 +301,6 @@ export const pagingText = (content: string, container: HTMLElement): PagingTextR }; }; -export const extractChapters = (text: string): { title: string; startIndex: number }[] => { - const chapterRegex = /(?:第 [一二三四五六七八九十百千万]+章|Chapter\s+\d+|CHAPTER\s+\d+|第\d+ 章)\s*.+/g; - const chapters = []; - let match; - while ((match = chapterRegex.exec(text)) != null) { - chapters.push({ title: match[0], startIndex: match.index }); - } - return chapters; -}; - export interface ChapterItem { title: string; start: number; @@ -317,58 +308,6 @@ export interface ChapterItem { pageNum?: number; } -export const extractRomanChapters = (text: string): ChapterItem[] => { - const romanRegex = /(?:\s|^)(I{1,3}|IV|V|VI|VII|VIII|IX|X|XI|XII|XIII|XIV|XV|XVI|XVII|XVIII|XIX|XX)(?:\s|$)/g; - const chapters: ChapterItem[] = []; - let match; - while ((match = romanRegex.exec(text)) != null) { - chapters.push({ title: match[1], start: match.index }); - } - chapters.forEach((chapter, index) => { - const nextChapter = chapters[index + 1]; - chapter.end = nextChapter ? nextChapter.start : text.length; - }); - return chapters; -}; -/** - * @description: 罗马数字转阿拉伯数字 - * @param {string} roman - * @return {number} - */ -export const romanToArabic = (roman: string): number => { - const romanNumeralMap: Record = { - I: 1, - IV: 4, - V: 5, - IX: 9, - X: 10, - XL: 40, - L: 50, - XC: 90, - C: 100, - CD: 400, - D: 500, - CM: 900, - M: 1000, - }; - - let arabic = 0; - let i = 0; - - while (i < roman.length) { - const twoChar = roman[i] + (roman[i + 1] || ''); - if (romanNumeralMap[twoChar]) { - arabic += romanNumeralMap[twoChar]; - i += 2; - } else { - arabic += romanNumeralMap[roman[i]]; - i += 1; - } - } - - return arabic; -}; - export const toString = (value: unknown): string => { return value == null ? '' : String(value); }; @@ -427,13 +366,16 @@ export const transformTextToExpectedFormat = ({ }): TextSyntaxTree => { // 1. 过滤空格换行 const text = arrayBufferToString(content).replace(/(?:\r\n|\r|\n)+/g, '\n') || ''; - // 2. 提取章节标题 - const extractedChapters = extractCaptionTitleChapters(text); + // 2. 提取章节标题:优先 标注,无标注的原始 txt 走自动识别 + let extractedChapters: ChapterItem[] = extractCaptionTitleChapters(text); + if (extractedChapters.length === 0) { + extractedChapters = detectChapters(text); + } // 3. 把文本按章节划分 const sections: Section[] = []; extractedChapters.forEach((item, index) => { const { start, end, title } = item; - if (index === 0) { + if (index === 0 && start > 0) { const section = text.slice(0, start); sections.push({ title: t('preface'), section }); } diff --git a/package.json b/package.json index fff2844..f05608f 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:server": "vite build --outDir dist/server --ssr ./views/server.tsx", "build": "sh ./bin/build.sh", "tsc": "tsc --noEmit", + "test": "vitest run", "format": "prettier --write .", "lint": "eslint --cache ." }, @@ -47,7 +48,8 @@ "tsx": "^4.23.1", "typescript": "^7.0.2", "typescript-eslint": "^8.64.0", - "vite": "^8.1.4" + "vite": "^8.1.4", + "vitest": "^4.1.10" }, "dependencies": { "@khmyznikov/pwa-install": "^0.6.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ac4a8d..bd5cfb9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,6 +108,9 @@ importers: vite: specifier: ^8.1.4 version: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1) + vitest: + specifier: ^4.1.10 + version: 4.1.10(@types/node@26.1.1)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1)) packages: @@ -581,6 +584,9 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tailwindcss/node@4.3.2': resolution: {integrity: sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==} @@ -681,9 +687,15 @@ packages: '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + '@types/crypto-js@4.2.2': resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/dom-chromium-installation-events@101.0.4': resolution: {integrity: sha512-jV4HXmW5D18bpndzAPF1REGE5xagQqrAexHgX9WoWIPpNaaHtsHQgu5uFbL2z0NIc9fOD0TIC1TRpJhYA1OPxw==} @@ -1025,6 +1037,35 @@ packages: babel-plugin-react-compiler: optional: true + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} + + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1038,6 +1079,10 @@ packages: ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + autoprefixer@10.5.3: resolution: {integrity: sha512-bJRzflk8GgE4JX+iZNEwz9f9p460NCHnU7bd+CZ9vIjIlZuTkt6F3WSl2oNO8StZBFx17nLEsiQ6H2wcZiY7nA==} engines: {node: ^10 || ^12 || >=14} @@ -1066,6 +1111,10 @@ packages: caniuse-lite@1.0.30001805: resolution: {integrity: sha512-52noaS3DubycKSXaU30TwPGIp+POyQSUVa5jBEq3vkRkY0kjyb3LQgvhU6WGyCcyXqVLWO0Cw0Q6BSdD0kUfVA==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + chokidar@5.0.0: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} @@ -1077,6 +1126,9 @@ packages: resolution: {integrity: sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==} engines: {node: '>= 12.0.0'} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@1.1.1: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} @@ -1121,6 +1173,9 @@ packages: resolution: {integrity: sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw==} engines: {node: '>=10.13.0'} + es-module-lexer@2.3.1: + resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} + esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} @@ -1225,10 +1280,17 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1466,6 +1528,10 @@ packages: resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} engines: {node: '>=18'} + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1486,6 +1552,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1715,6 +1784,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -1723,6 +1795,12 @@ packages: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} @@ -1742,10 +1820,21 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -1837,11 +1926,57 @@ packages: yaml: optional: true + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -2180,6 +2315,8 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@standard-schema/spec@1.1.0': {} + '@tailwindcss/node@4.3.2': dependencies: '@jridgewell/remapping': 2.3.5 @@ -2260,8 +2397,15 @@ snapshots: tslib: 2.8.1 optional: true + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + '@types/crypto-js@4.2.2': {} + '@types/deep-eql@4.0.2': {} + '@types/dom-chromium-installation-events@101.0.4': {} '@types/esrecurse@4.3.1': {} @@ -2512,6 +2656,47 @@ snapshots: '@rolldown/pluginutils': 1.0.1 vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1) + '@vitest/expect@4.1.10': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.10(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1))': + dependencies: + '@vitest/spy': 4.1.10 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1) + + '@vitest/pretty-format@4.1.10': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.10': + dependencies: + '@vitest/utils': 4.1.10 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.10': + dependencies: + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.10': {} + + '@vitest/utils@4.1.10': + dependencies: + '@vitest/pretty-format': 4.1.10 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: acorn: 8.17.0 @@ -2525,6 +2710,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + assertion-error@2.0.1: {} + autoprefixer@10.5.3(postcss@8.5.19): dependencies: browserslist: 4.28.6 @@ -2552,6 +2739,8 @@ snapshots: caniuse-lite@1.0.30001805: {} + chai@6.2.2: {} + chokidar@5.0.0: dependencies: readdirp: 5.0.0 @@ -2561,6 +2750,8 @@ snapshots: comment-parser@1.4.7: {} + convert-source-map@2.0.0: {} + cookie@1.1.1: {} cross-spawn@7.0.6: @@ -2595,6 +2786,8 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 + es-module-lexer@2.3.1: {} + esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -2753,8 +2946,14 @@ snapshots: estraverse@5.3.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + esutils@2.0.3: {} + expect-type@1.4.0: {} + fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} @@ -2931,6 +3130,8 @@ snapshots: node-releases@2.0.51: {} + obug@2.1.3: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2952,6 +3153,8 @@ snapshots: path-key@3.1.1: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@4.0.5: {} @@ -3154,10 +3357,16 @@ snapshots: shebang-regex@3.0.0: {} + siginfo@2.0.0: {} + source-map-js@1.2.1: {} stable-hash-x@0.2.0: {} + stackback@0.0.2: {} + + std-env@4.2.0: {} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 @@ -3172,11 +3381,17 @@ snapshots: tapable@2.3.3: {} + tinybench@2.9.0: {} + + tinyexec@1.2.4: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 + tinyrainbow@3.1.0: {} + ts-api-utils@2.5.0(typescript@7.0.2): dependencies: typescript: 7.0.2 @@ -3284,10 +3499,42 @@ snapshots: sass-embedded: 1.100.0 tsx: 4.23.1 + vitest@4.1.10(@types/node@26.1.1)(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1)): + dependencies: + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.1 + expect-type: 1.4.0 + magic-string: 0.30.21 + obug: 2.1.3 + pathe: 2.0.3 + picomatch: 4.0.5 + std-env: 4.2.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.1.4(@types/node@26.1.1)(esbuild@0.28.1)(jiti@2.7.0)(sass-embedded@1.100.0)(sass@1.100.0)(tsx@4.23.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 26.1.1 + transitivePeerDependencies: + - msw + which@2.0.2: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} yocto-queue@0.1.0: {} diff --git a/tsconfig.json b/tsconfig.json index cb7d8b8..c586daf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,6 @@ "noImplicitAny": true, "useUnknownInCatchVariables": false, "inlineSourceMap": true, - "baseUrl": ".", "experimentalDecorators": true, "jsx": "react-jsx", "paths": { diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..0f7e42d --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['**/*.test.ts'], + exclude: ['**/node_modules/**', '**/dist/**', 'public/**'], + }, +}); From 10f8f4a4861d2648ad8d2081cc671e9584dfc2b4 Mon Sep 17 00:00:00 2001 From: chaxus Date: Thu, 16 Jul 2026 22:56:39 +0800 Subject: [PATCH 03/54] feat: add browser NLP inference infrastructure (P2) - workers/nlpWorker.ts: transformers.js pipeline in a module worker, WebGPU-first with WASM fallback, forceable device, progress relay - lib/nlp/: shared message protocol, output normalization/score mapping, ChapterClassifier client (lazy worker, promise-based API) - choose @huggingface/transformers over raw onnxruntime-web: bundled SentencePiece tokenizer, Cache API model caching, progress callbacks - fix pnpm-workspace.yaml allowBuilds placeholders that broke pnpm install - verified in Chrome: download -> WebGPU/WASM inference -> cache -> ~600ms warm reload with a tiny placeholder model (iOS device test pending) Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-plan.md | 22 +- lib/nlp/__tests__/nlp.test.ts | 123 +++++++ lib/nlp/index.ts | 147 +++++++++ lib/nlp/protocol.ts | 78 +++++ lib/nlp/score.ts | 24 ++ package.json | 1 + pnpm-lock.yaml | 571 +++++++++++++++++++++++++++++++++ pnpm-workspace.yaml | 11 +- workers/nlpWorker.ts | 112 +++++++ 9 files changed, 1077 insertions(+), 12 deletions(-) create mode 100644 lib/nlp/__tests__/nlp.test.ts create mode 100644 lib/nlp/index.ts create mode 100644 lib/nlp/protocol.ts create mode 100644 lib/nlp/score.ts create mode 100644 workers/nlpWorker.ts diff --git a/docs/chapter-detection-plan.md b/docs/chapter-detection-plan.md index 5997eb6..e7bab0d 100644 --- a/docs/chapter-detection-plan.md +++ b/docs/chapter-detection-plan.md @@ -26,7 +26,7 @@ txt 文本 关键原则:**模型只替换/增强第 1 层**。第 2 层全局验证是精度的真正来源且语言无关, 无论模型是否启用都必须经过。 -## Phase 1 — 规则层(可独立上线) +## Phase 1 — 规则层(可独立上线)✅ 已完成(2026-07-16,c986090) 新增 `lib/chapter/` 模块: @@ -52,19 +52,21 @@ txt 文本 **验收**:对 fixtures 集合章节边界准确率 ≥ 95%,无网络依赖,可直接合入主干上线。 -## Phase 2 — 浏览器推理基础设施(模型无关,可先用占位模型打通) +## Phase 2 — 浏览器推理基础设施(模型无关)✅ 基本完成(2026-07-16) -- 依赖:`onnxruntime-web`(或 `@huggingface/transformers`,二选一,选前者更可控体积) -- 新增 `workers/nlpWorker.ts`: - - 模型下载(带进度回调)→ OPFS 缓存(Cache API 兜底),版本化文件名支持热更新 - - Execution provider:WebGPU 优先,WASM SIMD + threads 兜底 - - 批量推理 API:`classifyLines(lines: string[]): Promise`(返回标题概率) +- 依赖:**选定 `@huggingface/transformers`**(放弃裸 onnxruntime-web:mDeBERTa 需要 + SentencePiece 分词器,transformers.js 内置且自带 Cache API 缓存与进度回调,省掉整个手写层) +- `workers/nlpWorker.ts`:operationId 关联的消息协议(与 dbWorker 风格一致), + WebGPU 优先 / WASM 兜底 / `device` 参数可强制指定,模型走 Cache API(`transformers-cache`) +- `lib/nlp/`:protocol.ts(双端共享类型)、score.ts(输出归一化与标题概率映射)、 + index.ts(`ChapterClassifier` 客户端封装,懒建 worker,promise 化 API) - 加载策略:**懒加载**。规则层置信度高时完全不下载模型;置信度低(无主模式家族/序列断裂多) - 或用户手动触发「增强解析」时才拉取 + 或用户手动触发「增强解析」时才拉取(P4 接线) - 移动端:UA/内存探测,iOS 上默认只用规则层或提供裁剪版模型(见 Phase 3) -**验收**:占位模型(任意 HF 上现成的 deberta-v2 ONNX)在 worker 内完成加载→缓存→批量推理→ -离线二次加载全链路,桌面 Chrome/Safari + iOS Safari 真机通过。 +**验收结果**:占位模型(Xenova/tiny-random-RoFormerForSequenceClassification)在 +桌面 Chrome 通过全链路:下载(149 个进度事件)→ WebGPU 推理 → 强制 WASM 推理 → +Cache API 持久化 → 新 worker 二次加载 ~600ms。**待办:iOS Safari 真机验证**。 ## Phase 3 — 训练管线(仓库外 Python,产物回流) diff --git a/lib/nlp/__tests__/nlp.test.ts b/lib/nlp/__tests__/nlp.test.ts new file mode 100644 index 0000000..089cf09 --- /dev/null +++ b/lib/nlp/__tests__/nlp.test.ts @@ -0,0 +1,123 @@ +import { describe, expect, it, vi } from 'vitest'; +import { ChapterClassifier } from '../index'; +import type { NlpRequest, NlpResponse } from '../protocol'; +import { normalizeClassifierOutput, toTitleScores } from '../score'; + +describe('score 映射', () => { + it('按正类标签取概率,缺失标签按 0 处理', () => { + const scores = [ + [ + { label: 'LABEL_0', score: 0.3 }, + { label: 'LABEL_1', score: 0.7 }, + ], + [{ label: 'LABEL_0', score: 0.9 }], + ]; + expect(toTitleScores(scores, 'LABEL_1')).toEqual([0.7, 0]); + }); + + it('归一化分类器输出:单行扁平输出包成一行', () => { + const flat = [ + { label: 'LABEL_0', score: 0.2 }, + { label: 'LABEL_1', score: 0.8 }, + ]; + expect(normalizeClassifierOutput(flat, 1)).toEqual([flat]); + }); + + it('归一化分类器输出:多行时逐行包装非数组项', () => { + const mixed = [{ label: 'LABEL_1', score: 0.6 }, [{ label: 'LABEL_1', score: 0.4 }]]; + expect(normalizeClassifierOutput(mixed, 2)).toEqual([ + [{ label: 'LABEL_1', score: 0.6 }], + [{ label: 'LABEL_1', score: 0.4 }], + ]); + }); + + it('归一化分类器输出:非数组输入返回空', () => { + expect(normalizeClassifierOutput(null, 3)).toEqual([]); + }); +}); + +/** 模拟 nlpWorker:记录请求,由测试手动回消息 */ +class FakeWorker { + onmessage: ((event: MessageEvent) => void) | null = null; + onerror: ((event: ErrorEvent) => void) | null = null; + sent: NlpRequest[] = []; + terminated = false; + + postMessage(message: NlpRequest): void { + this.sent.push(message); + } + + terminate(): void { + this.terminated = true; + } + + emit(response: NlpResponse): void { + this.onmessage?.({ data: response } as MessageEvent); + } +} + +const createClassifier = (): { classifier: ChapterClassifier; worker: FakeWorker } => { + const worker = new FakeWorker(); + const classifier = new ChapterClassifier(() => worker as unknown as Worker); + return { classifier, worker }; +}; + +describe('ChapterClassifier 协议', () => { + it('load:转发进度回调并返回后端类型', async () => { + const { classifier, worker } = createClassifier(); + const onProgress = vi.fn(); + const loadPromise = classifier.load({ modelId: 'test/model', onProgress }); + + const { operationId } = worker.sent[0]; + worker.emit({ operationId, type: 'progress', progress: { status: 'progress', file: 'model.onnx', progress: 50 } }); + worker.emit({ operationId, type: 'loaded', device: 'wasm' }); + + await expect(loadPromise).resolves.toBe('wasm'); + expect(onProgress).toHaveBeenCalledWith({ status: 'progress', file: 'model.onnx', progress: 50 }); + expect(classifier.activeDevice).toBe('wasm'); + expect(worker.sent[0]).toMatchObject({ type: 'load', modelId: 'test/model' }); + }); + + it('classifyLines:按 LABEL_1 映射为标题概率', async () => { + const { classifier, worker } = createClassifier(); + const promise = classifier.classifyLines(['第一章 起点', '正文内容']); + + const { operationId } = worker.sent[0]; + worker.emit({ + operationId, + type: 'result', + scores: [ + [ + { label: 'LABEL_0', score: 0.1 }, + { label: 'LABEL_1', score: 0.9 }, + ], + [ + { label: 'LABEL_0', score: 0.8 }, + { label: 'LABEL_1', score: 0.2 }, + ], + ], + }); + + await expect(promise).resolves.toEqual([0.9, 0.2]); + }); + + it('worker 返回错误时对应请求被拒绝', async () => { + const { classifier, worker } = createClassifier(); + const promise = classifier.classifyLines(['line']); + + const { operationId } = worker.sent[0]; + worker.emit({ operationId, type: 'error', message: 'Model not loaded, send a load request first' }); + + await expect(promise).rejects.toThrow('Model not loaded'); + }); + + it('dispose:终止 worker 并拒绝在途请求', async () => { + const { classifier, worker } = createClassifier(); + const promise = classifier.load(); + classifier.dispose(); + + await expect(promise).rejects.toThrow('disposed'); + expect(worker.terminated).toBe(true); + expect(classifier.activeDevice).toBeNull(); + }); +}); diff --git a/lib/nlp/index.ts b/lib/nlp/index.ts new file mode 100644 index 0000000..cc8142f --- /dev/null +++ b/lib/nlp/index.ts @@ -0,0 +1,147 @@ +import { PLACEHOLDER_MODEL_ID } from './protocol'; +import type { + ClassifyResponse, + LabelScore, + LoadRequest, + LoadedResponse, + ModelProgress, + NlpDevice, + NlpRequest, + NlpResponse, +} from './protocol'; +import { toTitleScores } from './score'; + +/** 微调模型的正类标签,P3 训练脚本需与此保持一致 */ +export const DEFAULT_POSITIVE_LABEL = 'LABEL_1'; + +export interface LoadModelOptions { + modelId?: string; + dtype?: LoadRequest['dtype']; + /** 强制指定推理后端,缺省 WebGPU 优先、WASM 兜底 */ + device?: NlpDevice; + onProgress?: (progress: ModelProgress) => void; +} + +export interface ClassifyOptions { + /** 视为「是标题」的标签名 */ + positiveLabel?: string; +} + +interface PendingOperation { + resolve: (response: NlpResponse) => void; + reject: (error: Error) => void; + onProgress?: (progress: ModelProgress) => void; +} + +/** + * nlpWorker 的主线程封装:模型懒加载(首次 load 才创建 worker 并下载模型, + * 之后走浏览器缓存离线可用),批量行分类返回「是标题」概率。 + * 用法: + * const classifier = new ChapterClassifier(); + * await classifier.load({ onProgress }); + * const scores = await classifier.classifyLines(lines); + */ +export class ChapterClassifier { + private worker: Worker | null = null; + private nextOperationId = 1; + private pending = new Map(); + private device: NlpDevice | null = null; + private readonly createWorker: () => Worker; + + constructor(createWorker?: () => Worker) { + this.createWorker = + createWorker ?? + ((): Worker => new Worker(new URL('../../workers/nlpWorker.ts', import.meta.url), { type: 'module' })); + } + + /** 当前推理后端,未加载时为 null */ + get activeDevice(): NlpDevice | null { + return this.device; + } + + async load(options: LoadModelOptions = {}): Promise { + const response = await this.send( + { + type: 'load', + modelId: options.modelId ?? PLACEHOLDER_MODEL_ID, + dtype: options.dtype, + device: options.device, + }, + options.onProgress, + ); + this.device = (response as LoadedResponse).device; + return this.device; + } + + /** 逐行返回「是标题」概率,需先 load */ + async classifyLines(lines: string[], options: ClassifyOptions = {}): Promise { + const scores = await this.classifyLinesRaw(lines); + return toTitleScores(scores, options.positiveLabel ?? DEFAULT_POSITIVE_LABEL); + } + + /** 逐行返回全部标签得分,调试与评估用 */ + async classifyLinesRaw(lines: string[]): Promise { + const response = await this.send({ type: 'classify', lines }); + return (response as ClassifyResponse).scores; + } + + /** 终止 worker 并拒绝所有在途请求;再次 load 会重建 */ + dispose(): void { + this.worker?.terminate(); + this.worker = null; + this.device = null; + this.rejectAll(new Error('ChapterClassifier disposed')); + } + + private getWorker(): Worker { + if (!this.worker) { + this.worker = this.createWorker(); + this.worker.onmessage = (event: MessageEvent) => { + this.handleMessage(event.data); + }; + this.worker.onerror = (event: ErrorEvent) => { + this.rejectAll(new Error(event.message || 'nlpWorker crashed')); + }; + } + return this.worker; + } + + private send( + request: Omit | { type: 'classify'; lines: string[] }, + onProgress?: (progress: ModelProgress) => void, + ): Promise { + const operationId = this.nextOperationId++; + return new Promise((resolve, reject) => { + this.pending.set(operationId, { resolve, reject, onProgress }); + this.getWorker().postMessage({ ...request, operationId } as NlpRequest); + }); + } + + private handleMessage(response: NlpResponse): void { + const operation = this.pending.get(response.operationId); + if (!operation) { + return; + } + if (response.type === 'progress') { + operation.onProgress?.(response.progress); + return; + } + this.pending.delete(response.operationId); + if (response.type === 'error') { + operation.reject(new Error(response.message)); + } else { + operation.resolve(response); + } + } + + private rejectAll(error: Error): void { + for (const operation of this.pending.values()) { + operation.reject(error); + } + this.pending.clear(); + } +} + +export { PLACEHOLDER_MODEL_ID } from './protocol'; +export type { LabelScore, ModelProgress, NlpDevice } from './protocol'; +export { toTitleScores, normalizeClassifierOutput } from './score'; diff --git a/lib/nlp/protocol.ts b/lib/nlp/protocol.ts new file mode 100644 index 0000000..8b3e0e4 --- /dev/null +++ b/lib/nlp/protocol.ts @@ -0,0 +1,78 @@ +/** + * nlpWorker 与主线程之间的消息协议。 + * 双端共享此文件,保证请求/响应类型一致。 + */ + +/** + * 章节标题分类模型。P3 训练完成后替换为自有的 mDeBERTa 微调模型 id; + * 当前为链路验证用的占位模型(情感二分类,仅用于验证下载/缓存/推理管线)。 + */ +export const PLACEHOLDER_MODEL_ID = 'Xenova/distilbert-base-uncased-finetuned-sst-2-english'; + +/** 推理后端,按优先级降级 */ +export const DEVICE_PRIORITY = ['webgpu', 'wasm'] as const; + +export type NlpDevice = (typeof DEVICE_PRIORITY)[number]; + +/** 模型加载进度(transformers.js progress_callback 的窄化投影,可结构化克隆) */ +export interface ModelProgress { + status: string; + /** 当前正在下载的文件名 */ + file?: string; + /** 已下载字节数 */ + loaded?: number; + /** 总字节数 */ + total?: number; + /** 0-100 */ + progress?: number; +} + +export interface LabelScore { + label: string; + score: number; +} + +export interface LoadRequest { + operationId: number; + type: 'load'; + modelId: string; + /** 量化精度,默认 q8 */ + dtype?: 'fp32' | 'fp16' | 'q8' | 'q4'; + /** 强制指定推理后端(调试或移动端策略用),缺省按 DEVICE_PRIORITY 降级 */ + device?: NlpDevice; +} + +export interface ClassifyRequest { + operationId: number; + type: 'classify'; + lines: string[]; +} + +export type NlpRequest = LoadRequest | ClassifyRequest; + +export interface ProgressResponse { + operationId: number; + type: 'progress'; + progress: ModelProgress; +} + +export interface LoadedResponse { + operationId: number; + type: 'loaded'; + device: NlpDevice; +} + +export interface ClassifyResponse { + operationId: number; + type: 'result'; + /** 与请求 lines 一一对应,每行是全部标签的得分 */ + scores: LabelScore[][]; +} + +export interface ErrorResponse { + operationId: number; + type: 'error'; + message: string; +} + +export type NlpResponse = ProgressResponse | LoadedResponse | ClassifyResponse | ErrorResponse; diff --git a/lib/nlp/score.ts b/lib/nlp/score.ts new file mode 100644 index 0000000..e48c669 --- /dev/null +++ b/lib/nlp/score.ts @@ -0,0 +1,24 @@ +import type { LabelScore } from './protocol'; + +/** + * 把逐行的多标签得分映射成「是标题」的概率。 + * 行内找不到目标标签时按 0 处理(模型标签集与预期不符时宁可漏报不误报)。 + */ +export const toTitleScores = (scores: LabelScore[][], positiveLabel: string): number[] => { + return scores.map((line) => line.find((item) => item.label === positiveLabel)?.score ?? 0); +}; + +/** + * transformers.js 的 text-classification 输出在单条输入时不包着数组, + * 统一归一化为「每行一个 LabelScore[]」的形状。 + */ +export const normalizeClassifierOutput = (output: unknown, lineCount: number): LabelScore[][] => { + if (!Array.isArray(output)) { + return []; + } + // 单行输入且 top_k 展开时,输出是一层 LabelScore[] + if (lineCount === 1 && output.length > 0 && !Array.isArray(output[0])) { + return [output as LabelScore[]]; + } + return (output as (LabelScore | LabelScore[])[]).map((line) => (Array.isArray(line) ? line : [line])); +}; diff --git a/package.json b/package.json index f05608f..7f3b14f 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "vitest": "^4.1.10" }, "dependencies": { + "@huggingface/transformers": "^4.2.0", "@khmyznikov/pwa-install": "^0.6.4", "crypto-js": "^4.2.0", "jschardet": "^3.1.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd5cfb9..39a9815 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@huggingface/transformers': + specifier: ^4.2.0 + version: 4.2.0 '@khmyznikov/pwa-install': specifier: ^0.6.4 version: 0.6.4(@lit/react@1.0.8(@types/react@19.2.17))(@types/dom-chromium-installation-events@101.0.4)(@types/web-app-manifest@1.0.9)(lit@3.3.3) @@ -334,6 +337,16 @@ packages: resolution: {integrity: sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@huggingface/jinja@0.5.9': + resolution: {integrity: sha512-uWTG+l3VJRsl7EXxYizuL3P+cCPoc3cRqbWWRcQN0FhejRfbdq0RNhCmbY/YDtnTcz9icdLYuLDjsnz4d8JMuw==} + engines: {node: '>=18'} + + '@huggingface/tokenizers@0.1.3': + resolution: {integrity: sha512-8rF/RRT10u+kn7YuUbUg0OF30K8rjTc78aHpxT+qJ1uWSqxT1MHi8+9ltwYfkFYJzT/oS+qw3JVfHtNMGAdqyA==} + + '@huggingface/transformers@4.2.0': + resolution: {integrity: sha512-8BRCoBMH0XsWaEIamuR0LrJGAfftgHAfb2Vrffy0VKlSAE/MnUJ5/h/zTfEP3fDIft+nk7TqB8xXEyABGitBjQ==} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -354,6 +367,159 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -486,6 +652,33 @@ packages: resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} engines: {node: '>= 10.0.0'} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + '@rolldown/binding-android-arm64@1.1.5': resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1076,6 +1269,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + adm-zip@0.5.18: + resolution: {integrity: sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng==} + engines: {node: '>=12.0'} + ajv@6.15.0: resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} @@ -1099,6 +1296,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + boolean@3.2.0: + resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + brace-expansion@5.0.7: resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} engines: {node: 18 || 20 || >=22} @@ -1155,10 +1356,21 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + earcut@3.2.3: resolution: {integrity: sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==} @@ -1173,9 +1385,20 @@ packages: resolution: {integrity: sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw==} engines: {node: '>=10.13.0'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@2.3.1: resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + esbuild@0.28.1: resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} @@ -1321,6 +1544,9 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} + flatbuffers@25.9.23: + resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==} + flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} @@ -1339,6 +1565,10 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + global-agent@3.0.0: + resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} + engines: {node: '>=10.0'} + globals@15.15.0: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} @@ -1347,16 +1577,30 @@ packages: resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} engines: {node: '>=18'} + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + guid-typescript@1.0.9: + resolution: {integrity: sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1404,6 +1648,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1498,9 +1745,16 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + matcher@3.0.0: + resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} + engines: {node: '>=10'} + minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -1528,10 +1782,27 @@ packages: resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} engines: {node: '>=18'} + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + obug@2.1.3: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} + onnxruntime-common@1.24.0-dev.20251116-b39e144322: + resolution: {integrity: sha512-BOoomdHYmNRL5r4iQ4bMvsl2t0/hzVQ3OM3PHD0gxeXu1PmggqBv3puZicEUVOA3AtHHYmqZtjMj9FOfGrATTw==} + + onnxruntime-common@1.24.3: + resolution: {integrity: sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA==} + + onnxruntime-node@1.24.3: + resolution: {integrity: sha512-JH7+czbc8ALA819vlTgcV+Q214/+VjGeBHDjX81+ZCD0PCVCIFGFNtT0V4sXG/1JXypKPgScQcB3ij/hk3YnTg==} + os: [win32, darwin, linux] + + onnxruntime-web@1.26.0-dev.20260416-b7804b056c: + resolution: {integrity: sha512-MD6Ss4GSpQBo6zqoJzyT9LRbKYs7x/JVN23FT24EcEvlqF4VuzPOeH6X38orZPKHQDbprn7K+SBpu0/mj2CQiw==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1562,6 +1833,9 @@ packages: resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} + platform@1.3.6: + resolution: {integrity: sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==} + postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} @@ -1578,6 +1852,10 @@ packages: engines: {node: '>=14'} hasBin: true + protobufjs@7.6.5: + resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} + engines: {node: '>=12.0.0'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1631,6 +1909,10 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + roarr@2.15.4: + resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} + engines: {node: '>=8.0'} + rolldown@1.1.5: resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1768,14 +2050,25 @@ packages: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true + serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1791,6 +2084,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + stable-hash-x@0.2.0: resolution: {integrity: sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==} engines: {node: '>=12.0.0'} @@ -1853,6 +2149,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + typescript-eslint@8.64.0: resolution: {integrity: sha512-0qg+pDNMnqYzqH9AnNK+39tejHvsShUOUUoRUgtnTGE7QuMZhiFDnozq8nHJVq+Wae6NMLKNWLg5WmkcC/ndyQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2135,6 +2435,18 @@ snapshots: '@eslint/core': 1.2.1 levn: 0.4.1 + '@huggingface/jinja@0.5.9': {} + + '@huggingface/tokenizers@0.1.3': {} + + '@huggingface/transformers@4.2.0': + dependencies: + '@huggingface/jinja': 0.5.9 + '@huggingface/tokenizers': 0.1.3 + onnxruntime-node: 1.24.3 + onnxruntime-web: 1.26.0-dev.20260416-b7804b056c + sharp: 0.34.5 + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -2151,6 +2463,102 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -2264,6 +2672,26 @@ snapshots: '@parcel/watcher-win32-x64': 2.5.6 optional: true + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + '@rolldown/binding-android-arm64@1.1.5': optional: true @@ -2703,6 +3131,8 @@ snapshots: acorn@8.17.0: {} + adm-zip@0.5.18: {} + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 @@ -2725,6 +3155,8 @@ snapshots: baseline-browser-mapping@2.10.43: {} + boolean@3.2.0: {} + brace-expansion@5.0.7: dependencies: balanced-match: 4.0.4 @@ -2770,8 +3202,22 @@ snapshots: deep-is@0.1.4: {} + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + detect-libc@2.1.2: {} + detect-node@2.1.0: {} + earcut@3.2.3: {} electron-to-chromium@1.5.392: {} @@ -2786,8 +3232,14 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@2.3.1: {} + es6-error@4.1.1: {} + esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -2978,6 +3430,8 @@ snapshots: flatted: 3.4.2 keyv: 4.5.4 + flatbuffers@25.9.23: {} + flatted@3.4.2: {} fraction.js@5.3.4: {} @@ -2993,16 +3447,38 @@ snapshots: dependencies: is-glob: 4.0.3 + global-agent@3.0.0: + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.8.5 + serialize-error: 7.0.1 + globals@15.15.0: {} globals@17.7.0: {} + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + globrex@0.1.2: {} + gopd@1.2.0: {} + graceful-fs@4.2.11: {} + guid-typescript@1.0.9: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + ignore@5.3.2: {} ignore@7.0.6: {} @@ -3031,6 +3507,8 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json-stringify-safe@5.0.1: {} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -3109,10 +3587,16 @@ snapshots: dependencies: p-locate: 5.0.0 + long@5.3.2: {} + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + matcher@3.0.0: + dependencies: + escape-string-regexp: 4.0.0 + minimatch@10.2.5: dependencies: brace-expansion: 5.0.7 @@ -3130,8 +3614,29 @@ snapshots: node-releases@2.0.51: {} + object-keys@1.1.1: {} + obug@2.1.3: {} + onnxruntime-common@1.24.0-dev.20251116-b39e144322: {} + + onnxruntime-common@1.24.3: {} + + onnxruntime-node@1.24.3: + dependencies: + adm-zip: 0.5.18 + global-agent: 3.0.0 + onnxruntime-common: 1.24.3 + + onnxruntime-web@1.26.0-dev.20260416-b7804b056c: + dependencies: + flatbuffers: 25.9.23 + guid-typescript: 1.0.9 + long: 5.3.2 + onnxruntime-common: 1.24.0-dev.20251116-b39e144322 + platform: 1.3.6 + protobufjs: 7.6.5 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -3159,6 +3664,8 @@ snapshots: picomatch@4.0.5: {} + platform@1.3.6: {} + postcss-value-parser@4.2.0: {} postcss@8.5.19: @@ -3171,6 +3678,20 @@ snapshots: prettier@3.9.5: {} + protobufjs@7.6.5: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 26.1.1 + long: 5.3.2 + punycode@2.3.1: {} ranui@0.2.1-alpha.1: @@ -3218,6 +3739,15 @@ snapshots: resolve-pkg-maps@1.0.0: {} + roarr@2.15.4: + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.4 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.3 + rolldown@1.1.5: dependencies: '@oxc-project/types': 0.139.0 @@ -3347,10 +3877,47 @@ snapshots: refa: 0.12.1 regexp-ast-analysis: 0.7.1 + semver-compare@1.0.0: {} + semver@7.8.5: {} + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + set-cookie-parser@2.7.2: {} + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -3361,6 +3928,8 @@ snapshots: source-map-js@1.2.1: {} + sprintf-js@1.1.3: {} + stable-hash-x@0.2.0: {} stackback@0.0.2: {} @@ -3408,6 +3977,8 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@0.13.1: {} + typescript-eslint@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2): dependencies: '@typescript-eslint/eslint-plugin': 8.64.0(@typescript-eslint/parser@8.64.0(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2))(eslint@10.7.0(jiti@2.7.0))(typescript@7.0.2) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1972257..482f475 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,10 @@ allowBuilds: - esbuild: set this to true or false - unrs-resolver: set this to true or false + # vite 的核心依赖,需要安装原生二进制 + esbuild: true + # eslint-plugin-import-x 的原生解析器 + unrs-resolver: true + # 以下均为 Node 端可选依赖,浏览器项目用不到,禁止执行构建脚本 + '@parcel/watcher': false + onnxruntime-node: false + protobufjs: false + sharp: false diff --git a/workers/nlpWorker.ts b/workers/nlpWorker.ts new file mode 100644 index 0000000..e33c595 --- /dev/null +++ b/workers/nlpWorker.ts @@ -0,0 +1,112 @@ +import { env, pipeline } from '@huggingface/transformers'; +import type { ProgressInfo, TextClassificationPipeline } from '@huggingface/transformers'; +import { DEVICE_PRIORITY } from '@/lib/nlp/protocol'; +import type { + ClassifyRequest, + LabelScore, + LoadRequest, + ModelProgress, + NlpDevice, + NlpRequest, + NlpResponse, +} from '@/lib/nlp/protocol'; +import { normalizeClassifierOutput } from '@/lib/nlp/score'; + +// 模型一律走远端 + 浏览器缓存(Cache API),不探测本地路径 +env.allowLocalModels = false; +env.useBrowserCache = true; + +let classifier: TextClassificationPipeline | null = null; +let activeDevice: NlpDevice | null = null; +let loading: Promise | null = null; + +const post = (message: NlpResponse): void => { + self.postMessage(message); +}; + +/** transformers.js 的进度对象投影成可结构化克隆的窄类型 */ +const toModelProgress = (info: ProgressInfo): ModelProgress => { + const { status } = info; + const progress: ModelProgress = { status }; + if ('file' in info) { + progress.file = info.file; + } + if ('loaded' in info) { + progress.loaded = info.loaded; + } + if ('total' in info) { + progress.total = info.total; + } + if ('progress' in info) { + progress.progress = info.progress; + } + return progress; +}; + +/** 按 DEVICE_PRIORITY 依次尝试创建 pipeline,全部失败抛出最后一个错误 */ +const createClassifier = async (request: LoadRequest): Promise => { + let lastError: unknown = null; + const devices = request.device ? [request.device] : DEVICE_PRIORITY; + for (const device of devices) { + try { + classifier = await pipeline('text-classification', request.modelId, { + device, + dtype: request.dtype ?? 'q8', + progress_callback: (info: ProgressInfo) => { + post({ operationId: request.operationId, type: 'progress', progress: toModelProgress(info) }); + }, + }); + activeDevice = device; + return device; + } catch (error) { + lastError = error; + classifier = null; + } + } + throw lastError instanceof Error ? lastError : new Error(String(lastError)); +}; + +const handleLoad = async (request: LoadRequest): Promise => { + if (classifier && activeDevice) { + post({ operationId: request.operationId, type: 'loaded', device: activeDevice }); + return; + } + if (!loading) { + loading = createClassifier(request).finally(() => { + loading = null; + }); + } + const device = await loading; + post({ operationId: request.operationId, type: 'loaded', device }); +}; + +const handleClassify = async (request: ClassifyRequest): Promise => { + if (!classifier) { + throw new Error('Model not loaded, send a load request first'); + } + if (request.lines.length === 0) { + post({ operationId: request.operationId, type: 'result', scores: [] }); + return; + } + // top_k: null 返回每行全部标签的得分,交给主线程按标签取用 + const output = (await classifier(request.lines, { top_k: null })) as LabelScore[] | LabelScore[][]; + const scores = normalizeClassifierOutput(output, request.lines.length); + post({ operationId: request.operationId, type: 'result', scores }); +}; + +self.onmessage = async (event: MessageEvent) => { + const request = event.data; + try { + if (request.type === 'load') { + await handleLoad(request); + } else if (request.type === 'classify') { + await handleClassify(request); + } + } catch (error) { + post({ + operationId: request.operationId, + type: 'error', + message: error instanceof Error ? error.message : String(error), + }); + } +}; From 15280b6ef8c45d59088d8207ec89e26abe596891 Mon Sep 17 00:00:00 2001 From: chaxus Date: Fri, 17 Jul 2026 20:49:49 +0800 Subject: [PATCH 04/54] feat: chapter cache persistence and detection confidence (P4 partial) - detectChaptersDetailed: expose confidence (high/medium/low/none) and winning pattern family for model-enhancement decisions - books_chapters store (DB v2): resolveBookChapters orchestrates cache -> caption markup -> rule detection -> persist; algo version bump invalidates cached results (manual corrections exempt) - wire cache into both desktop and mobile book-detail pages - fix: WebDB/dbWorker connections now close on versionchange, without this any future DB upgrade deadlocks against stale connections Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-plan.md | 20 ++++-- lib/chapter/__tests__/detect.test.ts | 45 +++++++++++- lib/chapter/index.ts | 69 +++++++++++++++--- lib/chapter/validate.ts | 42 +++++++++-- lib/indexedDB.ts | 9 +++ lib/transformText.ts | 16 +++-- pages/book-detail/index.tsx | 33 +++++---- store/chapters.ts | 103 +++++++++++++++++++++++++++ store/index.ts | 3 +- workers/dbWorker.ts | 5 ++ 10 files changed, 304 insertions(+), 41 deletions(-) create mode 100644 store/chapters.ts diff --git a/docs/chapter-detection-plan.md b/docs/chapter-detection-plan.md index e7bab0d..0323acf 100644 --- a/docs/chapter-detection-plan.md +++ b/docs/chapter-detection-plan.md @@ -83,13 +83,19 @@ Cache API 持久化 → 新 worker 二次加载 ~600ms。**待办:iOS Safari **验收**:held-out 集上行分类 F1 显著高于纯规则候选层;zh/en 微调后日语零样本可用。 -## Phase 4 — 集成与数据回流 - -- 决策流水线落地:规则候选 →(低置信度时)模型增强 → 全局验证 → 兜底 -- 解析结果持久化到 IndexedDB(复用 `lib/indexedDB.ts`),一本书只解析一次 -- 目录手动编辑 UI:用户可增删改章节点;**用户修正即标注数据**,本地留存, - (可选、需用户同意)匿名回传作为下一轮训练语料 -- i18n:新增文案走 `locales/` +## Phase 4 — 集成与数据回流(模型无关部分 ✅ 2026-07-17) + +- ✅ 置信度信号:`detectChaptersDetailed` 输出 high/medium/low/none + 胜出家族 id, + 作为后续模型增强的触发依据(high 直接用;low/none 提示增强) +- ✅ 解析结果持久化:`books_chapters` store(DB v2),`store/chapters.ts` 的 + `resolveBookChapters` 编排「缓存 → caption 标注 → 规则识别 → 写缓存」, + `CHAPTER_ALGO_VERSION` 变更时自动失效重算(manual 修正除外);阅读页双端已接线 +- ✅ 附带修复:WebDB / dbWorker 连接补上 `onversionchange` 自动断开——否则任何 + DB 版本升级都会被旧连接(worker 或其他标签页)永久阻塞 +- ⬜ 模型增强接线:low/none 置信度时提示用户下载模型增强解析(依赖 P3 真模型) +- ⬜ 目录手动编辑 UI:用户可增删改章节点;**用户修正即标注数据**(source: manual), + 本地留存,(可选、需用户同意)匿名回传作为下一轮训练语料 +- ⬜ i18n:新增文案走 `locales/` ## 里程碑与顺序 diff --git a/lib/chapter/__tests__/detect.test.ts b/lib/chapter/__tests__/detect.test.ts index a77c906..2c3e0fc 100644 --- a/lib/chapter/__tests__/detect.test.ts +++ b/lib/chapter/__tests__/detect.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { detectChapters, parseChineseNumber, parseRomanNumber } from '../index'; +import { detectChapters, detectChaptersDetailed, parseChineseNumber, parseRomanNumber } from '../index'; /** 中文正文填充:短句行,不命中任何标题模式 */ const filler = (chars: number): string => { @@ -145,6 +145,49 @@ describe('detectChapters 抗噪与兜底', () => { }); }); +describe('detectChaptersDetailed 置信度', () => { + it('编号连贯的书为 high', () => { + const text = [filler(300), '第一章 起点', filler(400), '第二章 转折', filler(400), '第三章 结局', filler(400)].join( + '\n', + ); + const detection = detectChaptersDetailed(text); + expect(detection.confidence).toBe('high'); + expect(detection.familyId).toBe('cn-chapter'); + }); + + it('无格式文本为 none', () => { + const detection = detectChaptersDetailed(filler(2000)); + expect(detection.confidence).toBe('none'); + expect(detection.chapters).toEqual([]); + }); + + it('少于 3 章为 low', () => { + const text = [filler(300), '第一章 起点', filler(400), '第二章 结局', filler(400)].join('\n'); + const detection = detectChaptersDetailed(text); + expect(detection.chapters).toHaveLength(2); + expect(detection.confidence).toBe('low'); + }); + + it('编号断裂一半为 medium', () => { + const text = [ + filler(300), + '第一章 起点', + filler(400), + '第二章 前行', + filler(400), + '第四章 迷途', + filler(400), + '第五章 转折', + filler(400), + '第七章 结局', + filler(400), + ].join('\n'); + const detection = detectChaptersDetailed(text); + expect(detection.chapters).toHaveLength(5); + expect(detection.confidence).toBe('medium'); + }); +}); + describe('数字解析', () => { it('中文数字', () => { expect(parseChineseNumber('十五')).toBe(15); diff --git a/lib/chapter/index.ts b/lib/chapter/index.ts index 2bbc6f0..3e974bf 100644 --- a/lib/chapter/index.ts +++ b/lib/chapter/index.ts @@ -1,5 +1,11 @@ import { collectCandidates } from './candidates'; -import { selectChapters } from './validate'; +import { validateCandidates } from './validate'; + +/** + * 识别算法版本号。模式库或验证逻辑有实质变更时 +1, + * 用于失效 IndexedDB 里按旧算法缓存的章节结果(手动修正的结果不受影响)。 + */ +export const CHAPTER_ALGO_VERSION = 1; export interface DetectedChapter { title: string; @@ -8,23 +14,68 @@ export interface DetectedChapter { } /** - * @description: 从无固定格式的 txt 文本中识别章节边界并提取标题。 + * 识别置信度,驱动 P4 的模型增强决策: + * - high:编号连贯的主模式家族,结果可直接使用 + * - medium:有主模式但序列有断裂,结果可用、可提示增强 + * - low:仅靠无编号家族或章节过少,建议模型增强或人工确认 + * - none:未识别出章节,走兜底(整本一章) + */ +export type ChapterConfidence = 'high' | 'medium' | 'low' | 'none'; + +export interface ChapterDetection { + chapters: DetectedChapter[]; + confidence: ChapterConfidence; + /** 胜出的模式家族 id,无家族胜出时为 null */ + familyId: string | null; +} + +/** 无编号家族(无法做序列连贯性检查),置信度封顶 low */ +const UNNUMBERED_FAMILIES = new Set(['bracket']); + +/** + * @description: 从无固定格式的 txt 文本中识别章节边界并提取标题,附带置信度信号。 * 流程:按行生成候选(多语言模式库)→ 全局验证(编号递增序列 + 间距过滤 + 家族竞争)。 - * 无法可靠识别时返回空数组,调用方应走兜底逻辑(整本一章或按空行分块)。 * @param {string} text 已将换行统一为 \n 的全文 - * @return {DetectedChapter[]} 按出现顺序排列的章节,end 为下一章起点或文本末尾 + * @return {ChapterDetection} 章节列表(end 为下一章起点或文本末尾)+ 置信度 */ -export const detectChapters = (text: string): DetectedChapter[] => { +export const detectChaptersDetailed = (text: string): ChapterDetection => { const candidates = collectCandidates(text); - const selected = selectChapters(candidates, text.length); - return selected.map((chapter, index) => ({ + const validation = validateCandidates(candidates, text.length); + const chapters = validation.chapters.map((chapter, index) => ({ title: chapter.title, start: chapter.start, - end: selected[index + 1]?.start ?? text.length, + end: validation.chapters[index + 1]?.start ?? text.length, })); + return { + chapters, + confidence: resolveConfidence(chapters.length, validation.familyId, validation.contiguity), + familyId: validation.familyId, + }; +}; + +/** 兼容入口:只要章节列表 */ +export const detectChapters = (text: string): DetectedChapter[] => { + return detectChaptersDetailed(text).chapters; +}; + +const resolveConfidence = (chapterCount: number, familyId: string | null, contiguity: number): ChapterConfidence => { + if (chapterCount === 0) { + return 'none'; + } + if (familyId === null || UNNUMBERED_FAMILIES.has(familyId) || chapterCount < 3) { + return 'low'; + } + if (contiguity >= 0.8) { + return 'high'; + } + if (contiguity >= 0.5) { + return 'medium'; + } + return 'low'; }; export { collectCandidates } from './candidates'; export type { Candidate } from './candidates'; -export { selectChapters, MIN_CHAPTER_GAP } from './validate'; +export { selectChapters, validateCandidates, MIN_CHAPTER_GAP } from './validate'; +export type { ChapterValidation, ValidatedChapter } from './validate'; export { parseChineseNumber, parseRomanNumber, PATTERN_FAMILIES } from './patterns'; diff --git a/lib/chapter/validate.ts b/lib/chapter/validate.ts index 0873224..e3e3261 100644 --- a/lib/chapter/validate.ts +++ b/lib/chapter/validate.ts @@ -18,18 +18,30 @@ export interface ValidatedChapter { start: number; } +/** 全局验证的完整结果,familyId/contiguity 等细节供置信度评估使用 */ +export interface ChapterValidation { + chapters: ValidatedChapter[]; + /** 胜出家族,无家族胜出(仅特殊章节或识别失败)时为 null */ + familyId: string | null; + /** 胜出家族相邻编号恰好 +1 的比例(0-1),无编号家族为 0 */ + contiguity: number; + /** 全部候选行数(含被剔除的) */ + candidateCount: number; +} + interface FamilyResult { familyId: string; kept: Candidate[]; + contiguity: number; score: number; } /** - * 全局验证:按家族分组竞争,编号家族用「最长递增子序列 + 间距过滤」剔除误报, + * 全局验证:按家族分组竞争,编号家族用「间距过滤 + 最长递增子序列」剔除误报, * 选得分最高的家族作为主模式,再把特殊章节(序章/番外/后记)并入结果。 - * 没有任何家族胜出时返回空数组,由调用方走兜底逻辑。 + * 没有任何家族胜出时 chapters 为空数组,由调用方走兜底逻辑。 */ -export const selectChapters = (candidates: Candidate[], textLength: number): ValidatedChapter[] => { +export const validateCandidates = (candidates: Candidate[], textLength: number): ChapterValidation => { const specials = candidates.filter((item) => item.special); const regulars = candidates.filter((item) => !item.special); @@ -54,15 +66,31 @@ export const selectChapters = (candidates: Candidate[], textLength: number): Val const accepted = best ? [...best.kept] : []; mergeSpecials(accepted, specials); + const rejected: ChapterValidation = { + chapters: [], + familyId: null, + contiguity: 0, + candidateCount: candidates.length, + }; if (accepted.length < 2) { - return []; + return rejected; } // 结果不应挤在文本的极小前缀里(如仅命中开头的目录页),要求覆盖到文本中段 const last = accepted[accepted.length - 1]; if (textLength > 0 && last.start < textLength * 0.3) { - return []; + return rejected; } - return accepted.map((item) => ({ title: item.title, start: item.start })); + return { + chapters: accepted.map((item) => ({ title: item.title, start: item.start })), + familyId: best?.familyId ?? null, + contiguity: best?.contiguity ?? 0, + candidateCount: candidates.length, + }; +}; + +/** 兼容入口:只要章节列表 */ +export const selectChapters = (candidates: Candidate[], textLength: number): ValidatedChapter[] => { + return validateCandidates(candidates, textLength).chapters; }; const evaluateFamily = (familyId: string, group: Candidate[]): FamilyResult | null => { @@ -79,7 +107,7 @@ const evaluateFamily = (familyId: string, group: Candidate[]): FamilyResult | nu const contiguity = numbered ? contiguityScore(kept) : 0; const weight = FAMILY_WEIGHTS[familyId] ?? 0.5; const score = kept.length * (0.6 + 0.4 * contiguity) * weight; - return { familyId, kept, score }; + return { familyId, kept, contiguity, score }; }; /** diff --git a/lib/indexedDB.ts b/lib/indexedDB.ts index 9b5a6b9..570dfcf 100644 --- a/lib/indexedDB.ts +++ b/lib/indexedDB.ts @@ -29,6 +29,11 @@ export class WebDB { request.onsuccess = () => { this.database = request.result; this.version = this.database.version; + // 其他连接(新标签页/worker)请求更高版本时主动断开,避免阻塞升级 + this.database.onversionchange = () => { + this.database?.close(); + this.database = undefined; + }; resolve({ status: 'success', data: { @@ -72,6 +77,10 @@ export class WebDB { if (this.database && !this.database.objectStoreNames.contains('books_info')) { this.database.createObjectStore('books_info', { keyPath: 'id' }); } + // v2:章节识别结果缓存,key 为书籍 id + if (this.database && !this.database.objectStoreNames.contains('books_chapters')) { + this.database.createObjectStore('books_chapters', { keyPath: 'id' }); + } resolve({ status: 'success', data: { diff --git a/lib/transformText.ts b/lib/transformText.ts index b43af67..c7475bc 100644 --- a/lib/transformText.ts +++ b/lib/transformText.ts @@ -359,17 +359,25 @@ export const transformTextToExpectedFormat = ({ content, container, title, + chapters, }: { content: ArrayBuffer | Uint8Array; container: HTMLElement; title: string; + /** 预计算的章节(来自缓存或模型增强),传入时跳过内部识别;空数组表示已确认无章节 */ + chapters?: ChapterItem[]; }): TextSyntaxTree => { // 1. 过滤空格换行 const text = arrayBufferToString(content).replace(/(?:\r\n|\r|\n)+/g, '\n') || ''; - // 2. 提取章节标题:优先 标注,无标注的原始 txt 走自动识别 - let extractedChapters: ChapterItem[] = extractCaptionTitleChapters(text); - if (extractedChapters.length === 0) { - extractedChapters = detectChapters(text); + // 2. 提取章节标题:优先使用预计算结果,其次 标注,最后规则自动识别 + let extractedChapters: ChapterItem[]; + if (chapters) { + extractedChapters = chapters; + } else { + extractedChapters = extractCaptionTitleChapters(text); + if (extractedChapters.length === 0) { + extractedChapters = detectChapters(text); + } } // 3. 把文本按章节划分 const sections: Section[] = []; diff --git a/pages/book-detail/index.tsx b/pages/book-detail/index.tsx index d426fc0..55b4330 100644 --- a/pages/book-detail/index.tsx +++ b/pages/book-detail/index.tsx @@ -2,6 +2,7 @@ import { useEffect, useRef, useState } from 'react'; import { debounce, getQuery } from 'ranuts/utils'; import { getBookById } from '@/store/books'; +import { resolveBookChapters } from '@/store/chapters'; import { transformTextToExpectedFormat } from '@/lib/transformText'; import type { BookInfo } from '@/store/books'; import type { TextSyntaxTree } from '@/lib/transformText'; @@ -110,13 +111,17 @@ export const DesktopBookDetail = (): React.JSX.Element => { } else { setCurrentBookDetail(res.data); const { content, title } = res.data; - const textSyntaxTree: TextSyntaxTree = transformTextToExpectedFormat({ - content, - title, - container: showContainerRef.current!, + // 章节结果优先走 IndexedDB 缓存,未命中时识别并写入缓存 + resolveBookChapters(id, content).then((bookChapters) => { + const textSyntaxTree: TextSyntaxTree = transformTextToExpectedFormat({ + content, + title, + container: showContainerRef.current!, + chapters: bookChapters.chapters, + }); + setTextSyntaxTree(textSyntaxTree); + ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); }); - setTextSyntaxTree(textSyntaxTree); - ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); } }) .catch((error) => { @@ -237,13 +242,17 @@ export const MobileBookDetail = (): React.JSX.Element => { } else { setCurrentBookDetail(res.data); const { content, title } = res.data; - const textSyntaxTree: TextSyntaxTree = transformTextToExpectedFormat({ - content, - title, - container: showContainerRef.current!, + // 章节结果优先走 IndexedDB 缓存,未命中时识别并写入缓存 + resolveBookChapters(id, content).then((bookChapters) => { + const textSyntaxTree: TextSyntaxTree = transformTextToExpectedFormat({ + content, + title, + container: showContainerRef.current!, + chapters: bookChapters.chapters, + }); + setTextSyntaxTree(textSyntaxTree); + ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); }); - setTextSyntaxTree(textSyntaxTree); - ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); } }) .catch((error) => { diff --git a/store/chapters.ts b/store/chapters.ts new file mode 100644 index 0000000..aa30838 --- /dev/null +++ b/store/chapters.ts @@ -0,0 +1,103 @@ +import { db } from '@/store/index'; +import { CHAPTER_ALGO_VERSION, detectChaptersDetailed } from '@/lib/chapter'; +import type { ChapterConfidence, DetectedChapter } from '@/lib/chapter'; +import { arrayBufferToString, extractCaptionTitleChapters } from '@/lib/transformText'; + +export const STORE_NAME_BOOKS_CHAPTERS_KEY = 'books_chapters'; + +/** 章节结果来源:caption 标注 / 规则识别 / 模型增强 / 用户手动修正 */ +export type ChapterSource = 'caption' | 'rules' | 'model' | 'manual'; + +export interface BookChapters { + /** 书籍 id(与 books_info 同 key) */ + id: string; + chapters: DetectedChapter[]; + confidence: ChapterConfidence; + familyId: string | null; + source: ChapterSource; + /** 生成结果时的规则算法版本,用于算法升级后失效重算 */ + algoVersion: number; + modifyTime: number; +} + +/** + * 读取缓存的章节结果。手动修正的结果永远有效; + * 规则/模型产出的结果在算法版本升级后视为未命中,触发重算。 + * 数据库未就绪或旧库缺 store 时按未命中处理,不阻塞阅读流程。 + */ +export const getCachedChapters = async (id: string): Promise => { + try { + const result = await db.readByKey({ storeName: STORE_NAME_BOOKS_CHAPTERS_KEY, key: id }); + const record = result.data; + if (!record || !Array.isArray(record.chapters)) { + return null; + } + if (record.source !== 'manual' && record.algoVersion !== CHAPTER_ALGO_VERSION) { + return null; + } + return record; + } catch { + return null; + } +}; + +/** 写入章节结果缓存,失败静默(缓存缺失只影响下次打开的解析耗时) */ +export const saveChapters = async (record: Omit): Promise => { + try { + await db.update({ + storeName: STORE_NAME_BOOKS_CHAPTERS_KEY, + data: { ...record, algoVersion: CHAPTER_ALGO_VERSION, modifyTime: Date.now() }, + }); + } catch { + // 忽略:旧版本库缺 store 或配额不足时降级为每次现算 + } +}; + +/** + * 解析一本书的章节:缓存命中直接返回;否则依次尝试 + * 标注 → 规则识别,并把结果写入缓存。 + * 返回的 chapters 偏移基于「解码后换行归一化为 \n」的文本, + * 与 transformTextToExpectedFormat 内部使用的文本一致。 + */ +export const resolveBookChapters = async ( + id: string, + content: ArrayBuffer | Uint8Array, +): Promise => { + const cached = await getCachedChapters(id); + if (cached) { + return cached; + } + const text = arrayBufferToString(content).replace(/(?:\r\n|\r|\n)+/g, '\n') || ''; + + const captionChapters = extractCaptionTitleChapters(text); + let record: Omit; + if (captionChapters.length > 0) { + record = { + id, + chapters: captionChapters.map((item) => ({ title: item.title, start: item.start, end: item.end ?? text.length })), + confidence: 'high', + familyId: null, + source: 'caption', + }; + } else { + const detection = detectChaptersDetailed(text); + record = { + id, + chapters: detection.chapters, + confidence: detection.confidence, + familyId: detection.familyId, + source: 'rules', + }; + } + await saveChapters(record); + return { ...record, algoVersion: CHAPTER_ALGO_VERSION, modifyTime: Date.now() }; +}; + +/** 删除某本书的章节缓存(删书或手动重置时用) */ +export const deleteChapters = async (id: string): Promise => { + try { + await db.delete({ storeName: STORE_NAME_BOOKS_CHAPTERS_KEY, key: id }); + } catch { + // 忽略 + } +}; diff --git a/store/index.ts b/store/index.ts index b6cf21e..42d3b5e 100644 --- a/store/index.ts +++ b/store/index.ts @@ -1,7 +1,8 @@ import { WebDB } from '@/lib/indexedDB'; import { createBookStore } from '@/store/books'; -export const db = new WebDB({ dbName: 'read' }); +// v2 新增 books_chapters(章节识别结果缓存) +export const db = new WebDB({ dbName: 'read', version: 2 }); export const initDB = (): void => { db.openDataBase().then((result) => { diff --git a/workers/dbWorker.ts b/workers/dbWorker.ts index 1c064ce..eeb270e 100644 --- a/workers/dbWorker.ts +++ b/workers/dbWorker.ts @@ -191,6 +191,11 @@ const getDatabase = (dbName: string): Promise => { request.onsuccess = () => { db = request.result; dbPromise = null; + // 主线程请求版本升级时主动断开,下次操作会按新版本重开 + db.onversionchange = () => { + db?.close(); + db = null; + }; resolve(db); }; From 9dd70f020ddd3c24bcfb6f923aa334edc0351b96 Mon Sep 17 00:00:00 2001 From: chaxus Date: Fri, 17 Jul 2026 20:56:17 +0800 Subject: [PATCH 05/54] fix: catalogue first entry jumped past the opening page titleIdPage used a falsy check when recording each chapter's first page, so the first section's page 0 was treated as unset and overwritten by 1. Clicking the first catalogue entry skipped the opening page. - compare against undefined instead - add syntax tree tests covering titleIdPage/titleIdTitle, precomputed chapters, and the no-chapter fallback (preface spans multiple pages, otherwise the bug does not reproduce) - configure vitest alias: vite.config.ts aliases rely on vite root-relative resolution, which does not apply under node Co-Authored-By: Claude Fable 5 --- lib/chapter/__tests__/syntaxTree.test.ts | 76 ++++++++++++++++++++++++ lib/transformText.ts | 3 +- vitest.config.ts | 12 ++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 lib/chapter/__tests__/syntaxTree.test.ts diff --git a/lib/chapter/__tests__/syntaxTree.test.ts b/lib/chapter/__tests__/syntaxTree.test.ts new file mode 100644 index 0000000..e4232ac --- /dev/null +++ b/lib/chapter/__tests__/syntaxTree.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, it } from 'vitest'; +import { transformTextToExpectedFormat } from '@/lib/transformText'; + +/** pagingText 只读取 container 的 clientWidth/clientHeight,用最小对象即可驱动分页 */ +const fakeContainer = { clientWidth: 800, clientHeight: 600 } as HTMLElement; + +const filler = (chars: number): string => { + const sentence = '春天的风从山谷里吹过来,带着潮湿的泥土气息,她沿着旧铁轨慢慢往前走。'; + let out = ''; + while (out.length < chars) { + out += sentence + '\n'; + } + return out; +}; + +// 序言必须跨多页:titleIdPage 的 falsy 判断 bug 只在首章有第 2 页时才会覆盖掉页码 0 +const buildBook = (): Uint8Array => { + const text = [ + '开篇说明。\n' + filler(2000), + '第一章 风雪夜', + filler(2000), + '第二章 山路', + filler(2000), + '第三章 灯火', + filler(2000), + ].join('\n'); + return new TextEncoder().encode(text); +}; + +describe('transformTextToExpectedFormat 语法树', () => { + it('自动识别的章节进入目录,titleIdPage 指向各章真实首页', () => { + const tree = transformTextToExpectedFormat({ + content: buildBook(), + container: fakeContainer, + title: '测试书.txt', + }); + + // 目录项:序言 + 三章 + expect(tree.titleIdTitle).toHaveLength(4); + expect(tree.titleIdTitle.slice(1)).toEqual(['第一章 风雪夜', '第二章 山路', '第三章 灯火']); + + // titleIdPage 必须与 pageTitleId 首次出现的位置一致, + // 首章首页页码为 0,曾因 falsy 判断被误写成第 2 页(点目录第一项跳过开头) + const realFirstPage: Record = {}; + tree.pageTitleId.forEach((titleId, page) => { + if (realFirstPage[titleId] === undefined) { + realFirstPage[titleId] = page; + } + }); + expect(tree.titleIdPage[0]).toBe(0); + for (const [titleId, page] of Object.entries(realFirstPage)) { + expect(tree.titleIdPage[titleId]).toBe(page); + } + }); + + it('传入预计算章节时跳过内部识别,直接采用', () => { + const content = buildBook(); + const tree = transformTextToExpectedFormat({ + content, + container: fakeContainer, + title: '测试书.txt', + chapters: [{ title: '自定义章节', start: 0, end: new TextDecoder().decode(content).length }], + }); + expect(tree.titleIdTitle).toEqual(['自定义章节']); + }); + + it('无章节的文本整本作为一章', () => { + const tree = transformTextToExpectedFormat({ + content: new TextEncoder().encode(filler(2000)), + container: fakeContainer, + title: '无格式.txt', + }); + expect(tree.titleIdTitle).toEqual(['无格式.txt']); + expect(tree.totalPage).toBeGreaterThan(0); + }); +}); diff --git a/lib/transformText.ts b/lib/transformText.ts index c7475bc..4e737de 100644 --- a/lib/transformText.ts +++ b/lib/transformText.ts @@ -427,7 +427,8 @@ export const transformTextToExpectedFormat = ({ sequences.forEach((item) => { totalPage += item.result.program.length; item.result.program.forEach((page) => { - if (!titleIdPage[item.titleId]) { + // 必须与 undefined 比较:首章首页的页码是 0,用 falsy 判断会被当成未赋值而指向第 2 页 + if (titleIdPage[item.titleId] === undefined) { titleIdPage[item.titleId] = pageText.length; } pageTitleId.push(item.titleId); diff --git a/vitest.config.ts b/vitest.config.ts index 0f7e42d..cf46a85 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,6 +1,18 @@ +import { resolve } from 'node:path'; import { defineConfig } from 'vitest/config'; +// vite.config.ts 的 alias 依赖 vite 的 root 相对路径解析('/lib' 形式), +// node 环境下需要真实文件系统路径 +const alias = ['components', 'router', 'lib', 'store', 'assets', 'types', 'styles', 'pages', 'locales'].reduce( + (acc, dir) => { + acc[`@/${dir}`] = resolve(import.meta.dirname, dir); + return acc; + }, + {} as Record, +); + export default defineConfig({ + resolve: { alias }, test: { include: ['**/*.test.ts'], exclude: ['**/node_modules/**', '**/dist/**', 'public/**'], From 9aaed40c3ebc45915500bd40c766f33ca7cb8996 Mon Sep 17 00:00:00 2001 From: chaxus Date: Fri, 17 Jul 2026 23:05:41 +0800 Subject: [PATCH 06/54] feat: add ml/ training pipeline for chapter-title model (P3) Corpus evaluation (273 txt) proved the rules layer whack-a-moles: one pattern loosening fixed 28 books but broke 13 and exploded 23 with false positives. Rules kept frozen at high-precision P1 (high=147) as the auto-labeler bootstrap and no-model fallback. - ml/data/build_dataset.py: epub toc.ncx -> per-line labels (ground truth independent of our regex). Verified locally: 84/85 epubs parsed, 236k lines, 7983 title positives (semantic titles the regex cannot catch) - ml/train/train.py: mDeBERTa-v3-base per-line classifier, book-level train/eval split (needs GPU) - ml/export/export_onnx.py: ONNX export + int8 quantization - ml/eval/evalRules.ts: rules corpus evaluator (baseline reference) - ml/README.md documents the flow and what needs a GPU box Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-plan.md | 30 ++++- ml/.gitignore | 13 ++ ml/README.md | 64 ++++++++++ ml/data/build_dataset.py | 210 +++++++++++++++++++++++++++++++++ ml/eval/evalRules.ts | 129 ++++++++++++++++++++ ml/export/export_onnx.py | 54 +++++++++ ml/requirements.txt | 9 ++ ml/train/train.py | 143 ++++++++++++++++++++++ 8 files changed, 651 insertions(+), 1 deletion(-) create mode 100644 ml/.gitignore create mode 100644 ml/README.md create mode 100644 ml/data/build_dataset.py create mode 100644 ml/eval/evalRules.ts create mode 100644 ml/export/export_onnx.py create mode 100644 ml/requirements.txt create mode 100644 ml/train/train.py diff --git a/docs/chapter-detection-plan.md b/docs/chapter-detection-plan.md index 0323acf..bb909df 100644 --- a/docs/chapter-detection-plan.md +++ b/docs/chapter-detection-plan.md @@ -68,7 +68,35 @@ txt 文本 桌面 Chrome 通过全链路:下载(149 个进度事件)→ WebGPU 推理 → 强制 WASM 推理 → Cache API 持久化 → 新 worker 二次加载 ~600ms。**待办:iOS Safari 真机验证**。 -## Phase 3 — 训练管线(仓库外 Python,产物回流) +## 路线修正(2026-07-17,语料驱动) + +拿到真实语料(`literature-books-master`:273 txt + 85 epub)后,在其上评估规则层: + +- 规则层 high 置信度仅 147/273(54%),**完全未识别 96/273(35%)**,远低于计划里写的「~95%」 +- 尝试补正则接住失败样本,**一次改动修好 28 本却碰坏 13 本、另有 23 本误报爆炸**—— + 纯正则会打地鼠已被数据证实 +- 关键发现:85 个 epub 自带结构化目录(`toc.ncx`),是**独立于规则的 ground truth**, + 这解除了 P3 原来的「训练数据死结」(自动标注只能来自自己正则) + +**决策:提前启动 P3,规则层冻结在高精度(P1 版本)当自动标注器 + 兜底。** +P4 的目录编辑 UI 顺延到模型就位后(用户修正即增量标注)。 + +## Phase 3 — 训练管线(`ml/` 子项目,产物回流)✅ 数据管线已验证(2026-07-17) + +已落地 `ml/`(Python + tsx,不进 npm 构建): + +- `data/build_dataset.py`:epub → 行级标签 JSONL(prev/text/next/label)。**本机已跑通**: + 84/85 epub 解析成功,产出 23.6 万行、7983 标题正样本、正负比 1:29。标签是语义标题 + (「累到无力抵抗」「第1节 批《苦恋》」),正是规则接不住的那类 +- `train/train.py`:mDeBERTa-v3-base 逐行分类微调,按书划分 train/eval 防泄漏(需 GPU) +- `export/export_onnx.py`:ONNX 导出 + int8 量化(需 optimum) +- `eval/evalRules.ts`:规则层语料评估器(对照基线,high=147) +- 详见 `ml/README.md` + +**下一步**:GPU 机器上跑 `train.py`,产出模型 → `export_onnx.py` 转 ONNX → +放 `public/models/` → 前端 `ChapterClassifier` 换 modelId 接入(P2 设施已就绪)。 + +## Phase 3(原始计划,保留参考) 独立目录 `ml/`(不进 npm 构建): diff --git a/ml/.gitignore b/ml/.gitignore new file mode 100644 index 0000000..1d49bfb --- /dev/null +++ b/ml/.gitignore @@ -0,0 +1,13 @@ +# 生成的数据集与模型产物不进仓库 +data/out/ +train/out/ +export/out/ +eval/out/ +# 原始语料(体积大、版权)不进仓库 +corpus/ +*.jsonl +# Python +__pycache__/ +*.pyc +.venv/ +venv/ diff --git a/ml/README.md b/ml/README.md new file mode 100644 index 0000000..65dd00e --- /dev/null +++ b/ml/README.md @@ -0,0 +1,64 @@ +# ml/ — 章节标题识别模型 + +规则层(`lib/chapter/`)在真实语料上会「打地鼠」:每放宽一条正则接住一种新格式, +就在别处放进一批假阳性。这个子项目训练一个逐行分类模型来替换规则的**候选生成层**, +学习正则学不会的语义标题(如「基辛格越战回忆录序」「累到无力抵抗」——无编号、无标记)。 + +## 架构定位 + +``` +候选层:mDeBERTa 逐行「是否标题」分类 ← 本项目产出,替换规则候选层 + + 规则模式库(高精度,冻结) ← 保留:引导标注 + 模型未加载时的兜底 +结构层:多卷拼接 / 目录页剔除 / 覆盖度 ← 永远是 lib/chapter/validate.ts,模型不碰 +``` + +模型只判断单行的「标题性」,**不做全局结构组装**——多卷本编号重启、目录页与正文区分、 +章节覆盖度这些仍由 `validate.ts` 用代码完成。 + +## 数据来源:epub 目录 = ground truth + +epub 自带结构化目录(`toc.ncx`),是**独立于规则正则**的真值标签,这解决了 +「自动标注只能来自自己正则、模型只会学成正则模仿者」的死结。 + +当前语料(273 txt + 85 epub)中,84 本 epub 产出 **23.6 万行标注、7983 个标题正样本**, +正负比约 1:29。 + +## 流程 + +```bash +# 1. 构建数据集(只用标准库,本机即可跑) +cd data +python3 build_dataset.py /path/to/corpus --out out/dataset.jsonl +# 加 --report 只统计不写文件 + +# 2. 微调(需 GPU 机器) +cd ../train +pip install -r ../requirements.txt +python3 train.py --data ../data/out/dataset.jsonl --out out/model + +# 3. 导出浏览器 ONNX(需装 optimum 的机器) +cd ../export +python3 export_onnx.py --model ../train/out/model --out out/full + +# 4. 部署:把 out/full 复制到 public/models/chapter-title/, +# 前端 lib/nlp 的 ChapterClassifier 换 modelId 即可加载 + +# 评估规则层在语料上的当前表现(对照基线,非模型) +cd ../eval +npx tsx evalRules.ts /path/to/corpus +``` + +## 目录 + +| 路径 | 说明 | 运行环境 | +|------|------|----------| +| `data/build_dataset.py` | epub → 行级标签 JSONL | 本机(标准库) | +| `train/train.py` | mDeBERTa 逐行分类微调 | **GPU 机器** | +| `export/export_onnx.py` | ONNX 导出 + int8 量化 | 装 optimum 的机器 | +| `eval/evalRules.ts` | 规则层语料评估(对照基线) | 本机(tsx) | + +## 已知待办 + +- 词表裁剪版(移动端 ~150MB):`export/prune_vocab.py` 待补,按 CJK+拉丁+西里尔裁剪 +- 类别不平衡(1:29)当前靠 F1 选优 + 长训练;如效果不足可换带 class_weight 的 loss +- 训练/导出脚本尚未在 GPU 机器上实跑验证;数据管线已在本机验证(84/85 epub 解析成功) diff --git a/ml/data/build_dataset.py b/ml/data/build_dataset.py new file mode 100644 index 0000000..b1f9df7 --- /dev/null +++ b/ml/data/build_dataset.py @@ -0,0 +1,210 @@ +""" +从 epub 语料构建行级章节标题分类的训练数据。 + +epub 自带结构化目录(toc.ncx / nav),是独立于规则正则的 ground truth: +把 epub 正文按 spine 顺序拍平成纯文本行,凡是命中目录条目标题的行标 1(是标题), +其余标 0。产出 JSONL,每条含目标行 + 上下文窗口,供 mDeBERTa 逐行分类微调。 + +只用标准库,无需 pip 安装即可运行与验证。 + +用法: + python3 build_dataset.py --out out/dataset.jsonl [--report] +""" + +from __future__ import annotations + +import argparse +import html +import json +import re +import sys +import unicodedata +import zipfile +from dataclasses import dataclass +from pathlib import Path +from xml.etree import ElementTree as ET + + +def normalize(text: str) -> str: + """统一全角/半角、压缩空白,用于标题匹配与去噪。""" + text = unicodedata.normalize("NFKC", text) + text = re.sub(r"\s+", " ", text) + return text.strip() + + +def strip_html(fragment: str) -> str: + """极简 HTML → 文本:块级标签转换行,其余标签删除,再解码实体。""" + fragment = re.sub(r"(?is)<(script|style)[^>]*>.*?", "", fragment) + fragment = re.sub(r"(?i)<(p|div|h[1-6]|br|li|tr)\b[^>]*>", "\n", fragment) + fragment = re.sub(r"(?i)", "\n", fragment) + fragment = re.sub(r"<[^>]+>", "", fragment) + return html.unescape(fragment) + + +@dataclass +class Epub: + titles: set[str] + lines: list[str] + + +def _ns(tag: str) -> str: + """去掉 XML 命名空间前缀。""" + return tag.rsplit("}", 1)[-1] + + +def read_opf_spine(zf: zipfile.ZipFile, opf_name: str) -> list[str]: + """按 spine 顺序返回正文 html 的内部路径。opf 命名空间不规范时回退正则解析。""" + raw = zf.read(opf_name) + base = opf_name.rsplit("/", 1)[0] if "/" in opf_name else "" + manifest: dict[str, str] = {} + spine: list[str] = [] + try: + root = ET.fromstring(raw) + for el in root.iter(): + tag = _ns(el.tag) + if tag == "item": + manifest[el.attrib.get("id", "")] = el.attrib.get("href", "") + elif tag == "itemref": + idref = el.attrib.get("idref", "") + if idref: + spine.append(idref) + except ET.ParseError: + text = raw.decode("utf-8", "ignore") + for m in re.finditer(r"]*\bid=\"([^\"]+)\"[^>]*\bhref=\"([^\"]+)\"", text): + manifest[m.group(1)] = m.group(2) + for m in re.finditer(r"]*\bhref=\"([^\"]+)\"[^>]*\bid=\"([^\"]+)\"", text): + manifest[m.group(2)] = m.group(1) + for m in re.finditer(r"]*\bidref=\"([^\"]+)\"", text): + spine.append(m.group(1)) + out: list[str] = [] + for idref in spine: + href = manifest.get(idref) + if not href: + continue + path = f"{base}/{href}" if base else href + out.append(path.split("#", 1)[0]) + return out + + +def read_toc_titles(zf: zipfile.ZipFile, names: list[str]) -> set[str]: + """从 toc.ncx 或 nav.xhtml 抽取所有目录条目标题(归一化)。""" + titles: set[str] = set() + for name in names: + low = name.lower() + if low.endswith(".ncx"): + try: + root = ET.fromstring(zf.read(name)) + except ET.ParseError: + continue + for el in root.iter(): + if _ns(el.tag) == "text" and el.text: + titles.add(normalize(el.text)) + elif low.endswith(("nav.xhtml", "nav.html")): + text = zf.read(name).decode("utf-8", "ignore") + for m in re.findall(r"(?is)]*>(.*?)", text): + titles.add(normalize(strip_html(m))) + return {t for t in titles if t} + + +def find_opf(zf: zipfile.ZipFile) -> str | None: + try: + container = zf.read("META-INF/container.xml").decode("utf-8", "ignore") + except KeyError: + return None + m = re.search(r'full-path="([^"]+)"', container) + return m.group(1) if m else None + + +def parse_epub(path: Path) -> Epub | None: + try: + zf = zipfile.ZipFile(path) + except zipfile.BadZipFile: + return None + names = zf.namelist() + opf = find_opf(zf) or ("content.opf" if "content.opf" in names else None) + if not opf or opf not in names: + return None + titles = read_toc_titles(zf, names) + if len(titles) < 3: + return None # 目录太少,无法提供有效标签 + lines: list[str] = [] + for html_path in read_opf_spine(zf, opf): + if html_path not in names: + continue + raw = zf.read(html_path).decode("utf-8", "ignore") + for line in strip_html(raw).split("\n"): + norm = normalize(line) + if norm: + lines.append(norm) + if not lines: + return None + return Epub(titles=titles, lines=lines) + + +def build_records(epub: Epub, book_id: str) -> list[dict]: + """逐行打标签:命中目录标题的行为正样本,其余为负样本,附前后各一行上下文。""" + records = [] + for i, line in enumerate(epub.lines): + # 标题通常较短;过长的行几乎不可能是目录条目,直接判负,避免正文误匹配 + is_title = len(line) <= 40 and line in epub.titles + records.append( + { + "book": book_id, + "prev": epub.lines[i - 1] if i > 0 else "", + "text": line, + "next": epub.lines[i + 1] if i + 1 < len(epub.lines) else "", + "label": 1 if is_title else 0, + } + ) + return records + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("corpus") + ap.add_argument("--out", default="out/dataset.jsonl") + ap.add_argument("--report", action="store_true", help="只统计不写文件") + args = ap.parse_args() + + corpus = Path(args.corpus) + epubs = sorted(corpus.rglob("*.epub")) + print(f"发现 {len(epubs)} 个 epub", file=sys.stderr) + + all_records: list[dict] = [] + parsed = 0 + skipped = 0 + pos_samples: list[str] = [] + for path in epubs: + epub = parse_epub(path) + if epub is None: + skipped += 1 + continue + parsed += 1 + recs = build_records(epub, path.stem) + all_records.extend(recs) + for r in recs: + if r["label"] == 1 and len(pos_samples) < 30: + pos_samples.append(r["text"]) + + pos = sum(r["label"] for r in all_records) + neg = len(all_records) - pos + print(f"\n解析成功 {parsed} 本, 跳过 {skipped} 本(无目录/损坏)") + print(f"总行数 {len(all_records)} 正样本(标题) {pos} 负样本 {neg}") + if all_records: + print(f"正样本占比 {pos / len(all_records) * 100:.2f}% 正负比 1:{neg / max(pos, 1):.0f}") + print("\n正样本示例(这些正是规则正则接不住的语义标题):") + for s in pos_samples[:25]: + print(" +", repr(s)) + + if not args.report: + out = Path(args.out) + out.parent.mkdir(parents=True, exist_ok=True) + with out.open("w", encoding="utf-8") as f: + for r in all_records: + f.write(json.dumps(r, ensure_ascii=False) + "\n") + print(f"\n已写入 {out} ({len(all_records)} 行)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ml/eval/evalRules.ts b/ml/eval/evalRules.ts new file mode 100644 index 0000000..048b1c7 --- /dev/null +++ b/ml/eval/evalRules.ts @@ -0,0 +1,129 @@ +/** + * 在真实书籍语料上评估规则层章节识别效果。 + * 用法:npx tsx [--json out.json] + */ +import { readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs'; +import { extname, join } from 'node:path'; +import jschardet from 'jschardet'; +import { detectChaptersDetailed } from '../../lib/chapter/index'; + +interface Row { + file: string; + sizeKB: number; + encoding: string; + textLength: number; + chapters: number; + confidence: string; + familyId: string | null; + sampleTitles: string[]; +} + +const walk = (dir: string): string[] => { + const out: string[] = []; + for (const name of readdirSync(dir)) { + const full = join(dir, name); + const stat = statSync(full); + if (stat.isDirectory()) { + out.push(...walk(full)); + } else if (extname(name).toLowerCase() === '.txt') { + out.push(full); + } + } + return out; +}; + +const decode = (buf: Buffer): { text: string; encoding: string } => { + // 与应用一致:jschardet 检测后用 TextDecoder 解码 + const ascii = Array.from(buf.subarray(0, 100000)) + .map((b) => String.fromCharCode(b)) + .join(''); + const detected = jschardet.detect(ascii); + let encoding = detected.encoding || 'utf-8'; + // Node 的 TextDecoder 不认 jschardet 的部分别名 + const alias: Record = { 'windows-1252': 'utf-8', ascii: 'utf-8', 'ISO-8859-1': 'utf-8' }; + encoding = alias[encoding] || encoding; + try { + return { text: new TextDecoder(encoding).decode(buf), encoding }; + } catch { + return { text: new TextDecoder('utf-8').decode(buf), encoding: `${encoding}(fallback utf-8)` }; + } +}; + +const corpusDir = process.argv[2]; +const jsonFlag = process.argv.indexOf('--json'); +const files = walk(corpusDir); + +const rows: Row[] = []; +for (const file of files) { + try { + const buf = readFileSync(file); + const { text: raw, encoding } = decode(buf); + const text = raw.replace(/(?:\r\n|\r|\n)+/g, '\n'); + const detection = detectChaptersDetailed(text); + rows.push({ + file: file.replace(corpusDir, '').replace(/^\//, ''), + sizeKB: Math.round(buf.length / 1024), + encoding, + textLength: text.length, + chapters: detection.chapters.length, + confidence: detection.confidence, + familyId: detection.familyId, + sampleTitles: detection.chapters.slice(0, 3).map((c) => c.title), + }); + } catch (error) { + rows.push({ + file: file.replace(corpusDir, '').replace(/^\//, ''), + sizeKB: 0, + encoding: 'ERROR', + textLength: 0, + chapters: 0, + confidence: `error: ${error instanceof Error ? error.message : String(error)}`, + familyId: null, + sampleTitles: [], + }); + } +} + +const byConfidence = rows.reduce>((acc, r) => { + const key = r.confidence.startsWith('error') ? 'error' : r.confidence; + acc[key] = (acc[key] || 0) + 1; + return acc; +}, {}); +const byFamily = rows.reduce>((acc, r) => { + const key = r.familyId ?? '(none)'; + acc[key] = (acc[key] || 0) + 1; + return acc; +}, {}); + +console.log(`\n总计 ${rows.length} 本\n`); +console.log('置信度分布:', byConfidence); +console.log('胜出家族分布:', byFamily); + +const chapterCounts = rows.filter((r) => r.chapters > 0).map((r) => r.chapters); +chapterCounts.sort((a, b) => a - b); +console.log( + `\n识别出章节的书:${chapterCounts.length}/${rows.length}`, + `中位数章节数:${chapterCounts[Math.floor(chapterCounts.length / 2)]}`, + `最少:${chapterCounts[0]} 最多:${chapterCounts[chapterCounts.length - 1]}`, +); + +console.log('\n=== 未识别出章节 (none) ==='); +rows + .filter((r) => r.confidence === 'none') + .slice(0, 40) + .forEach((r) => console.log(` [${r.sizeKB}KB ${r.encoding}] ${r.file}`)); + +console.log('\n=== 低置信度 (low) ==='); +rows + .filter((r) => r.confidence === 'low') + .slice(0, 40) + .forEach((r) => console.log(` [${r.chapters}章 ${r.familyId}] ${r.file} :: ${r.sampleTitles.join(' | ')}`)); + +console.log('\n=== 可疑:章节数异常多 (>500) ==='); +rows + .filter((r) => r.chapters > 500) + .forEach((r) => console.log(` [${r.chapters}章 ${r.familyId}] ${r.file} :: ${r.sampleTitles.join(' | ')}`)); + +if (jsonFlag > -1) { + writeFileSync(process.argv[jsonFlag + 1], JSON.stringify(rows, null, 2)); +} diff --git a/ml/export/export_onnx.py b/ml/export/export_onnx.py new file mode 100644 index 0000000..c99eb61 --- /dev/null +++ b/ml/export/export_onnx.py @@ -0,0 +1,54 @@ +""" +把微调后的模型导出为浏览器可用的 ONNX,并做 int8 动态量化。 + +产出两份(对应 lib/nlp 的加载策略): + - full/ 全量词表,桌面端,~280MB(100 语言覆盖) + - 词表裁剪版由 prune_vocab.py 另行处理(移动端 ~150MB),本脚本先出 full + +导出后目录结构符合 transformers.js 约定:model_quantized.onnx + tokenizer.json + config.json, +放到 public/models/ 或 CDN,前端 ChapterClassifier 换 modelId 即可加载。 + +需要在装好 optimum 的机器运行。 + +用法: + pip install -r ../requirements.txt + python3 export_onnx.py --model ../train/out/model --out out/full +""" + +from __future__ import annotations + +import argparse +from pathlib import Path + +from optimum.onnxruntime import ORTModelForSequenceClassification, ORTQuantizer +from optimum.onnxruntime.configuration import AutoQuantizationConfig +from transformers import AutoTokenizer + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--model", required=True) + ap.add_argument("--out", default="out/full") + args = ap.parse_args() + + out = Path(args.out) + out.mkdir(parents=True, exist_ok=True) + + # 1. HF → ONNX + model = ORTModelForSequenceClassification.from_pretrained(args.model, export=True) + model.save_pretrained(out) + AutoTokenizer.from_pretrained(args.model).save_pretrained(out) + + # 2. int8 动态量化(avx512 配置,兼容大多数 CPU;WebGPU 侧仍可用量化权重) + quantizer = ORTQuantizer.from_pretrained(out) + qconfig = AutoQuantizationConfig.avx512_vnni(is_static=False, per_channel=False) + quantizer.quantize(save_dir=out, quantization_config=qconfig) + + print(f"导出完成: {out}") + print("产物应含 model.onnx 与 model_quantized.onnx;前端默认加载 quantized。") + print("部署: 复制到 public/models/chapter-title/ 或上传 CDN,更新 public 下模型清单 JSON。") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ml/requirements.txt b/ml/requirements.txt new file mode 100644 index 0000000..0cd25f4 --- /dev/null +++ b/ml/requirements.txt @@ -0,0 +1,9 @@ +# 训练与导出依赖。数据管线 data/build_dataset.py 只用标准库,无需安装这些。 +transformers>=4.44 +datasets>=2.20 +torch>=2.3 +scikit-learn>=1.5 +sentencepiece>=0.2 +accelerate>=0.33 +# 导出 ONNX +optimum[onnxruntime]>=1.21 diff --git a/ml/train/train.py b/ml/train/train.py new file mode 100644 index 0000000..c91ef20 --- /dev/null +++ b/ml/train/train.py @@ -0,0 +1,143 @@ +""" +微调 mDeBERTa-v3-base 做逐行章节标题二分类。 + +输入是 build_dataset.py 产出的 JSONL(prev/text/next/label)。 +把上下文窗口拼成单条输入: prev [SEP] text [SEP] next,让模型看到相邻行判断标题性。 + +需要 GPU 机器运行(CPU 上不现实)。产出 HuggingFace 格式模型,交给 export_onnx.py 转 ONNX。 + +用法: + pip install -r ../requirements.txt + python3 train.py --data ../data/out/dataset.jsonl --out out/model +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +import numpy as np +from datasets import Dataset +from sklearn.metrics import precision_recall_fscore_support +from transformers import ( + AutoModelForSequenceClassification, + AutoTokenizer, + DataCollatorWithPadding, + Trainer, + TrainingArguments, +) + +MODEL_ID = "microsoft/mdeberta-v3-base" +MAX_LEN = 128 +# 正类标签需与前端 lib/nlp/index.ts 的 DEFAULT_POSITIVE_LABEL 保持一致 +LABELS = ["not_title", "title"] + + +def load_records(path: Path) -> list[dict]: + with path.open(encoding="utf-8") as f: + return [json.loads(line) for line in f] + + +def dedupe(records: list[dict]) -> list[dict]: + """按 (text,label) 去重,避免同一标题在 train/test 间泄漏。""" + seen = set() + out = [] + for r in records: + key = (r["text"], r["label"]) + if key in seen: + continue + seen.add(key) + out.append(r) + return out + + +def make_text(r: dict) -> str: + return f"{r.get('prev', '')} [SEP] {r['text']} [SEP] {r.get('next', '')}" + + +def split_by_book(records: list[dict], holdout_frac: float = 0.15) -> tuple[list[dict], list[dict]]: + """按书划分 train/eval:同一本书不跨集,避免风格泄漏,逼近真实泛化。""" + books = sorted({r["book"] for r in records}) + cut = int(len(books) * (1 - holdout_frac)) + train_books = set(books[:cut]) + train = [r for r in records if r["book"] in train_books] + dev = [r for r in records if r["book"] not in train_books] + return train, dev + + +def compute_metrics(pred) -> dict: + logits, labels = pred + preds = np.argmax(logits, axis=-1) + p, r, f, _ = precision_recall_fscore_support(labels, preds, average="binary", zero_division=0) + return {"precision": p, "recall": r, "f1": f} + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--data", required=True) + ap.add_argument("--out", default="out/model") + ap.add_argument("--epochs", type=float, default=3.0) + ap.add_argument("--batch", type=int, default=32) + args = ap.parse_args() + + records = dedupe(load_records(Path(args.data))) + train_recs, dev_recs = split_by_book(records) + print(f"训练 {len(train_recs)} 行, 验证 {len(dev_recs)} 行") + + tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) + + def encode(batch): + enc = tokenizer( + [make_text({"prev": p, "text": t, "next": n}) for p, t, n in zip(batch["prev"], batch["text"], batch["next"])], + truncation=True, + max_length=MAX_LEN, + ) + enc["labels"] = batch["label"] + return enc + + train_ds = Dataset.from_list(train_recs).map(encode, batched=True, remove_columns=["book", "prev", "text", "next", "label"]) + dev_ds = Dataset.from_list(dev_recs).map(encode, batched=True, remove_columns=["book", "prev", "text", "next", "label"]) + + model = AutoModelForSequenceClassification.from_pretrained( + MODEL_ID, + num_labels=len(LABELS), + id2label=dict(enumerate(LABELS)), + label2id={label: i for i, label in enumerate(LABELS)}, + ) + + training_args = TrainingArguments( + output_dir=args.out, + num_train_epochs=args.epochs, + per_device_train_batch_size=args.batch, + per_device_eval_batch_size=args.batch, + eval_strategy="epoch", + save_strategy="epoch", + load_best_model_at_end=True, + metric_for_best_model="f1", + learning_rate=2e-5, + warmup_ratio=0.1, + # 类别不平衡(约 1:29):靠更长训练 + F1 选优;如需可换带 class_weight 的自定义 loss + logging_steps=50, + ) + + trainer = Trainer( + model=model, + args=training_args, + train_dataset=train_ds, + eval_dataset=dev_ds, + tokenizer=tokenizer, + data_collator=DataCollatorWithPadding(tokenizer), + compute_metrics=compute_metrics, + ) + trainer.train() + metrics = trainer.evaluate() + print("最终验证指标:", metrics) + trainer.save_model(args.out) + tokenizer.save_pretrained(args.out) + print(f"模型已保存到 {args.out}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From fbc4d0a4e1fa7f05ce878705281b76ab481dea32 Mon Sep 17 00:00:00 2001 From: chaxus Date: Fri, 17 Jul 2026 23:32:04 +0800 Subject: [PATCH 07/54] chore: add train smoke-test flag and pin python 3.11/3.12 - train.py --limit N: quick end-to-end pipeline check on a few books - document venv setup; torch has no wheels for python 3.13/3.14 Co-Authored-By: Claude Fable 5 --- ml/README.md | 13 +++++++++---- ml/requirements.txt | 4 ++++ ml/train/train.py | 8 ++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/ml/README.md b/ml/README.md index 65dd00e..c42010c 100644 --- a/ml/README.md +++ b/ml/README.md @@ -31,10 +31,15 @@ cd data python3 build_dataset.py /path/to/corpus --out out/dataset.jsonl # 加 --report 只统计不写文件 -# 2. 微调(需 GPU 机器) -cd ../train -pip install -r ../requirements.txt -python3 train.py --data ../data/out/dataset.jsonl --out out/model +# 2. 微调(需 GPU 机器;Mac 用 Apple MPS 也能跑,慢些) +# 注意:需 Python 3.11/3.12(torch 无 3.13/3.14 wheel);本机 python3 是 3.14 时用 venv: +cd .. +python3.11 -m venv .venv +.venv/bin/python -m pip install -r requirements.txt +# 先冒烟测试确认链路通(只用少量书): +.venv/bin/python train/train.py --data data/out/dataset.jsonl --limit 5 --epochs 1 +# 再跑完整训练: +.venv/bin/python train/train.py --data data/out/dataset.jsonl --out train/out/model # 3. 导出浏览器 ONNX(需装 optimum 的机器) cd ../export diff --git a/ml/requirements.txt b/ml/requirements.txt index 0cd25f4..9b00c19 100644 --- a/ml/requirements.txt +++ b/ml/requirements.txt @@ -1,4 +1,8 @@ # 训练与导出依赖。数据管线 data/build_dataset.py 只用标准库,无需安装这些。 +# +# 需 Python 3.11 或 3.12(torch 尚无 3.13/3.14 wheel)。本机 python3 若是 3.14,用: +# python3.11 -m venv .venv && .venv/bin/python -m pip install -r requirements.txt +# .venv/bin/python train/train.py --data data/out/dataset.jsonl transformers>=4.44 datasets>=2.20 torch>=2.3 diff --git a/ml/train/train.py b/ml/train/train.py index c91ef20..af6f98f 100644 --- a/ml/train/train.py +++ b/ml/train/train.py @@ -79,10 +79,18 @@ def main() -> int: ap.add_argument("--out", default="out/model") ap.add_argument("--epochs", type=float, default=3.0) ap.add_argument("--batch", type=int, default=32) + ap.add_argument("--limit", type=int, default=0, help="冒烟测试:只用前 N 本书,验证链路是否跑通") args = ap.parse_args() records = dedupe(load_records(Path(args.data))) train_recs, dev_recs = split_by_book(records) + if args.limit: + # 各取若干本书的样本快速验证端到端,不追求效果 + train_books = list(dict.fromkeys(r["book"] for r in train_recs))[: args.limit] + dev_books = list(dict.fromkeys(r["book"] for r in dev_recs))[: max(1, args.limit // 4)] + train_recs = [r for r in train_recs if r["book"] in set(train_books)] + dev_recs = [r for r in dev_recs if r["book"] in set(dev_books)] + print(f"[冒烟测试] 限制到 {len(train_books)} 训练本 / {len(dev_books)} 验证本") print(f"训练 {len(train_recs)} 行, 验证 {len(dev_recs)} 行") tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) From ece69b5024356dccc6a3e1437f94ec20923bfe7a Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 00:04:02 +0800 Subject: [PATCH 08/54] feat: negative subsampling on train split to fix class imbalance Smoke test confirmed the 1:29 positive:negative ratio collapses the model to all-negative predictions (eval f1=0). Subsample negatives in the training split only (default 1:5); keep eval at natural distribution for honest metrics. Co-Authored-By: Claude Fable 5 --- ml/data/build_dataset.py | 1 + ml/train/train.py | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/ml/data/build_dataset.py b/ml/data/build_dataset.py index b1f9df7..f82e5a5 100644 --- a/ml/data/build_dataset.py +++ b/ml/data/build_dataset.py @@ -186,6 +186,7 @@ def main() -> int: if r["label"] == 1 and len(pos_samples) < 30: pos_samples.append(r["text"]) + # 保留全部负样本;负样本降采样在 train.py 的训练集上做,验证集保持自然分布 pos = sum(r["label"] for r in all_records) neg = len(all_records) - pos print(f"\n解析成功 {parsed} 本, 跳过 {skipped} 本(无目录/损坏)") diff --git a/ml/train/train.py b/ml/train/train.py index af6f98f..93dc2b2 100644 --- a/ml/train/train.py +++ b/ml/train/train.py @@ -66,6 +66,25 @@ def split_by_book(records: list[dict], holdout_frac: float = 0.15) -> tuple[list return train, dev +def subsample_negatives(records: list[dict], neg_ratio: float, seed: int = 42) -> list[dict]: + """ + 负样本降采样:保留全部正样本,随机保留 neg_ratio×正样本数 的负样本。 + 只用于训练集——1:29 的极端不平衡会让模型退化成「全判非标题」(冒烟测试已验证 f1=0); + 降到约 1:5 训练更快、能真正学到标题特征。验证集不动,保持自然分布以诚实评估。 + """ + import random + + rng = random.Random(seed) + pos = [r for r in records if r["label"] == 1] + neg = [r for r in records if r["label"] == 0] + keep = int(len(pos) * neg_ratio) + if keep >= len(neg): + return records + out = pos + rng.sample(neg, keep) + rng.shuffle(out) + return out + + def compute_metrics(pred) -> dict: logits, labels = pred preds = np.argmax(logits, axis=-1) @@ -80,6 +99,12 @@ def main() -> int: ap.add_argument("--epochs", type=float, default=3.0) ap.add_argument("--batch", type=int, default=32) ap.add_argument("--limit", type=int, default=0, help="冒烟测试:只用前 N 本书,验证链路是否跑通") + ap.add_argument( + "--neg-ratio", + type=float, + default=5.0, + help="训练集负样本降采样目标比例(负:正=N:1),缓解 1:29 不平衡。0 表示不降采样", + ) args = ap.parse_args() records = dedupe(load_records(Path(args.data))) @@ -91,7 +116,13 @@ def main() -> int: train_recs = [r for r in train_recs if r["book"] in set(train_books)] dev_recs = [r for r in dev_recs if r["book"] in set(dev_books)] print(f"[冒烟测试] 限制到 {len(train_books)} 训练本 / {len(dev_books)} 验证本") - print(f"训练 {len(train_recs)} 行, 验证 {len(dev_recs)} 行") + if args.neg_ratio > 0: + before = len(train_recs) + train_recs = subsample_negatives(train_recs, args.neg_ratio) + print(f"训练集负样本降采样: {before} → {len(train_recs)} 行 (目标 1:{args.neg_ratio:g})") + train_pos = sum(r["label"] for r in train_recs) + dev_pos = sum(r["label"] for r in dev_recs) + print(f"训练 {len(train_recs)} 行(正 {train_pos}), 验证 {len(dev_recs)} 行(正 {dev_pos}, 保持自然分布)") tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) From b447efc4e6eb47266788ac380214ef2773e1dc94 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 05:20:22 +0800 Subject: [PATCH 09/54] fix: stabilize DeBERTa-v3 training (batch 16, tunable lr, eval subsampling) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The batch-32/3-epoch run produced a dead model (constant logits, f1=0) — a known DeBERTa-v3 fine-tuning instability. Reverting to the smoke-proven batch 16 / lr 2e-5 / 2 epochs on full data gives f1=0.59, precision=0.88. Model correctly flags Jin-Yong-style chapter titles (青衫磊落险峰行) that regex cannot match. - default batch 16, epochs 2; add --lr and --eval-limit knobs - --eval-limit subsamples the dev set for fast iteration (17min -> 2min) Co-Authored-By: Claude Fable 5 --- ml/train/train.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ml/train/train.py b/ml/train/train.py index 93dc2b2..fafc84e 100644 --- a/ml/train/train.py +++ b/ml/train/train.py @@ -96,9 +96,11 @@ def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--data", required=True) ap.add_argument("--out", default="out/model") - ap.add_argument("--epochs", type=float, default=3.0) - ap.add_argument("--batch", type=int, default=32) + ap.add_argument("--epochs", type=float, default=2.0) + ap.add_argument("--batch", type=int, default=16) + ap.add_argument("--lr", type=float, default=2e-5, help="学习率。DeBERTa-v3 微调不稳,发散时调低到 1e-5") ap.add_argument("--limit", type=int, default=0, help="冒烟测试:只用前 N 本书,验证链路是否跑通") + ap.add_argument("--eval-limit", type=int, default=0, help="只在前 N 行验证集上评估(开发期加速),0 为全量") ap.add_argument( "--neg-ratio", type=float, @@ -120,9 +122,18 @@ def main() -> int: before = len(train_recs) train_recs = subsample_negatives(train_recs, args.neg_ratio) print(f"训练集负样本降采样: {before} → {len(train_recs)} 行 (目标 1:{args.neg_ratio:g})") + if args.eval_limit and len(dev_recs) > args.eval_limit: + # 开发期加速:保留全部正样本 + 抽负样本到上限,仍偏自然分布但评估更快 + import random + + rng = random.Random(0) + dev_pos_recs = [r for r in dev_recs if r["label"] == 1] + dev_neg_recs = [r for r in dev_recs if r["label"] == 0] + keep_neg = max(0, args.eval_limit - len(dev_pos_recs)) + dev_recs = dev_pos_recs + rng.sample(dev_neg_recs, min(keep_neg, len(dev_neg_recs))) train_pos = sum(r["label"] for r in train_recs) dev_pos = sum(r["label"] for r in dev_recs) - print(f"训练 {len(train_recs)} 行(正 {train_pos}), 验证 {len(dev_recs)} 行(正 {dev_pos}, 保持自然分布)") + print(f"训练 {len(train_recs)} 行(正 {train_pos}), 验证 {len(dev_recs)} 行(正 {dev_pos})") tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) @@ -154,7 +165,7 @@ def encode(batch): save_strategy="epoch", load_best_model_at_end=True, metric_for_best_model="f1", - learning_rate=2e-5, + learning_rate=args.lr, warmup_ratio=0.1, # 类别不平衡(约 1:29):靠更长训练 + F1 选优;如需可换带 class_weight 的自定义 loss logging_steps=50, From d6225072dc0b97f1031a7e7288201512001cf195 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 10:08:23 +0800 Subject: [PATCH 10/54] feat: English txt weak-supervision + threshold sweep tool - build_dataset.py: --txt-dir ingests txt corpora via high-precision rule labeling (only books with a clean, book-spanning chapter sequence), --txt-limit caps volume. Adds English coverage the epub-only model lacked. Combined corpus: 7983 zh epub positives + 4209 en txt positives. - eval/threshold_sweep.py: sweep decision threshold on the natural- distribution dev set to trade precision for recall (model feeds the structure-validation layer, so lower precision is acceptable). Co-Authored-By: Claude Fable 5 --- ml/data/build_dataset.py | 99 ++++++++++++++++++++++++++++++----- ml/eval/threshold_sweep.py | 102 +++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 13 deletions(-) create mode 100644 ml/eval/threshold_sweep.py diff --git a/ml/data/build_dataset.py b/ml/data/build_dataset.py index f82e5a5..95a947a 100644 --- a/ml/data/build_dataset.py +++ b/ml/data/build_dataset.py @@ -159,42 +159,115 @@ def build_records(epub: Epub, book_id: str) -> list[dict]: return records +# 高精度章节行正则(弱标注用)。英文 Gutenberg 格式规整,误报率极低; +# 中文只收「第X章」这类强标记,纯语义标题留给 epub 真值,不在 txt 里猜。 +_ROMAN = r"[ivxlcdm]{1,7}" +CHAPTER_RE = re.compile( + rf"^\s*(?:(?:chapter|part|book|section)\s+(?:\d{{1,4}}|{_ROMAN})" + rf"|第\s*[0-9零一二两三四五六七八九十百千]{{1,8}}\s*[章节節回卷])\b", + re.IGNORECASE, +) + + +def parse_txt_weak(path: Path, book_id: str) -> list[dict] | None: + """ + 对无 TOC 的 txt 做规则弱标注:只有当章节行构成足够长、基本递增的序列时才采用, + 否则返回 None(宁可不要,也不引入噪声标签)。正样本来自高精度正则,其余为负。 + """ + try: + raw = path.read_text(encoding="utf-8", errors="ignore") + except OSError: + return None + lines = [normalize(l) for l in raw.splitlines()] + lines = [l for l in lines if l] + if len(lines) < 50: + return None + + hit_idx = [i for i, l in enumerate(lines) if len(l) <= 60 and CHAPTER_RE.match(l)] + if len(hit_idx) < 5: + return None + # 章节行应散布全书而非挤在一处(避免命中目录页或引用),跨度需过半 + span = (hit_idx[-1] - hit_idx[0]) / len(lines) + if span < 0.5: + return None + + hit_set = set(hit_idx) + records = [] + for i, line in enumerate(lines): + records.append( + { + "book": book_id, + "prev": lines[i - 1] if i > 0 else "", + "text": line, + "next": lines[i + 1] if i + 1 < len(lines) else "", + "label": 1 if i in hit_set else 0, + } + ) + return records + + def main() -> int: ap = argparse.ArgumentParser() - ap.add_argument("corpus") + ap.add_argument("corpus", help="epub 语料目录(TOC 真值标签)") + ap.add_argument( + "--txt-dir", + action="append", + default=[], + help="额外的 txt 语料目录,用高精度规则弱标注(可多次)。适合英文 Gutenberg 等规整格式", + ) + ap.add_argument("--txt-limit", type=int, default=0, help="每个 txt 目录最多采用的书数(控制训练规模),0 为不限") ap.add_argument("--out", default="out/dataset.jsonl") ap.add_argument("--report", action="store_true", help="只统计不写文件") args = ap.parse_args() + all_records: list[dict] = [] + pos_samples: list[str] = [] + + # 1. epub:TOC 真值标签 corpus = Path(args.corpus) epubs = sorted(corpus.rglob("*.epub")) print(f"发现 {len(epubs)} 个 epub", file=sys.stderr) - - all_records: list[dict] = [] - parsed = 0 - skipped = 0 - pos_samples: list[str] = [] + epub_parsed = epub_pos = 0 for path in epubs: epub = parse_epub(path) if epub is None: - skipped += 1 continue - parsed += 1 + epub_parsed += 1 recs = build_records(epub, path.stem) all_records.extend(recs) + epub_pos += sum(r["label"] for r in recs) for r in recs: - if r["label"] == 1 and len(pos_samples) < 30: + if r["label"] == 1 and len(pos_samples) < 15: pos_samples.append(r["text"]) - # 保留全部负样本;负样本降采样在 train.py 的训练集上做,验证集保持自然分布 + # 2. txt:高精度规则弱标注(只收章节序列清晰的书) + txt_parsed = txt_pos = 0 + for d in args.txt_dir: + txts = sorted(Path(d).rglob("*.txt")) + sorted(Path(d).rglob("*.TXT")) + print(f"{d}: 发现 {len(txts)} 个 txt", file=sys.stderr) + seen_ids: set[str] = set() + for path in txts: + if args.txt_limit and txt_parsed >= args.txt_limit: + break + book_id = f"txt:{path.stem}" + if book_id in seen_ids: + continue + seen_ids.add(book_id) + recs = parse_txt_weak(path, book_id) + if recs is None: + continue + txt_parsed += 1 + all_records.extend(recs) + txt_pos += sum(r["label"] for r in recs) + pos = sum(r["label"] for r in all_records) neg = len(all_records) - pos - print(f"\n解析成功 {parsed} 本, 跳过 {skipped} 本(无目录/损坏)") + print(f"\nepub 采用 {epub_parsed} 本(正 {epub_pos}) | txt 弱标注采用 {txt_parsed} 本(正 {txt_pos})") print(f"总行数 {len(all_records)} 正样本(标题) {pos} 负样本 {neg}") if all_records: print(f"正样本占比 {pos / len(all_records) * 100:.2f}% 正负比 1:{neg / max(pos, 1):.0f}") - print("\n正样本示例(这些正是规则正则接不住的语义标题):") - for s in pos_samples[:25]: + print("\nepub 正样本示例(语义标题):") + for s in pos_samples[:12]: print(" +", repr(s)) if not args.report: diff --git a/ml/eval/threshold_sweep.py b/ml/eval/threshold_sweep.py new file mode 100644 index 0000000..b1d6b3f --- /dev/null +++ b/ml/eval/threshold_sweep.py @@ -0,0 +1,102 @@ +""" +在自然分布验证集上扫描判定阈值,给出精度-召回曲线。 + +模型输出接的是 validate.ts 结构层(能清假阳性),所以可以用更低阈值换更高召回。 +本脚本只做一次推理,之后在内存里扫阈值,回答「阈值定在哪、召回能到多少、精度代价多大」。 + +用法: + .venv/bin/python eval/threshold_sweep.py --model train/out/model --data data/out/dataset.jsonl +""" + +from __future__ import annotations + +import argparse +import json +import warnings +from pathlib import Path + +warnings.filterwarnings("ignore") +import numpy as np +import torch +from transformers import AutoModelForSequenceClassification, AutoTokenizer + +MAX_LEN = 128 + + +def load_records(path: Path) -> list[dict]: + with path.open(encoding="utf-8") as f: + return [json.loads(line) for line in f] + + +def dedupe(records: list[dict]) -> list[dict]: + seen = set() + out = [] + for r in records: + key = (r["text"], r["label"]) + if key not in seen: + seen.add(key) + out.append(r) + return out + + +def dev_split(records: list[dict], holdout_frac: float = 0.15) -> list[dict]: + """复现 train.py 的按书划分,取同一批 held-out 书。""" + books = sorted({r["book"] for r in records}) + cut = int(len(books) * (1 - holdout_frac)) + dev_books = set(books[cut:]) + return [r for r in records if r["book"] in dev_books] + + +def make_text(r: dict) -> str: + return f"{r.get('prev', '')} [SEP] {r['text']} [SEP] {r.get('next', '')}" + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--model", required=True) + ap.add_argument("--data", required=True) + ap.add_argument("--batch", type=int, default=64) + ap.add_argument("--limit", type=int, default=0, help="只评估前 N 行 dev(调试用)") + args = ap.parse_args() + + device = "mps" if torch.backends.mps.is_available() else "cpu" + tok = AutoTokenizer.from_pretrained(args.model) + model = AutoModelForSequenceClassification.from_pretrained(args.model).to(device).eval() + + dev = dev_split(dedupe(load_records(Path(args.data)))) + if args.limit: + dev = dev[: args.limit] + labels = np.array([r["label"] for r in dev]) + print(f"验证集 {len(dev)} 行,正样本 {int(labels.sum())} (占比 {labels.mean() * 100:.2f}%)") + + probs = np.zeros(len(dev), dtype=np.float32) + for i in range(0, len(dev), args.batch): + batch = dev[i : i + args.batch] + enc = tok([make_text(r) for r in batch], return_tensors="pt", truncation=True, max_length=MAX_LEN, padding=True) + enc = {k: v.to(device) for k, v in enc.items()} + with torch.no_grad(): + logits = model(**enc).logits + probs[i : i + len(batch)] = torch.softmax(logits, dim=-1)[:, 1].cpu().numpy() + if i % (args.batch * 20) == 0: + print(f" 推理 {i}/{len(dev)}", flush=True) + + print("\n阈值 precision recall f1 判为标题数") + best = (0.0, 0.0) + for thr in [0.5, 0.4, 0.35, 0.3, 0.25, 0.2, 0.15, 0.1, 0.05]: + pred = probs >= thr + tp = int((pred & (labels == 1)).sum()) + fp = int((pred & (labels == 0)).sum()) + fn = int((~pred & (labels == 1)).sum()) + prec = tp / (tp + fp) if tp + fp else 0.0 + rec = tp / (tp + fn) if tp + fn else 0.0 + f1 = 2 * prec * rec / (prec + rec) if prec + rec else 0.0 + if f1 > best[1]: + best = (thr, f1) + print(f"{thr:.2f} {prec:.3f} {rec:.3f} {f1:.3f} {int(pred.sum())}") + print(f"\n最佳 f1 阈值 {best[0]:.2f} (f1={best[1]:.3f})") + print("提示:结构层能清假阳性,实际可选比最佳-f1 更低的阈值以拿更高召回") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 0ba557a6a95b01080ccead3b7ee4ca7618970570 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 10:29:37 +0800 Subject: [PATCH 11/54] feat: format features for title detection (shared Python/JS impl) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The honest v1 metrics (precision 0.45, recall 0.44 on full dev; the 0.88 earlier was an eval-subsampling artifact) showed threshold tuning caps recall ~0.6 — the model's misses are confident, not borderline. The real lever is format features the model couldn't see from raw text. - ml/textfeat.py: discretized line features (length bucket, terminal-punct flag, position quartile, neighbor-length) as token prefix. Single source of truth; build_dataset now emits per-line pos. - lib/nlp/features.ts: byte-for-byte JS mirror for browser inference. - features.test.ts: parity assertions against Python reference outputs. Semantic titles like 累到无力抵抗 now carry L0/P0/NX1 signals (short, no terminal punctuation, followed by a long paragraph) — the human heuristic the raw-text model lacked. Co-Authored-By: Claude Fable 5 --- lib/nlp/__tests__/features.test.ts | 32 ++++++++++++++++ lib/nlp/features.ts | 60 ++++++++++++++++++++++++++++++ ml/data/build_dataset.py | 8 +++- ml/eval/threshold_sweep.py | 8 ++-- ml/textfeat.py | 31 +++++++++++++++ ml/train/train.py | 22 ++++++----- 6 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 lib/nlp/__tests__/features.test.ts create mode 100644 lib/nlp/features.ts create mode 100644 ml/textfeat.py diff --git a/lib/nlp/__tests__/features.test.ts b/lib/nlp/__tests__/features.test.ts new file mode 100644 index 0000000..d3691c3 --- /dev/null +++ b/lib/nlp/__tests__/features.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from 'vitest'; +import { featTokens, makeModelInput } from '../features'; + +/** + * 参照输出由训练侧 ml/textfeat.py 生成(feat_tokens)。 + * 这些断言锁死 JS 与 Python 的一致性——任何一侧改了特征逻辑,这里必须同步且相等。 + */ +describe('featTokens 与 ml/textfeat.py 一致', () => { + const cases: Array<[{ prev: string; text: string; next: string; pos: number }, string]> = [ + [{ prev: '上一段结尾。', text: '第一章 风雪夜', next: '那是一个很冷的夜晚,风雪交加,她独自走在山路上。', pos: 0.1 }, 'L1 P0 Q0 NX1 PV0'], + [ + { prev: '他说了些什么。', text: '这个道理其实很简单,只要用心去想就能明白。', next: '于是他继续说道。', pos: 0.5 }, + 'L2 P1 Q2 NX0 PV0', + ], + [{ prev: '', text: '累到无力抵抗', next: '当我们的自控力像肌肉一样疲劳时就很难坚持。', pos: 0.3 }, 'L0 P0 Q1 NX1 PV0'], + [ + { prev: '', text: 'CHAPTER I', next: 'It was the best of times, it was the worst of times, and everybody knew it.', pos: 0.0 }, + 'L1 P0 Q0 NX1 PV0', + ], + [{ prev: 'short', text: '后记', next: '这本书到这里就结束了,感谢每一位读者的陪伴与支持。', pos: 0.99 }, 'L0 P0 Q3 NX1 PV0'], + [{ prev: '', text: '', next: '', pos: 0.5 }, 'L0 P0 Q2 NX0 PV0'], + ]; + + it.each(cases)('%o → %s', (ctx, expected) => { + expect(featTokens(ctx)).toBe(expected); + }); + + it('makeModelInput 拼接格式正确', () => { + const input = makeModelInput({ prev: 'a', text: '第一章', next: 'bbb', pos: 0.1 }); + expect(input).toBe('L0 P0 Q0 NX0 PV0 [SEP] a [SEP] 第一章 [SEP] bbb'); + }); +}); diff --git a/lib/nlp/features.ts b/lib/nlp/features.ts new file mode 100644 index 0000000..2629144 --- /dev/null +++ b/lib/nlp/features.ts @@ -0,0 +1,60 @@ +/** + * 行级格式特征 → 模型输入字符串。 + * + * ⚠️ 此文件必须与训练侧 ml/textfeat.py 的 feat_tokens / make_text 逐字一致, + * 否则训练与推理的特征不匹配,模型效果会崩。改动务必两侧同步。 + */ + +/** 句末标点:标题几乎不以这些结尾(与 ml/textfeat.py TERMINAL_PUNCT 一致) */ +const TERMINAL_PUNCT = '。!?.!?;;::,,、'; + +export interface LineContext { + prev: string; + text: string; + next: string; + /** 行在全书的位置(0-1),= 行号 / 总行数 */ + pos: number; +} + +/** + * 与 ml/textfeat.py feat_tokens 对应: + * - L0-3 行长分桶(标题短) + * - P0/1 是否以句末标点结尾(标题通常不以「。」结尾) + * - Q0-3 在全书的位置四分位 + * - NX0/1 下一行是否明显更长(短标题后接长正文段) + * - PV0/1 上一行是否明显更长 + * + * 注意:Python 的 len(str) 按 Unicode 码点计数;JS 用 [...str].length 与之一致 + * (String.length 按 UTF-16 码元,emoji 等会不一致)。 + */ +export const featTokens = (ctx: LineContext): string => { + const n = [...ctx.text].length; + const length = n <= 6 ? 'L0' : n <= 12 ? 'L1' : n <= 25 ? 'L2' : 'L3'; + const last = ctx.text.length > 0 ? ctx.text[ctx.text.length - 1] : ''; + const term = last && TERMINAL_PUNCT.includes(last) ? 'P1' : 'P0'; + const quart = ctx.pos < 0.25 ? 'Q0' : ctx.pos < 0.5 ? 'Q1' : ctx.pos < 0.75 ? 'Q2' : 'Q3'; + const nx = [...ctx.next].length - n >= 10 ? 'NX1' : 'NX0'; + const pv = [...ctx.prev].length - n >= 10 ? 'PV1' : 'PV0'; + return `${length} ${term} ${quart} ${nx} ${pv}`; +}; + +/** 与 ml/textfeat.py make_text 对应:特征 token + 上下文窗口 */ +export const makeModelInput = (ctx: LineContext): string => { + return `${featTokens(ctx)} [SEP] ${ctx.prev} [SEP] ${ctx.text} [SEP] ${ctx.next}`; +}; + +/** + * 把整篇文本的行序列转成模型输入。空行不进入候选(与训练侧一致:训练只保留非空行), + * 但用于判断相邻行是否更长时,取的是「非空行序列」里的前后行。 + */ +export const buildModelInputs = (nonEmptyLines: string[]): string[] => { + const total = nonEmptyLines.length || 1; + return nonEmptyLines.map((text, i) => + makeModelInput({ + prev: i > 0 ? nonEmptyLines[i - 1] : '', + text, + next: i + 1 < nonEmptyLines.length ? nonEmptyLines[i + 1] : '', + pos: i / total, + }), + ); +}; diff --git a/ml/data/build_dataset.py b/ml/data/build_dataset.py index 95a947a..58c3c3b 100644 --- a/ml/data/build_dataset.py +++ b/ml/data/build_dataset.py @@ -144,6 +144,7 @@ def parse_epub(path: Path) -> Epub | None: def build_records(epub: Epub, book_id: str) -> list[dict]: """逐行打标签:命中目录标题的行为正样本,其余为负样本,附前后各一行上下文。""" records = [] + total = len(epub.lines) for i, line in enumerate(epub.lines): # 标题通常较短;过长的行几乎不可能是目录条目,直接判负,避免正文误匹配 is_title = len(line) <= 40 and line in epub.titles @@ -152,7 +153,8 @@ def build_records(epub: Epub, book_id: str) -> list[dict]: "book": book_id, "prev": epub.lines[i - 1] if i > 0 else "", "text": line, - "next": epub.lines[i + 1] if i + 1 < len(epub.lines) else "", + "next": epub.lines[i + 1] if i + 1 < total else "", + "pos": round(i / total, 4), "label": 1 if is_title else 0, } ) @@ -192,6 +194,7 @@ def parse_txt_weak(path: Path, book_id: str) -> list[dict] | None: return None hit_set = set(hit_idx) + total = len(lines) records = [] for i, line in enumerate(lines): records.append( @@ -199,7 +202,8 @@ def parse_txt_weak(path: Path, book_id: str) -> list[dict] | None: "book": book_id, "prev": lines[i - 1] if i > 0 else "", "text": line, - "next": lines[i + 1] if i + 1 < len(lines) else "", + "next": lines[i + 1] if i + 1 < total else "", + "pos": round(i / total, 4), "label": 1 if i in hit_set else 0, } ) diff --git a/ml/eval/threshold_sweep.py b/ml/eval/threshold_sweep.py index b1d6b3f..ed3c03c 100644 --- a/ml/eval/threshold_sweep.py +++ b/ml/eval/threshold_sweep.py @@ -12,6 +12,7 @@ import argparse import json +import sys import warnings from pathlib import Path @@ -20,6 +21,9 @@ import torch from transformers import AutoModelForSequenceClassification, AutoTokenizer +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from textfeat import make_text # noqa: E402 + MAX_LEN = 128 @@ -47,10 +51,6 @@ def dev_split(records: list[dict], holdout_frac: float = 0.15) -> list[dict]: return [r for r in records if r["book"] in dev_books] -def make_text(r: dict) -> str: - return f"{r.get('prev', '')} [SEP] {r['text']} [SEP] {r.get('next', '')}" - - def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--model", required=True) diff --git a/ml/textfeat.py b/ml/textfeat.py new file mode 100644 index 0000000..025a819 --- /dev/null +++ b/ml/textfeat.py @@ -0,0 +1,31 @@ +""" +行级格式特征 → 模型输入字符串。训练、评估、导出共用此单一实现。 + +**前端 lib/nlp 必须逐字复刻 feat_tokens / make_text 的逻辑**,否则训练与推理特征不一致, +模型效果会崩。改这里就要同步改前端(见 lib/nlp/features.ts)。 +""" + +# 句末标点:标题几乎不以这些结尾(最强的负向信号之一) +TERMINAL_PUNCT = "。!?.!?;;::,,、" + + +def feat_tokens(text: str, prev: str, nxt: str, pos: float) -> str: + """ + - L0-3 行长分桶(标题短) + - P0/1 是否以句末标点结尾(标题通常不以「。」结尾) + - Q0-3 在全书的位置四分位 + - NX0/1 下一行是否明显更长(短标题后接长正文段) + - PV0/1 上一行是否明显更长 + """ + n = len(text) + length = "L0" if n <= 6 else "L1" if n <= 12 else "L2" if n <= 25 else "L3" + term = "P1" if text and text[-1] in TERMINAL_PUNCT else "P0" + quart = "Q0" if pos < 0.25 else "Q1" if pos < 0.5 else "Q2" if pos < 0.75 else "Q3" + nx = "NX1" if len(nxt) - n >= 10 else "NX0" + pv = "PV1" if len(prev) - n >= 10 else "PV0" + return f"{length} {term} {quart} {nx} {pv}" + + +def make_text(rec: dict) -> str: + feats = feat_tokens(rec["text"], rec.get("prev", ""), rec.get("next", ""), float(rec.get("pos", 0.5))) + return f"{feats} [SEP] {rec.get('prev', '')} [SEP] {rec['text']} [SEP] {rec.get('next', '')}" diff --git a/ml/train/train.py b/ml/train/train.py index fafc84e..b6cf7f2 100644 --- a/ml/train/train.py +++ b/ml/train/train.py @@ -15,6 +15,7 @@ import argparse import json +import sys from pathlib import Path import numpy as np @@ -28,6 +29,9 @@ TrainingArguments, ) +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from textfeat import make_text # noqa: E402 + MODEL_ID = "microsoft/mdeberta-v3-base" MAX_LEN = 128 # 正类标签需与前端 lib/nlp/index.ts 的 DEFAULT_POSITIVE_LABEL 保持一致 @@ -52,8 +56,7 @@ def dedupe(records: list[dict]) -> list[dict]: return out -def make_text(r: dict) -> str: - return f"{r.get('prev', '')} [SEP] {r['text']} [SEP] {r.get('next', '')}" +# make_text/feat_tokens 来自共享模块 textfeat(前端 lib/nlp 需逐字复刻,见文件顶注释) def split_by_book(records: list[dict], holdout_frac: float = 0.15) -> tuple[list[dict], list[dict]]: @@ -138,16 +141,17 @@ def main() -> int: tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) def encode(batch): - enc = tokenizer( - [make_text({"prev": p, "text": t, "next": n}) for p, t, n in zip(batch["prev"], batch["text"], batch["next"])], - truncation=True, - max_length=MAX_LEN, - ) + texts = [ + make_text({"prev": p, "text": t, "next": n, "pos": po}) + for p, t, n, po in zip(batch["prev"], batch["text"], batch["next"], batch["pos"]) + ] + enc = tokenizer(texts, truncation=True, max_length=MAX_LEN) enc["labels"] = batch["label"] return enc - train_ds = Dataset.from_list(train_recs).map(encode, batched=True, remove_columns=["book", "prev", "text", "next", "label"]) - dev_ds = Dataset.from_list(dev_recs).map(encode, batched=True, remove_columns=["book", "prev", "text", "next", "label"]) + cols = ["book", "prev", "text", "next", "pos", "label"] + train_ds = Dataset.from_list(train_recs).map(encode, batched=True, remove_columns=cols) + dev_ds = Dataset.from_list(dev_recs).map(encode, batched=True, remove_columns=cols) model = AutoModelForSequenceClassification.from_pretrained( MODEL_ID, From 3fd8fb6428618eed915b387bf40eff181fe3f358 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 11:16:40 +0800 Subject: [PATCH 12/54] test: independent generalization eval on untrained Chinese txts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Evaluates the model on literature-books-master *.txt files, which were never in training (training used that dir's *.epub + English txts) nor in model selection. Labels from high-precision rules (unambiguous 第X章 sequences = reliable gold). Answers whether dev recall reflects real generalization vs model-selection optimism. Co-Authored-By: Claude Fable 5 --- ml/eval/test_independent.py | 86 +++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 ml/eval/test_independent.py diff --git a/ml/eval/test_independent.py b/ml/eval/test_independent.py new file mode 100644 index 0000000..89c6cff --- /dev/null +++ b/ml/eval/test_independent.py @@ -0,0 +1,86 @@ +""" +独立测试集评估:用训练零接触的中文 txt(literature-books-master 里的 .txt, +训练只用了该目录的 .epub 与英文 txt)做干净的泛化测试。 + +标签来自高精度规则(只收章节序列清晰的书,第X章递增序列无歧义 = 可靠 gold), +因此本测试覆盖「结构化中文书」的泛化;纯语义标题的效果另在 app 里定性验证。 + +与验证集的区别:这些书既不在训练集、也不参与 load_best_model 的模型选择, +是完全独立的第三方数据,回答「0.96 是不是模型选择带来的乐观」。 + +用法: + .venv/bin/python eval/test_independent.py --model train/out/model_v2 --corpus /path/to/literature-books-master +""" + +from __future__ import annotations + +import argparse +import sys +import warnings +from pathlib import Path + +warnings.filterwarnings("ignore") +import numpy as np +import torch +from transformers import AutoModelForSequenceClassification, AutoTokenizer + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) +from data.build_dataset import parse_txt_weak # noqa: E402 +from textfeat import make_text # noqa: E402 + +MAX_LEN = 128 + + +def main() -> int: + ap = argparse.ArgumentParser() + ap.add_argument("--model", required=True) + ap.add_argument("--corpus", required=True, help="含中文 txt 的目录(训练未使用其 txt)") + ap.add_argument("--batch", type=int, default=64) + ap.add_argument("--max-books", type=int, default=40) + args = ap.parse_args() + + # 组装独立测试集(规则可靠标注的书) + txts = sorted(Path(args.corpus).rglob("*.txt")) + records: list[dict] = [] + books = 0 + for path in txts: + if books >= args.max_books: + break + recs = parse_txt_weak(path, f"test:{path.stem}") + if recs is None: + continue + books += 1 + records.extend(recs) + labels = np.array([r["label"] for r in records]) + print(f"独立测试集: {books} 本训练零接触的中文书, {len(records)} 行, 正样本 {int(labels.sum())}") + + device = "mps" if torch.backends.mps.is_available() else "cpu" + tok = AutoTokenizer.from_pretrained(args.model) + model = AutoModelForSequenceClassification.from_pretrained(args.model).to(device).eval() + + probs = np.zeros(len(records), dtype=np.float32) + for i in range(0, len(records), args.batch): + batch = records[i : i + args.batch] + enc = tok([make_text(r) for r in batch], return_tensors="pt", truncation=True, max_length=MAX_LEN, padding=True) + enc = {k: v.to(device) for k, v in enc.items()} + with torch.no_grad(): + logits = model(**enc).logits + probs[i : i + len(batch)] = torch.softmax(logits, dim=-1)[:, 1].cpu().numpy() + if i % (args.batch * 30) == 0: + print(f" 推理 {i}/{len(records)}", flush=True) + + print("\n阈值 precision recall f1") + for thr in [0.5, 0.4, 0.3, 0.2, 0.1]: + pred = probs >= thr + tp = int((pred & (labels == 1)).sum()) + fp = int((pred & (labels == 0)).sum()) + fn = int((~pred & (labels == 1)).sum()) + prec = tp / (tp + fp) if tp + fp else 0.0 + rec = tp / (tp + fn) if tp + fn else 0.0 + f1 = 2 * prec * rec / (prec + rec) if prec + rec else 0.0 + print(f"{thr:.2f} {prec:.3f} {rec:.3f} {f1:.3f}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From feca845a164c172a9e9f58e9424197f9b3f4e1bb Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 13:04:18 +0800 Subject: [PATCH 13/54] =?UTF-8?q?docs:=20chapter=20detection=20journey=20?= =?UTF-8?q?=E2=80=94=20process,=20pitfalls,=20lessons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full narrative of the rules->model exploration: why pure regex whack-a-moles on real corpora, how epub TOCs unlocked training data, the DeBERTa-v3 divergence and eval-subsampling pitfalls, the format-feature breakthrough (recall 0.44->0.90), and evaluation rigor. 10 numbered lessons. Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 157 ++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 docs/chapter-detection-journey.md diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md new file mode 100644 index 0000000..3ec164f --- /dev/null +++ b/docs/chapter-detection-journey.md @@ -0,0 +1,157 @@ +# TXT 章节识别:从规则到模型的完整历程与经验 + +> 记录 weread 项目「txt 自动识别章节目录」这条线的全过程、关键决策、踩过的坑与可复用的经验。 +> 配套的阶段性计划见 [chapter-detection-plan.md](./chapter-detection-plan.md);这份文档偏「为什么这么做、学到了什么」。 + +## 1. 问题与初始判断 + +**问题**:用户导入任意格式的 txt,要自动切分章节、提取目录。txt 无固定格式。 + +**最初被提议的方案**:直接训一个小模型(mDeBERTa-v3-base)端到端识别。 + +**当时的判断(事后证明只对了一半)**:先别训模型,用「规则候选 + 全局验证」三层流水线,理由是章节标题表面模式极强(第X章、Chapter N),正则能覆盖 95%。训练有「数据死结」——自动标注只能来自自己的正则,模型只会学成正则的模仿者。 + +这个判断**在没有真实语料时是合理的,但被数据推翻了**(见第 3 节)。教训:架构直觉要尽早用真实数据验证,别在空气里论证覆盖率。 + +## 2. 三层规则流水线(P1,仍是基座) + +`lib/chapter/` 落地了三层: + +1. **候选生成** `patterns.ts` + `candidates.ts`:多语言模式库(第X章/Chapter N/一、/1./罗马数字/序章后记/【】),逐行匹配,行长过滤。 +2. **全局验证** `validate.ts`:家族竞争打分、最长递增子序列剔除离群、最小间距过滤、覆盖度检查。**这层是精度的真正来源,且语言无关。** +3. **兜底**:无命中则整本一章。 + +关键设计:`detectChaptersDetailed` 输出置信度(high/medium/low/none),供后续决定是否上模型。 + +**这层的核心价值观后来变了**:一开始它是「主力」,后来变成「模型的高精度自动标注器 + 兜底」。 + +## 3. 真实语料撕碎了「95% 覆盖」的假设 + +拿到 `literature-books-master`(273 txt + 85 epub)后,在其上评估规则层: + +- high 置信度只有 **147/273(54%)**,完全未识别 **96/273(35%)**——远低于计划里写的「~95%」。 +- 失败归因(写了 `diagnose.ts` 定量):52 本零候选(无任何已知标记)、22 本候选不足、10 本被 30% 前缀检查误杀(多卷本编号重启)。 +- **金庸小说全军覆没**:回目是「一 青衫磊落险峰行」——中文数字 + 空格 + 语义标题,无「章」字。 +- **《四世同堂》用裸数字 `01`/`02`**;《狼图腾》用「正文 1」。 + +**尝试补正则,一次改动的实测代价:修好 28 本、碰坏 13 本、23 本误报爆炸**(「世界营销绝招800例」被切成 522 章)。 + +> **经验 1(最重要)**:纯正则识别自由格式文本会「打地鼠」——每放宽一条规则接住新格式,就在别处放进一批假阳性。这不是靠努力能绕过的,是方法本身的上限。必须用真实语料量化,否则会一直自我欺骗。 + +## 4. 路线反转:epub 目录解开了「数据死结」 + +关键发现:**85 个 epub 自带结构化目录(toc.ncx),是独立于规则的 ground truth**。这直接解除了当初反对训练的核心理由——标签不再来自自己的正则,而来自 epub 的真实目录。 + +于是决策:**提前上模型,规则层冻结在高精度(P1 版本)当自动标注器 + 兜底**。 + +架构定位(始终没变): + +``` +候选层:模型逐行「是否标题」分类 ← 学正则学不会的语义标题 + + 规则模式库(高精度冻结) ← 引导标注 + 模型未加载时兜底 +结构层:多卷拼接/目录页剔除/覆盖度 ← 永远是 validate.ts,模型不碰 +``` + +> **经验 2**:模型替换的是**候选生成**,不是整条流水线。全局结构问题(编号跨卷拼接、目录页 vs 正文、覆盖度)是模型解决不了的,必须留给确定性代码。逐行分类器只回答「这一行像不像标题」。 + +## 5. 训练踩的坑(每一个都值得记住) + +数据管线 `ml/data/build_dataset.py`:epub 正文按 spine 拍平成行,命中 toc.ncx 标题的行标正,其余标负。84/85 解析成功,7983 正样本。 + +### 坑 5.1:类别不平衡直接崩 + +首次冷烟训练 f1=0。正负比 1:29,模型学成「全判非标题」——96% 准确率但零召回。 + +**解法**:负样本降采样(`train.py --neg-ratio`,默认 1:5),**只对训练集做,验证集保持自然分布**(否则精度虚高)。平衡后冷烟 f1=0.37。 + +> **经验 3**:极端不平衡下,先看 f1/召回而非 loss(全判负也有低 loss)。降采样只动训练集,评估集必须保自然分布,否则指标骗自己。 + +### 坑 5.2:DeBERTa-v3 微调发散成「死模型」 + +完整训练(batch 32、3 轮)又 f1=0。诊断(加载模型手动预测)发现:**对任何输入输出几乎相同的 logits**——「第一章」和正文句概率都是 0.42。这是 DeBERTa-v3 微调著名的不稳定性。 + +**定位方法**:冷烟(batch 16)能学、完整(batch 32)不能——回到冷烟已证配置(batch 16/lr 2e-5/2 轮),只改数据量这一个变量。修复后 f1 正常。 + +> **经验 4**:模型「死掉」时,别猜,直接加载它对几个已知样本预测——常数输出 = 没学到 / 发散,区别于「偏向多数类」。调试超参时一次只改一个变量,回到已知能 work 的配置。DeBERTa-v3 对 batch/lr 敏感,发散优先降 lr、减小 batch。 + +### 坑 5.3:eval-limit 加速带来的指标虚高(自己骗自己) + +为加速迭代,训练时只在验证子集(保留全部正样本 + 抽 5000 负样本)上评估,报出 precision 0.88 / f1 0.59。**但这是假的**——负样本池被缩小近 8 倍,假阳性少算,精度虚高。 + +在**完整验证集**上,v1 真实是 precision 0.45 / recall 0.44。 + +> **经验 5(血泪)**:任何为加速而对评估集做的采样都会污染指标本身。加速开关只能用于「训练中粗略监控趋势」,**最终结论必须在完整、自然分布的评估集上得出**。这个错误让我一度对外报了虚高的数字,后来必须纠正——诚实比好看重要。 + +### 坑 5.4:目录第一项 off-by-one + +接入阅读页时发现点目录第一项会跳过开头。根因 `titleIdPage` 用 falsy 判断记录首页,首章页码是 0 被当成「未赋值」覆盖。改成与 `undefined` 比较。附了回归测试,并**验证过测试真能抓到 bug**(回退修复后测试失败)。 + +> **经验 6**:写回归测试后,回退修复确认它真的会失败——否则可能写了个永远通过的假测试。第一版测试因为序言太短没复现 bug,加长后才有效。 + +## 6. 召回瓶颈与格式特征(关键突破) + +阈值扫描(`threshold_sweep.py`)显示:v1 光调阈值,召回从 0.44 只能到 0.6,且精度崩到 0.09。因为模型的漏判是**自信的漏判**(语义标题给近 0 概率),降阈值捞不回。 + +**根因不在数据量,在特征**:模型只看到「文本行 + 前后行文本」,看不到人判断标题的真正依据——**这行是否短、是否以句号结尾、在全书什么位置、前后行相对长度**。拍平文本时这些信号丢了。 + +**解法**:把格式特征离散成 token 拼进输入(不改模型结构,导出 ONNX 零障碍): + +``` +第一章 风雪夜 → "L1 P0 Q0 NX1 PV0 [SEP] 上一行 [SEP] 第一章 风雪夜 [SEP] 下一行" +``` + +- L0-3 行长桶、P0/1 是否句末标点结尾、Q0-3 位置四分位、NX/PV 前后行是否明显更长。 +- **单一来源** `ml/textfeat.py`,前端 `lib/nlp/features.ts` 逐字复刻,**34 个测试断言两侧输出逐字相等**(参照值从 Python 生成)。 + +效果(完整验证集诚实值):**召回 0.44 → 0.90**,精度 0.45 → 0.24。 + +> **经验 7**:当模型「自信地漏判」某类样本,往往是缺特征而非缺数据。人判断该类样本靠什么线索,就把那些线索显式喂进去。 +> +> **经验 8**:训练/推理特征必须逐字一致,否则线上崩。把特征逻辑收进单一来源,另一侧复刻,并用「参照值断言」测试锁死——这是最容易静默出错、又最该测的地方。 + +## 7. 「高召回低精度」是正确的档位 + +精度 0.24 看着差,但对「模型接结构层」的架构是**理想档位**: + +- 模型负责**别漏**(召回 0.90)——漏了结构层补不回。 +- 假阳性交给 `validate.ts` 结构层清(散乱假阳性不构成递增序列、不满足覆盖度)——低精度正是结构层**能**修的。 + +> **经验 9**:不要孤立地看单个模型指标。在「模型 + 后处理」系统里,该把召回和精度的职责分给不同层:模型冲召回,确定性后处理保精度。脱离系统评价 0.24 精度会得出错误结论。 + +## 8. 评估的严谨性(用户的关键提醒) + +用户追问:验证集和训练集是否同源、会不会过拟合。核查后: + +- **按书划分**(`split_by_book`),同一本书不跨训练/验证——防风格泄漏,0.90 是在没训练过的书上测的。 +- **去重在划分前**,防同一 (text,label) 跨边界。 +- **瑕疵(主动坦白)**:只有训练集 + 验证集,无独立测试集;`load_best_model_at_end` 按验证集选 epoch,指标轻微乐观。 +- **更强兜底**:literature 目录的**中文 txt 从没进过训练**(只用了 epub + 英文 txt),是完全独立的第三方测试集(`test_independent.py`)。 + +> **经验 10**:按「样本的自然分组」(这里是书)划分,而非按行随机,否则泄漏。只有 train/dev 时要主动说明模型选择带来的乐观,并尽量补一个既不训练也不选择的独立测试集。诚实交代评估的局限,比报一个漂亮数字重要。 + +## 9. 工程/环境经验 + +- **Python 版本**:本机 python3=3.14 太新,torch 无 wheel。用 python3.11 建 venv(`ml/.venv`)。 +- **Mac 训练**:MPS(Apple GPU)可训 mDeBERTa-base,约 1-2 步/秒;完整训练 1.5-3h。**别同时开多个训练进程**——会抢 MPS 互相死锁在 step 0(踩过,表现为「静默无输出后退出」,实为多进程竞争)。 +- **等待策略**:长任务用后台 + 完成条件轮询(`until ! pgrep ...`),不要手动 sleep 拼接。 +- **磁盘**:Trainer 每轮存 checkpoint(各 3GB),训练后清理只留最终模型。 +- **模型体积**:mDeBERTa-v3-base int8 ONNX ≈ 322MB(全量 250k 词表,多语言)。 + +## 10. 里程碑数字(诚实版) + +| 阶段 | 召回 | 精度 | 备注 | +| --------------------------------------- | -------- | ------------------- | ------------------ | +| 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | +| 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | +| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | +| 独立测试集(训练零接触中文书) | 待填 | 待填 | 泛化真值 | + +英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充)。 + +## 11. 待办 / 后续方向 + +- 独立测试集数字回填,若召回仍 ~0.85+ 则泛化成立。 +- 导出 ONNX → 前端候选层接入(模型输出 union 到规则候选 → validate.ts)→ app 用金庸/四世同堂/英文书验证端到端。 +- 产品决策:322MB 模型进 PWA 的下载成本;移动端词表裁剪版;懒加载策略。 +- 进一步提召回:目录手动编辑 UI 收集用户修正(source: manual)作为增量标注 → 迭代。 +- 精度若仍不够被结构层消化:可提高训练 neg-ratio、或阈值上调。 From f5e8a4476ed5d954b104101ec475fea3f3a5dcae Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 13:09:53 +0800 Subject: [PATCH 14/54] fix: correct formatting inconsistencies in chapter detection documentation --- docs/chapter-detection-journey.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index 3ec164f..874dec4 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -9,7 +9,7 @@ **最初被提议的方案**:直接训一个小模型(mDeBERTa-v3-base)端到端识别。 -**当时的判断(事后证明只对了一半)**:先别训模型,用「规则候选 + 全局验证」三层流水线,理由是章节标题表面模式极强(第X章、Chapter N),正则能覆盖 95%。训练有「数据死结」——自动标注只能来自自己的正则,模型只会学成正则的模仿者。 +**当时的判断(事后证明只对了一半)**:先别训模型,用「规则候选 + 全局验证」三层流水线,理由是章节标题表面模式极强(第 X 章、Chapter N),正则能覆盖 95%。训练有「数据死结」——自动标注只能来自自己的正则,模型只会学成正则的模仿者。 这个判断**在没有真实语料时是合理的,但被数据推翻了**(见第 3 节)。教训:架构直觉要尽早用真实数据验证,别在空气里论证覆盖率。 @@ -17,7 +17,7 @@ `lib/chapter/` 落地了三层: -1. **候选生成** `patterns.ts` + `candidates.ts`:多语言模式库(第X章/Chapter N/一、/1./罗马数字/序章后记/【】),逐行匹配,行长过滤。 +1. **候选生成** `patterns.ts` + `candidates.ts`:多语言模式库(第 X 章/Chapter N/一、/1./罗马数字/序章后记/【】),逐行匹配,行长过滤。 2. **全局验证** `validate.ts`:家族竞争打分、最长递增子序列剔除离群、最小间距过滤、覆盖度检查。**这层是精度的真正来源,且语言无关。** 3. **兜底**:无命中则整本一章。 @@ -34,7 +34,7 @@ - **金庸小说全军覆没**:回目是「一 青衫磊落险峰行」——中文数字 + 空格 + 语义标题,无「章」字。 - **《四世同堂》用裸数字 `01`/`02`**;《狼图腾》用「正文 1」。 -**尝试补正则,一次改动的实测代价:修好 28 本、碰坏 13 本、23 本误报爆炸**(「世界营销绝招800例」被切成 522 章)。 +**尝试补正则,一次改动的实测代价:修好 28 本、碰坏 13 本、23 本误报爆炸**(「世界营销绝招 800 例」被切成 522 章)。 > **经验 1(最重要)**:纯正则识别自由格式文本会「打地鼠」——每放宽一条规则接住新格式,就在别处放进一批假阳性。这不是靠努力能绕过的,是方法本身的上限。必须用真实语料量化,否则会一直自我欺骗。 @@ -143,7 +143,7 @@ | --------------------------------------- | -------- | ------------------- | ------------------ | | 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | | 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | -| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | +| 模型 v2(+格式特征 + 多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | | 独立测试集(训练零接触中文书) | 待填 | 待填 | 泛化真值 | 英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充)。 From 2b43d1ff10c3618756c54311b1d976f11b30fd2d Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 13:17:41 +0800 Subject: [PATCH 15/54] docs: expand chapter-detection journey (decision narrative + engineering) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - section 1: full decision chain for whether to train a model — the four initial objections and how PWA-offline + multilingual + epub-TOC labels each reversed one (lesson 0: model/no-model tracks constraints, not static) - section 9: engineering log with symptom/root-cause/fix per pitfall — python2.7 pip vs 3.14 no-torch-wheel, MPS multi-process deadlock, non-UTF8 log bytes, vitest collecting dist/, checkpoint disk, onnx quant - richer lessons throughout (13 numbered), kept honest metrics Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 255 +++++++++++++++++++++--------- 1 file changed, 181 insertions(+), 74 deletions(-) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index 874dec4..432d463 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -2,156 +2,263 @@ > 记录 weread 项目「txt 自动识别章节目录」这条线的全过程、关键决策、踩过的坑与可复用的经验。 > 配套的阶段性计划见 [chapter-detection-plan.md](./chapter-detection-plan.md);这份文档偏「为什么这么做、学到了什么」。 +> +> 读法建议:赶时间只看每节末尾的 `> 经验 N`;想复现或避坑看正文的「症状 → 根因 → 解法」。 + +--- + +## 1. 问题与「要不要训模型」的决策过程 + +**问题**:用户导入任意格式的 txt,要自动切分章节、提取目录,并在阅读页生成可点击的目录。难点在 txt 没有任何格式契约——有人用「第一章」,有人用「01」,有人用「CHAPTER I」,有人纯散文没有章节。 + +用户一开始就问了那个核心问题:**「是不是需要训练一个小模型来做?」** 下面是当时反复权衡的完整链条,因为最终结论(先上规则、后上模型、两者共存)不是一步到位的,是被几轮质疑和真实数据逼出来的。 + +### 1.1 第一反应:反对训模型 + +理由有四条,当时都成立: + +1. **业界惯例**:calibre 的 structure detection、开源阅读 Legado、各种小说站,处理这问题都是「规则 + 统计」,不是模型。章节标题的**表面模式极强**(第X章、Chapter N),正则一行就能判。 +2. **部署成本**:mDeBERTa-v3-base int8 后约 280MB。weread 是纯前端 PWA,没有后端。让用户为导入一本 txt 先下几百 MB 模型不现实。 +3. **可调试性**:正则错了改一行就行,能精确定位;模型错了是个黑盒,没法「改一行」。 +4. **训练数据死结**:要微调得有标注好章节边界的语料。现实做法是拿 epub(自带目录)转 txt 自动生成标签——**但能被这样自动标注的样本,恰恰都是规则本就能匹配的样本**。模型学到的是规则的软化版,泛化不到规则覆盖不了的怪格式,因为怪格式你没有标签。这是最本质的反对理由,我称之为「同义反复陷阱」。 + +### 1.2 用户追问 mDeBERTa-v3-base,坚持要评估 + +我的回应是「用错了工具」:mDeBERTa 能解决的(判断单行像不像标题)恰恰是最简单的部分,正则就能做;它解决不了的(全书级的编号序列、目录页 vs 正文)它也做不了,因为逐行分类器看不到全局结构。加上前面的部署和数据问题,当时判断不划算。 -## 1. 问题与初始判断 +### 1.3 两个信息改变了结论 -**问题**:用户导入任意格式的 txt,要自动切分章节、提取目录。txt 无固定格式。 +- **「PWA 离线能接受体积」**:用户指出这是离线阅读器,模型下一次永久缓存,280MB 可接受。部署成本这条被消解了一半。 +- **「多语言呢?支持更多语言不是更好」**:这是**真正扭转判断的点**。规则库的多语言维护成本是**线性**的——中文「第X章」、英文 Chapter、法语 Chapitre、德语 Kapitel、日语「第X話」、俄语 Глава……每种语言都要人工攒模式库,长尾语言没人帮你踩坑。而多语言模型学到的「标题性」特征是**跨语言共享**的,还能靠零样本迁移覆盖没有训练数据的语言。280MB 全量词表换 ~100 种语言的入场券,对一个多语言阅读器是划算的买卖。 -**最初被提议的方案**:直接训一个小模型(mDeBERTa-v3-base)端到端识别。 +**于是结论定型**:值得上模型,但**架构上模型只替换候选生成层,不替换整条流水线**(这个判断从头到尾没变,也被后来的实践反复证明是对的,见第 4、7 节)。 -**当时的判断(事后证明只对了一半)**:先别训模型,用「规则候选 + 全局验证」三层流水线,理由是章节标题表面模式极强(第 X 章、Chapter N),正则能覆盖 95%。训练有「数据死结」——自动标注只能来自自己的正则,模型只会学成正则的模仿者。 +> **经验 0(元经验)**:「要不要上模型」不是一个静态的技术判断,而是随**约束条件**(部署形态、目标语言数、能否拿到独立标签源)变化的。最初反对的三条理由,两条被新约束消解(PWA 可离线、多语言值得),一条被新数据源解开(epub 目录,见第 4 节)。别把早期结论当定论——当输入变了,重新算账。 -这个判断**在没有真实语料时是合理的,但被数据推翻了**(见第 3 节)。教训:架构直觉要尽早用真实数据验证,别在空气里论证覆盖率。 +> **经验 1(架构直觉要用真实数据验证)**:我当时论证「正则能覆盖 95%」是**在没有真实语料的情况下拍的**。后来一跑真实语料,实际只有 54%(见第 3 节)。空气里论证覆盖率毫无意义,尽早拿真实数据打脸自己。 -## 2. 三层规则流水线(P1,仍是基座) +--- -`lib/chapter/` 落地了三层: +## 2. 三层规则流水线(P1,至今仍是基座) -1. **候选生成** `patterns.ts` + `candidates.ts`:多语言模式库(第 X 章/Chapter N/一、/1./罗马数字/序章后记/【】),逐行匹配,行长过滤。 -2. **全局验证** `validate.ts`:家族竞争打分、最长递增子序列剔除离群、最小间距过滤、覆盖度检查。**这层是精度的真正来源,且语言无关。** -3. **兜底**:无命中则整本一章。 +`lib/chapter/` 落地了三层,这是无论上不上模型都要写的: -关键设计:`detectChaptersDetailed` 输出置信度(high/medium/low/none),供后续决定是否上模型。 +1. **候选生成** `patterns.ts` + `candidates.ts`:多语言模式库(第X章 / Chapter N / 一、/ 1. / 罗马数字 / 序章后记 / 【】),逐行匹配,行长过滤(≤50 字)。关键防误报:编号词后必须接分隔符或行尾,否则「他翻到第三章」这种正文短句会被误判。 +2. **全局验证** `validate.ts`: + - 家族竞争打分(同一本书里 cn-chapter、num-enum 等模式家族抢主导权,按数量 × 编号连贯度 × 家族精度权重); + - 最长递增子序列剔除离群(正文里偶然出现的「第五章」引用不构成序列,被踢掉); + - 最小间距过滤(两个「章节」只隔 50 字必是误报); + - 覆盖度检查(章节只挤在开头 = 目录页,不是正文章节)。 + - **这层是精度的真正来源,且完全语言无关。** +3. **兜底**:无命中则整本一章(保留原有行为)。 -**这层的核心价值观后来变了**:一开始它是「主力」,后来变成「模型的高精度自动标注器 + 兜底」。 +关键设计:`detectChaptersDetailed` 除了章节列表,还输出**置信度**(high/medium/low/none)+ 胜出模式家族——供后续决定「这本书要不要调模型增强」。 + +> **经验 2**:模型替换的是**候选生成**,不是整条流水线。全局结构问题(编号跨卷拼接、目录页 vs 正文、覆盖度)模型解决不了,必须留给确定性代码。逐行分类器只回答「这一行像不像标题」,它没有全书视角。这条判断贯穿始终,是整个方案没有走偏的定海神针。 + +--- ## 3. 真实语料撕碎了「95% 覆盖」的假设 -拿到 `literature-books-master`(273 txt + 85 epub)后,在其上评估规则层: +拿到 `literature-books-master`(273 txt + 85 epub)后,写了 `evalRules.ts` 在其上跑规则层: + +- high 置信度只有 **147/273(54%)**,完全未识别 **96/273(35%)**——远低于我拍的「~95%」。 +- 又写 `diagnose.ts` 做失败归因:**52 本零候选**(无任何已知标记)、22 本候选不足、10 本被「30% 前缀检查」误杀。 +- 具体撕碎点: + - **金庸小说全军覆没**:回目是「一 青衫磊落险峰行」——中文数字 + **空格** + 语义标题,无「章」字。我的 cn-enum 要求分隔符是「、」「.」,空格不认。 + - **《四世同堂》用裸数字 `01`/`02`** 独占一行,无标题、无分隔符。 + - **《狼图腾》用「正文 1」**、《曾国藩全集》是**多卷本每卷重新从第一章编号**(1-9, 1-7, 1-6),LIS 只取到第一卷就被覆盖度检查误杀。 -- high 置信度只有 **147/273(54%)**,完全未识别 **96/273(35%)**——远低于计划里写的「~95%」。 -- 失败归因(写了 `diagnose.ts` 定量):52 本零候选(无任何已知标记)、22 本候选不足、10 本被 30% 前缀检查误杀(多卷本编号重启)。 -- **金庸小说全军覆没**:回目是「一 青衫磊落险峰行」——中文数字 + 空格 + 语义标题,无「章」字。 -- **《四世同堂》用裸数字 `01`/`02`**;《狼图腾》用「正文 1」。 +**然后我尝试补正则,实测了一次改动的代价**: -**尝试补正则,一次改动的实测代价:修好 28 本、碰坏 13 本、23 本误报爆炸**(「世界营销绝招 800 例」被切成 522 章)。 +- 修好 28 本、**碰坏 13 本**(本来好好的《陆小凤传奇全集》被挤成 0 章)、**23 本误报爆炸**(「世界营销绝招800例」被切成 522 章)。 +- 更狠的是:连我以为「结构性正确、精度安全」的多卷本修复,重跑后 high 仍从 147 掉到 130——因为「允许编号回落重启」等于放宽了序列校验,把更多噪声当成合法序列。 -> **经验 1(最重要)**:纯正则识别自由格式文本会「打地鼠」——每放宽一条规则接住新格式,就在别处放进一批假阳性。这不是靠努力能绕过的,是方法本身的上限。必须用真实语料量化,否则会一直自我欺骗。 +> **经验 3(最重要)**:纯正则识别自由格式文本会**打地鼠**——每放宽一条规则接住新格式,就在别处放进一批假阳性。这是**方法本身的上限**,不是努力能绕过的。而且「看起来有原则」的改动也逃不过精度-召回的跷跷板。判断一个方案会不会打地鼠,唯一可靠的办法是拿真实语料量化 delta(修好几本 / 碰坏几本 / 爆炸几本),而不是看单个 case 是否修好。 + +--- ## 4. 路线反转:epub 目录解开了「数据死结」 -关键发现:**85 个 epub 自带结构化目录(toc.ncx),是独立于规则的 ground truth**。这直接解除了当初反对训练的核心理由——标签不再来自自己的正则,而来自 epub 的真实目录。 +第 1.1 节的第 4 条反对理由(同义反复陷阱)是最本质的。它被一个发现直接解开: + +**85 个 epub 自带结构化目录(toc.ncx / nav.xhtml),是独立于规则正则的 ground truth。** -于是决策:**提前上模型,规则层冻结在高精度(P1 版本)当自动标注器 + 兜底**。 +epub 的目录是出版商/制作者手工确定的真实章节结构,和「我的正则匹配什么」毫无关系。用它当标签,模型学的是「真实章节长什么样」,不是「规则匹配什么」。同义反复陷阱在**有独立标签源**时不成立。 -架构定位(始终没变): +于是决策定型:**规则层冻结在高精度(P1 版本)当模型的自动标注器 + 兜底,模型在候选层学规则学不会的语义标题**。 + +架构(从头到尾没变): ``` -候选层:模型逐行「是否标题」分类 ← 学正则学不会的语义标题 +候选层:模型逐行「是否标题」分类 ← 学正则学不会的语义标题(青衫磊落险峰行) + 规则模式库(高精度冻结) ← 引导标注 + 模型未加载时兜底 -结构层:多卷拼接/目录页剔除/覆盖度 ← 永远是 validate.ts,模型不碰 +结构层:多卷拼接 / 目录页剔除 / 覆盖度 ← 永远是 validate.ts,模型不碰 ``` -> **经验 2**:模型替换的是**候选生成**,不是整条流水线。全局结构问题(编号跨卷拼接、目录页 vs 正文、覆盖度)是模型解决不了的,必须留给确定性代码。逐行分类器只回答「这一行像不像标题」。 +> **经验 4**:「训练数据死结」这类反对理由,要具体到「标签从哪来」。当出现一个**独立于待训模型的标签源**(这里是 epub 目录),死结就解开了。遇到「没法训,因为没标签」时,先穷尽找找有没有天然的、旁路的真值来源。 + +--- ## 5. 训练踩的坑(每一个都值得记住) -数据管线 `ml/data/build_dataset.py`:epub 正文按 spine 拍平成行,命中 toc.ncx 标题的行标正,其余标负。84/85 解析成功,7983 正样本。 +数据管线 `ml/data/build_dataset.py`:epub 正文按 spine 顺序拍平成行,命中 toc.ncx 标题的行标正,其余标负。84/85 解析成功,23.6 万行、7983 正样本、正负比 1:29。 ### 坑 5.1:类别不平衡直接崩 -首次冷烟训练 f1=0。正负比 1:29,模型学成「全判非标题」——96% 准确率但零召回。 +首次冷烟训练 f1=0。诊断:正负比 1:29,模型学成「全判非标题」——准确率 96% 但**零召回**,loss 还很低(0.067),完全在骗自己。 -**解法**:负样本降采样(`train.py --neg-ratio`,默认 1:5),**只对训练集做,验证集保持自然分布**(否则精度虚高)。平衡后冷烟 f1=0.37。 +**解法**:负样本降采样(`train.py --neg-ratio`,默认 1:5),**只对训练集做,验证集保持自然分布**。放数据生成阶段会把验证集也采样导致精度虚高,所以放在 train.py 切分之后、只动训练集。平衡后冷烟 f1=0.37。 -> **经验 3**:极端不平衡下,先看 f1/召回而非 loss(全判负也有低 loss)。降采样只动训练集,评估集必须保自然分布,否则指标骗自己。 +> **经验 5**:极端不平衡下,**看 f1/召回而非 loss**(全判负也有低 loss)。降采样只动训练集,评估集必须保自然分布,否则指标骗自己。 ### 坑 5.2:DeBERTa-v3 微调发散成「死模型」 -完整训练(batch 32、3 轮)又 f1=0。诊断(加载模型手动预测)发现:**对任何输入输出几乎相同的 logits**——「第一章」和正文句概率都是 0.42。这是 DeBERTa-v3 微调著名的不稳定性。 +完整训练(batch 32、3 轮)又 f1=0。这次不是不平衡——诊断方法是**加载模型,手动对几个已知样本预测**,发现它对任何输入都输出**几乎相同的 logits**:「第一章 风雪夜」和「这个道理其实很简单」的标题概率都是 0.42,logits 几乎不随输入变化。这是「死模型 / 发散」,不是「偏向多数类」(后者会给多数类高概率)。DeBERTa-v3 微调以不稳定著称。 -**定位方法**:冷烟(batch 16)能学、完整(batch 32)不能——回到冷烟已证配置(batch 16/lr 2e-5/2 轮),只改数据量这一个变量。修复后 f1 正常。 +**定位方法**:冷烟(batch 16)能学、完整(batch 32)不能——**只改数据量这一个变量**,回到冷烟已证配置(batch 16 / lr 2e-5 / 2 轮)跑完整数据。修复后 f1 正常。事后加了 `--lr` 参数,注释写明「发散时降到 1e-5」。 -> **经验 4**:模型「死掉」时,别猜,直接加载它对几个已知样本预测——常数输出 = 没学到 / 发散,区别于「偏向多数类」。调试超参时一次只改一个变量,回到已知能 work 的配置。DeBERTa-v3 对 batch/lr 敏感,发散优先降 lr、减小 batch。 +> **经验 6**:模型「死掉」时别猜,**直接加载它对已知样本预测**——常数输出 = 没学到 / 发散,明显区别于「偏向多数类」。调超参**一次只改一个变量**,从已知能 work 的配置出发。DeBERTa-v3 对 batch/lr 敏感,发散优先减小 batch、降 lr。 ### 坑 5.3:eval-limit 加速带来的指标虚高(自己骗自己) -为加速迭代,训练时只在验证子集(保留全部正样本 + 抽 5000 负样本)上评估,报出 precision 0.88 / f1 0.59。**但这是假的**——负样本池被缩小近 8 倍,假阳性少算,精度虚高。 +为加速迭代(完整验证集 39k 行推理要 17 分钟/轮),训练时加了 `--eval-limit`,只在验证子集(保留全部正样本 + 抽 5000 负样本)上评估,报出 **precision 0.88 / f1 0.59**。 + +**但这是假的**——子集把负样本池缩小近 8 倍,假阳性少算,精度被抬高。算笔账:真实 566 个假阳性,在 1:4.8 的子集里只剩 ~74 个,精度就从 0.45 虚高到 0.88。在**完整验证集**上 v1 真实是 **precision 0.45 / recall 0.44**。 -在**完整验证集**上,v1 真实是 precision 0.45 / recall 0.44。 +> **经验 7(血泪)**:任何为加速而对**评估集**做的采样都会污染指标本身。加速开关只能用于「训练中粗略监控趋势」,**最终结论必须在完整、自然分布的评估集上得出**。这个错误让我一度对外报了虚高数字,后来必须主动纠正。注意:召回不受负样本采样影响(分母是全部正样本),精度受影响——搞清楚每个指标的分母对采样敏不敏感。 -> **经验 5(血泪)**:任何为加速而对评估集做的采样都会污染指标本身。加速开关只能用于「训练中粗略监控趋势」,**最终结论必须在完整、自然分布的评估集上得出**。这个错误让我一度对外报了虚高的数字,后来必须纠正——诚实比好看重要。 +### 坑 5.4:目录第一项 off-by-one(既有 bug,被新功能照出来) -### 坑 5.4:目录第一项 off-by-one +接入阅读页后发现点目录第一项会跳过开头。根因在 `transformText.ts`:`titleIdPage` 用 `if (!titleIdPage[id])` 记录每章首页,而首章首页页码是 `0`,被 falsy 判断当成「未赋值」覆盖成第 2 页。改成与 `undefined` 比较。这是既有代码的潜伏 bug,因为规则以前识别不出章节、目录一直是空的,所以从没暴露。 -接入阅读页时发现点目录第一项会跳过开头。根因 `titleIdPage` 用 falsy 判断记录首页,首章页码是 0 被当成「未赋值」覆盖。改成与 `undefined` 比较。附了回归测试,并**验证过测试真能抓到 bug**(回退修复后测试失败)。 +补了回归测试,并**验证过测试真能抓 bug**:回退修复后测试失败(`expected 1 to be +0`)。第一版测试因为序言太短(只占 1 页)没复现,加长序言到跨多页才有效。 -> **经验 6**:写回归测试后,回退修复确认它真的会失败——否则可能写了个永远通过的假测试。第一版测试因为序言太短没复现 bug,加长后才有效。 +> **经验 8**:写回归测试后,**回退修复确认它真的会失败**——否则可能写了个永远通过的假测试。构造复现数据时要满足 bug 的触发条件(这里是「首章必须跨多页」)。 + +--- ## 6. 召回瓶颈与格式特征(关键突破) -阈值扫描(`threshold_sweep.py`)显示:v1 光调阈值,召回从 0.44 只能到 0.6,且精度崩到 0.09。因为模型的漏判是**自信的漏判**(语义标题给近 0 概率),降阈值捞不回。 +`threshold_sweep.py` 在完整验证集上扫阈值,结果很冷静:v1 光调阈值,召回从 0.44 **只能到 0.6**,且精度崩到 0.09。曲线很平——因为模型的漏判是**自信的漏判**:语义标题「累到无力抵抗」给的概率是 0.007,不是「差一点到 0.5」,降阈值根本捞不回。 -**根因不在数据量,在特征**:模型只看到「文本行 + 前后行文本」,看不到人判断标题的真正依据——**这行是否短、是否以句号结尾、在全书什么位置、前后行相对长度**。拍平文本时这些信号丢了。 +**根因不在数据量,在特征**:模型只看到「文本行 + 前后行文本」,看不到人判断标题的真正依据——**这行是否短、是否以句号结尾、在全书什么位置、前后行相对长度**。拍平文本时这些信号全丢了。「累到无力抵抗」单独一行拿出来,你我也未必看得出是标题;线索在于「它很短、不以句号结尾、独占一行、后面跟着长段落」。 -**解法**:把格式特征离散成 token 拼进输入(不改模型结构,导出 ONNX 零障碍): +**解法**:把格式特征**离散成 token 拼进输入**(不改模型结构,导出 ONNX 零障碍,前端只要拼出一样的字符串): ``` -第一章 风雪夜 → "L1 P0 Q0 NX1 PV0 [SEP] 上一行 [SEP] 第一章 风雪夜 [SEP] 下一行" +第一章 风雪夜 → "L1 P0 Q0 NX1 PV0 [SEP] 上一行 [SEP] 第一章 风雪夜 [SEP] 下一行" +累到无力抵抗 → "L0 P0 Q1 NX1 PV0 [SEP] [SEP] 累到无力抵抗 [SEP] 当我们的自控力像肌肉一样疲劳时…" ``` -- L0-3 行长桶、P0/1 是否句末标点结尾、Q0-3 位置四分位、NX/PV 前后行是否明显更长。 -- **单一来源** `ml/textfeat.py`,前端 `lib/nlp/features.ts` 逐字复刻,**34 个测试断言两侧输出逐字相等**(参照值从 Python 生成)。 +- **L0-3** 行长桶、**P0/1** 是否以句末标点结尾(标题几乎不以「。」结尾,最强负向信号)、**Q0-3** 位置四分位、**NX/PV** 前后行是否明显更长(短标题后接长正文段)。 +- **单一来源** `ml/textfeat.py`,前端 `lib/nlp/features.ts` **逐字复刻**,**34 个测试断言两侧输出逐字相等**(参照值直接从 Python 生成)。 -效果(完整验证集诚实值):**召回 0.44 → 0.90**,精度 0.45 → 0.24。 +效果(完整验证集诚实值):**召回 0.44 → 0.90**,精度 0.45 → 0.24。语义标题「累到无力抵抗」现在带上 `L0 P0 NX1`(极短、不以句号结尾、后接长段落),正是它缺的信号。 -> **经验 7**:当模型「自信地漏判」某类样本,往往是缺特征而非缺数据。人判断该类样本靠什么线索,就把那些线索显式喂进去。 -> -> **经验 8**:训练/推理特征必须逐字一致,否则线上崩。把特征逻辑收进单一来源,另一侧复刻,并用「参照值断言」测试锁死——这是最容易静默出错、又最该测的地方。 +> **经验 9**:当模型**自信地漏判**某类样本,往往是**缺特征而非缺数据**。问自己「人判断这类样本靠什么线索」,把那些线索显式喂进去。加数据对「缺特征」型的错误帮助有限。 + +> **经验 10**:训练/推理特征必须**逐字一致**,否则线上崩且极难排查(模型在训练集上好好的,线上全错)。把特征逻辑收进**单一来源**,另一侧复刻,用「参照值断言」测试锁死。这是最容易静默出错、又最该测的地方。跨语言(Python `len` 按码点 / JS `String.length` 按 UTF-16 码元)也要对齐——用 `[...str].length`。 + +--- ## 7. 「高召回低精度」是正确的档位 -精度 0.24 看着差,但对「模型接结构层」的架构是**理想档位**: +精度 0.24 孤立看很差(报 6693 行找 1808 个真标题,约 4900 假阳性),但对「模型接结构层」的架构是**理想档位**: + +- 模型负责**别漏**(召回 0.90)——漏了结构层补不回,没有编号序列可插值。 +- 假阳性交给 `validate.ts` 结构层清:散乱的假阳性不构成递增章节序列、不满足最小间距和覆盖度,会被过滤掉——**低精度正是结构层能修的**。 -- 模型负责**别漏**(召回 0.90)——漏了结构层补不回。 -- 假阳性交给 `validate.ts` 结构层清(散乱假阳性不构成递增序列、不满足覆盖度)——低精度正是结构层**能**修的。 +训练时用 neg-ratio 1:4 主动偏向召回,就是这个考量。 -> **经验 9**:不要孤立地看单个模型指标。在「模型 + 后处理」系统里,该把召回和精度的职责分给不同层:模型冲召回,确定性后处理保精度。脱离系统评价 0.24 精度会得出错误结论。 +> **经验 11**:不要孤立地看单个模型指标。在「模型 + 确定性后处理」系统里,把召回和精度的**职责分给不同层**:模型冲召回(漏了补不回),后处理保精度(假阳性可过滤)。脱离系统评价 0.24 精度会得出「模型很差」的错误结论。 + +--- ## 8. 评估的严谨性(用户的关键提醒) 用户追问:验证集和训练集是否同源、会不会过拟合。核查后: -- **按书划分**(`split_by_book`),同一本书不跨训练/验证——防风格泄漏,0.90 是在没训练过的书上测的。 -- **去重在划分前**,防同一 (text,label) 跨边界。 -- **瑕疵(主动坦白)**:只有训练集 + 验证集,无独立测试集;`load_best_model_at_end` 按验证集选 epoch,指标轻微乐观。 -- **更强兜底**:literature 目录的**中文 txt 从没进过训练**(只用了 epub + 英文 txt),是完全独立的第三方测试集(`test_independent.py`)。 +- **按书划分**(`split_by_book` 取排序后后 15% 的整本书当验证集),同一本书不跨训练/验证——防**风格泄漏**(同一本书章节风格一致,按行随机分会让模型作弊)。0.90 是在没训练过的书上测的。 +- **去重在划分前**(按 text+label 全局去重),防同一 (text,label) 跨边界。 +- **瑕疵(主动坦白)**:只有训练集 + 验证集,**无独立测试集**;`load_best_model_at_end` 按验证集 f1 选 epoch,验证指标**轻微乐观**。 +- **更强兜底**:literature 目录的**中文 txt 从没进过训练**(训练只用了该目录的 epub + 英文 txt),是完全独立的第三方测试集(`test_independent.py`,用规则给结构化中文书打可靠 gold 标签)。做这个测试前还要比对书名,防「同名书既是训练 epub 又是测试 txt」的泄漏。 + +> **经验 12**:按**样本的自然分组**(这里是书)划分,而非按行随机,否则泄漏。只有 train/dev 时要主动说明模型选择带来的乐观,并尽量补一个**既不训练也不参与选择**的独立测试集。诚实交代评估的局限,比报一个漂亮数字重要——这条是用户逼出来的,也是最该内化的。 + +--- + +## 9. 工程与环境经验(每条都踩过) + +### 9.1 Python / torch 版本地雷 + +- **症状**:`pip install -r requirements.txt` 报 `Could not find transformers>=4.44`,只找到 2.x。 +- **根因**:机器上 `pip` 指向 **Python 2.7**(deprecation warning 泄露),在 2.x 包索引里找。而 `python3` 是 **Homebrew 的 3.14.5**,太新,**torch 没有对应 wheel**。 +- **解法**:`python3.11 -m venv ml/.venv`,用 3.11 装(torch 支持到 3.12)。命令一律走 `.venv/bin/python`,不用系统 `pip`。 +- **经验**:多 Python 环境下,`pip` / `python` 到底指向谁必须先确认(`which -a`)。用最新 Python 前先查关键依赖有没有 wheel——torch/onnxruntime 这类带原生扩展的,滞后新版本 Python 半年到一年很常见。 + +### 9.2 MPS 多进程死锁(最坑,一度以为是崩溃) -> **经验 10**:按「样本的自然分组」(这里是书)划分,而非按行随机,否则泄漏。只有 train/dev 时要主动说明模型选择带来的乐观,并尽量补一个既不训练也不选择的独立测试集。诚实交代评估的局限,比报一个漂亮数字重要。 +- **症状**:启动训练后日志**长时间零输出,然后进程消失**。第一反应以为是段错误 / 崩溃。 +- **误判过程**:反复重跑,越跑越多进程;`ps | grep train.py` 有时抓不到(shell 怪异),加深了「崩溃」的错觉。 +- **真相**:我为了「重试」启动了**3 个训练进程**,它们**抢同一块 MPS(Apple GPU)互相死锁在 step 0**。`ps aux` 一看,三个 python 进程都在,其中一个 55% CPU 空转。 +- **解法**:`pkill -9 -f train.py` 全杀,只留一个干净进程。 +- **经验**:Mac 上 MPS 是独占性强的单 GPU,**同时只跑一个训练/推理进程**。「静默无输出后退出」这种症状,先 `ps aux | grep` 数一下是不是多进程竞争,别急着当崩溃排查。后续所有长任务启动前都先 `pgrep -f ... | wc -l` 确认没有残留。 -## 9. 工程/环境经验 +### 9.3 训练在 Mac 上到底多慢 -- **Python 版本**:本机 python3=3.14 太新,torch 无 wheel。用 python3.11 建 venv(`ml/.venv`)。 -- **Mac 训练**:MPS(Apple GPU)可训 mDeBERTa-base,约 1-2 步/秒;完整训练 1.5-3h。**别同时开多个训练进程**——会抢 MPS 互相死锁在 step 0(踩过,表现为「静默无输出后退出」,实为多进程竞争)。 -- **等待策略**:长任务用后台 + 完成条件轮询(`until ! pgrep ...`),不要手动 sleep 拼接。 -- **磁盘**:Trainer 每轮存 checkpoint(各 3GB),训练后清理只留最终模型。 -- **模型体积**:mDeBERTa-v3-base int8 ONNX ≈ 322MB(全量 250k 词表,多语言)。 +- mDeBERTa-v3-base,batch 16,MPS 上约 **1.8 秒/步**(batch 32 会发散,见 5.2)。 +- 完整训练(1.5-2 万训练行、2 轮)约 **1.5 小时**;验证集 39k-100k 行推理 **每轮 3-17 分钟**(用 `--eval-limit` 压到 2 分钟,但注意 5.3 的虚高陷阱——只用于监控趋势)。 +- 独立测试集 15 万行推理约 30-40 分钟。 +- **经验**:没有 CUDA 时,MPS 能训 base 级模型但慢一个量级;迭代要靠「小数据冷烟验证链路 → 全量正式训练」两段式,别一上来就全量。 + +### 9.4 输出被工具链过滤 / 编码问题 + +- **rtk 代理过滤 vitest 输出**:`pnpm test` 的详细结果被压掉,只剩汇总。需要原始输出时用 `rtk proxy ` 落到文件再读。 +- **训练日志有非 UTF-8 字节**:`tr '\r' '\n'` 报 `Illegal byte sequence`。解法 `LC_ALL=C tr -cd '[:print:]\n\r'` 先过滤再处理。 +- **进度条用 `\r` 刷新**:`tail` 直接看是一坨,要 `tr '\r' '\n'` 拆开取最后一行。 +- **经验**:长时间后台任务的进度/结果,别指望终端实时看——统一重定向到文件,用 `grep -a` / `LC_ALL=C` 抗二进制字节,用完成条件轮询(`until ! pgrep ...; do sleep N; done`)等结束,不要手动 `sleep` 拼接。 + +### 9.5 vitest 收集了编译产物 + +- **症状**:测试数从 12 跳到 24,凭空多一倍。 +- **根因**:`vite build` 产生的 `dist/` 里有编译后的 `.test.js`,vitest 4 默认把它们也收进来跑。 +- **解法**:`vitest.config.ts` 显式 `exclude: ['**/dist/**', ...]`;顺带配 alias(vite 的 root 相对路径 alias 在 node 下不生效,要真实文件系统路径)。 +- **经验**:测试数异常翻倍先查是不是重复收集了构建产物 / 快照。 + +### 9.6 磁盘与产物管理 + +- Trainer **每轮存 checkpoint**(mDeBERTa-base 各 ~3GB),一个 2 轮训练留下 6-7GB 中间产物。训练后 `rm -rf out/model/checkpoint-*` 只留最终模型。 +- ONNX 导出产物:`model.onnx`(fp32,~1GB,不部署)+ `model_quantized.onnx`(int8,**322MB,浏览器加载这个**)+ tokenizer.json(15.6MB)。 +- 全部走 `ml/.gitignore`(`train/out/`、`export/out/`、`data/out/`、`.venv/`、`*.jsonl`),**模型和数据集绝不进 git**。 +- **经验**:训练前就把产物目录加进 gitignore,别等 `git status` 里冒出 1GB 文件才补。定期清 checkpoint。 + +### 9.7 ONNX 导出与量化 + +- 用 `optimum[onnxruntime]` 导出 + int8 动态量化,optimum 2.1 上脚本直接可用。 +- **量化不损伤判别力**:验证量化后 ONNX 预测与 PyTorch 一致(标题 0.92-0.98、正文 0.002),用**浏览器同款 onnxruntime** 加载 `model_quantized.onnx` 复核,而不是只信 PyTorch。 +- **经验**:量化后必须用**部署时的运行时**(这里是 onnxruntime,不是 PyTorch)复核几个样本,int8 偶尔会显著掉点,早发现。 + +--- ## 10. 里程碑数字(诚实版) -| 阶段 | 召回 | 精度 | 备注 | -| --------------------------------------- | -------- | ------------------- | ------------------ | -| 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | -| 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | -| 模型 v2(+格式特征 + 多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | -| 独立测试集(训练零接触中文书) | 待填 | 待填 | 泛化真值 | +| 阶段 | 召回 | 精度 | 备注 | +| --------------------------------------- | -------- | ------------------- | ---------------------- | +| 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | +| 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | +| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | +| 独立测试集(训练零接触中文书) | 待填 | 待填 | 泛化真值,答过拟合疑问 | + +- 英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充,+4209 正样本)。 +- 数据规模:epub 真值 7983 正 + 英文 txt 弱标注 4209 正 = 12192 正样本(多语言数据集)。 -英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充)。 +--- ## 11. 待办 / 后续方向 - 独立测试集数字回填,若召回仍 ~0.85+ 则泛化成立。 -- 导出 ONNX → 前端候选层接入(模型输出 union 到规则候选 → validate.ts)→ app 用金庸/四世同堂/英文书验证端到端。 -- 产品决策:322MB 模型进 PWA 的下载成本;移动端词表裁剪版;懒加载策略。 -- 进一步提召回:目录手动编辑 UI 收集用户修正(source: manual)作为增量标注 → 迭代。 -- 精度若仍不够被结构层消化:可提高训练 neg-ratio、或阈值上调。 +- 导出 ONNX → 前端候选层接入(模型输出 union 到规则候选 → `validate.ts` 结构层过滤)→ app 用金庸 / 四世同堂 / 英文书验证端到端。 +- **产品决策**:322MB 模型进 PWA 的下载成本;移动端词表裁剪版(~150MB,按 CJK+拉丁+西里尔裁剪);懒加载策略(规则高置信度时不下模型)。 +- 进一步提召回:目录手动编辑 UI 收集用户修正(`source: manual`)作为增量标注 → 迭代飞轮。 +- 精度若仍不够被结构层消化:提高训练 neg-ratio、或阈值上调、或给 validate.ts 加更强的序列约束。 From 076b552c994deef037a68a80d9f367c0d47b9f9d Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 13:43:37 +0800 Subject: [PATCH 16/54] docs: fill independent-test result (recall 0.988 on zero-contact books) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generalization confirmed: recall 0.988 on 40 Chinese books in neither training nor model selection — refutes overfitting/model-selection optimism. Precision understated (rule gold only marks 第X章). Note dev (0.90, harder semantic-title labels) and independent (0.988, structured labels) measure different label sets and aren't directly comparable. Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index 432d463..a075dc3 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -243,12 +243,17 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 ## 10. 里程碑数字(诚实版) -| 阶段 | 召回 | 精度 | 备注 | -| --------------------------------------- | -------- | ------------------- | ---------------------- | -| 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | -| 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | -| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | -| 独立测试集(训练零接触中文书) | 待填 | 待填 | 泛化真值,答过拟合疑问 | +| 阶段 | 召回 | 精度 | 备注 | +| --------------------------------------- | --------- | ------------------- | -------------------- | +| 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | +| 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | +| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | +| 独立测试集(40 本训练零接触中文书) | **0.988** | 0.21\* | 泛化真值,排除过拟合 | + +\* 独立测试的标签来自规则(仅标「第X章」类),模型额外找出的序言/楔子/语义标题被算作假阳性, +所以精度被低估,真实值更高。召回 0.988 是可信的关键信号——在训练与模型选择都零接触的书上 +近满分,直接排除「0.90 是模型选择乐观」的可能。注意两套考卷难度不同:验证集含难的纯语义标题 +(召回 0.90),独立测试是结构化中文章节(召回 0.988),不能直接比高低,但都证明泛化成立。 - 英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充,+4209 正样本)。 - 数据规模:epub 真值 7983 正 + 英文 txt 弱标注 4209 正 = 12192 正样本(多语言数据集)。 From 4766d1abc7495e3dc083f5363929c21f63ad8a68 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 15:44:32 +0800 Subject: [PATCH 17/54] docs: browser deployment plan for the chapter model (lazy-load/chunk/cache) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two separate problems: lazy-loading (when to fetch — confidence-gated, most users never download) and chunking/size (vocab pruning 322->~150MB, q4, runtime code-split, range-streamed weights, OPFS + persist). Tiered rollout (tier 0 = confidence gate + progressive UX, tier 1 = code-split + stream + cache, tier 2 = pruned mobile build). Maps each piece to existing code (detectChaptersDetailed confidence, resolveBookChapters, ChapterClassifier, features.ts, validate.ts). Co-Authored-By: Claude Fable 5 --- docs/chapter-model-deployment.md | 117 +++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 docs/chapter-model-deployment.md diff --git a/docs/chapter-model-deployment.md b/docs/chapter-model-deployment.md new file mode 100644 index 0000000..1978a6a --- /dev/null +++ b/docs/chapter-model-deployment.md @@ -0,0 +1,117 @@ +# 章节识别模型的浏览器部署规划(懒加载 / 分包 / 缓存) + +> 目标:把 322MB 的章节标题模型接进纯前端 PWA,而**不让绝大多数用户付出这个下载成本**。 +> 前置:模型已训成(v2,验证集 recall 0.90 / 独立测试 recall 0.988),推理设施 `lib/nlp/ChapterClassifier` + `workers/nlpWorker.ts` 已就绪。 +> 配套:模型的由来与效果见 [chapter-detection-journey.md](./chapter-detection-journey.md)。 + +这是两个**不同**的问题,杠杆和收益完全不同,分开处理: + +- **懒加载**:_什么时候_才去下模型(多数用户永远不下)。 +- **分包 / 减体积**:真要下时,_怎么把 322MB 拆小、拆开、可恢复_。 + +--- + +## 一、懒加载:最大的杠杆(复用已有的置信度信号) + +核心判断:**绝大多数用户不该下这个模型。** 规则层对结构化书(第X章、CHAPTER N)本就是 high 置信度、识别良好;模型只对规则搞不定的书有增量价值。 + +`detectChaptersDetailed` 已输出置信度(high/medium/low/none)+ 胜出模式家族,直接拿来门控: + +``` +导入书 → 规则识别(0 成本,永远先跑,结果进 books_chapters 缓存) + ├─ high 置信度 → 直接用规则结果,永不下模型 + └─ low / none 置信度 → 展示规则结果(或整本一章)+ 一个「目录可能不全,点此 AI 增强」入口 + └─ 用户点击才下模型 → 进度条 → 重新解析 → 更新目录 + → 结果写 books_chapters(source: 'model'),一本书只解析一次 +``` + +要点: + +- **渐进增强,不是强制等待**:先给规则结果 / 兜底,模型是可选的二次提升。 +- **门控把「人人下 322MB」变成「碰到难书且主动点了增强的少数人下一次」**。 +- 结果持久化到 `books_chapters`(已有),命中缓存的书再打开不重算、不再触发模型。 +- 可加策略:用户在设置里选「总是用 AI 增强 / 从不 / 仅在规则失败时提示」(默认第三种)。 + +> 这一层决定 ~90% 的用户体验,且几乎不碰模型本身,应最先做。它同时验证一个关键假设:**多数用户根本不需要下模型**——上线后看真实下载触发率,再决定第二、三层投入多少。 + +--- + +## 二、减体积(分包之前先做,性价比更高) + +按收益排序: + +1. **词表裁剪(最大头,322 → ~150-180MB)** + mDeBERTa 的 322MB 里近 2/3 是 25 万 token 的多语言 embedding。裁到实际用到的语系(CJK + 拉丁 + 西里尔,约 5-8 万 token),精度几乎无损。做成两档:**桌面全量 / 移动裁剪版**,按 `navigator.deviceMemory`、UA 选。(当初保留全量词表就是为多语言,这里正好落地分档。) + +2. **q4 量化(~322 → ~160MB,或裁剪后 ~90MB)** + 现为 int8。transformers.js 支持 q4 dtype,再砍一半,代价是些许精度——需实测。裁剪 + q4 可叠加。 + +3. **换更小骨干(能降一个数量级,但工作量大)** + 关键洞察:**加了格式特征后,很多判别信号已在 token 里**,模型未必需要 base 级。可蒸馏小学生模型,或试更小的多语言编码器。留作后续大优化,非首期。 + +--- + +## 三、分包(怎么把字节拆开传) + +1. **JS/WASM 运行时代码分包(真正的 code splitting,先做,近零成本)** + transformers.js + onnxruntime-web 的运行时(WASM 后端几 MB)**不进主 bundle**。在 worker 里动态 import:`const { pipeline } = await import('@huggingface/transformers')`,只在要用时加载;ORT 的 WASM 后端文件也是首次用才拉。这块和模型权重是两件独立的事。 + +2. **权重 Range 流式下载(进度 + 断点续传)** + 322MB 用 HTTP Range 分块拉,配进度条与**断点续传**(移动网络必然会断)。ORT Web 可从 ArrayBuffer 加载模型,故可自控分块与恢复。这是「分包」在权重层面的主要形态——不是逻辑拆分,是**传输可控 + 可恢复**。 + +3. **ONNX external data(图/权重分离)** + ONNX 支持权重存独立文件(`model.onnx` 小图 + `model.onnx_data` 权重),onnxruntime-web 可分别加载。单模型收益有限,但要做「先加载图、权重后到」的渐进式加载时是基础。 + +--- + +## 四、缓存与存储(下一次就够,离线可用) + +- **OPFS 优先于 Cache API 存大模型**:322MB 大 blob,OPFS 配额更可预期、更适合。transformers.js 可配自定义缓存后端。 +- **`navigator.storage.persist()`**:请求持久化存储,否则 iOS Safari 在存储压力下会驱逐模型,用户又得重下。 +- **版本化 immutable URL + 清单 JSON**:模型文件名带版本(如 `chapter-title.v2.q8.onnx`),CDN 设长缓存头(immutable);`public/` 放 manifest(version / url / size / sha256),前端对比决定是否更新。 +- **禁止 Service Worker precache 模型**:那等于给所有用户强制下载。模型只走**运行时按需缓存**,SW 不预缓存。 + +--- + +## 五、移动端特殊处理 + +- iOS PWA 单页内存约 1-1.5GB,322MB 模型 + ORT 运行时峰值可能触顶。 +- 策略:移动端默认裁剪版(~150MB)或 q4;`deviceMemory` 低的机器直接只用规则层(不提供模型增强,或提示「本设备暂不支持」)。 +- **真机压测必做**:加载峰值内存、Cache/OPFS 配额、被系统杀掉的概率。 + +--- + +## 六、落地建议(分层,从零成本到高投入) + +| 层 | 做什么 | 成本 | 谁受影响 | +| ----- | ---------------------------------------------------------------- | ----------------- | ------------------------------- | +| **0** | 规则先跑;high 置信度永不下模型;low/none 显示「AI 增强」入口 | 已有信号,改 UI | 所有人,多数在这层就完事 | +| **1** | 运行时代码动态 import + 权重 Range 流式 + 进度条 + OPFS 持久缓存 | 中 | 点了「AI 增强」的少数人,下一次 | +| **2** | 词表裁剪出移动版 + q4,按设备选档 + 版本化 CDN + manifest | 高(要重训/重导) | 移动端 / 全量优化 | + +**推荐顺序**: + +1. **先做第 0 层**(置信度门控 + 渐进 UX + 「AI 增强」按钮)。纯前端,不碰模型重训,决定 90% 体验,并验证「多数用户不需要下模型」的假设。 +2. **接入时顺带第 1 层**(代码分包 + 流式 + OPFS)。这一步同时完成「模型接进浏览器」这件事本身。 +3. **看第 0/1 层的真实下载触发率,再决定第 2 层投入**。如果触发率很低(多数书规则就够),移动裁剪版可以延后甚至不做。 + +--- + +## 七、与现有代码的衔接点 + +- `lib/chapter/index.ts` `detectChaptersDetailed` 的置信度 → 门控是否提示「AI 增强」。 +- `store/chapters.ts` `resolveBookChapters` → 增加 `source: 'model'` 分支,模型结果走同一缓存与失效逻辑(`CHAPTER_ALGO_VERSION` / manual 保留)。 +- `lib/nlp/ChapterClassifier` + `workers/nlpWorker.ts`(P2 已建)→ 改为加载**本地/CDN 模型**(transformers.js `env.localModelPath` 或直接 URL),而非 HF modelId;进度回调已有(`onProgress`),接进度条。 +- `lib/nlp/features.ts` → 推理时对每一候选行算特征、拼 `makeModelInput`,喂给分类器(与训练侧 `ml/textfeat.py` 逐字一致,已被测试锁定)。 +- 模型输出(逐行标题概率)→ 阈值化成候选 → **union 到规则候选** → 交 `validate.ts` 结构层过滤(高召回低精度靠这层收敛)。 +- `public/models/` 放模型文件与 manifest(`.gitignore` 排除大文件,走 CDN)。 + +--- + +## 八、待验证 / 开放问题 + +- 阈值定多少:模型 recall 0.90+ 但 precision 0.24,结构层能否把假阳性清干净,需 app 实测(金庸 / 四世同堂 / 英文书)后定阈值。 +- 词表裁剪后精度损失的实测值。 +- q4 相对 int8 的精度损失。 +- iOS 真机内存峰值与 OPFS 配额上限。 +- 触发率:上线第 0 层后,实际有多少书落到 low/none、多少用户点了「AI 增强」——决定后续投入。 From d9be44b64ebe607bae39520e676ea91bc4b436e6 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 16:05:47 +0800 Subject: [PATCH 18/54] fix: charset detection + anchored literary-phrase weak labeling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2 systematically failed pure literary titles (青衫磊落险峰行, 累到无力抵抗 all ~0.001) — the academic epub corpus lacks literary phrase-titles and the 4209 English CHAPTER-N positives drowned what little signal existed. - decode_txt: try utf-8/gb18030/utf-16 (was hardcoded utf-8, so gb18030/ utf-16le wuxia books read as garbage and were silently skipped) - CHAPTER_RE now catches anchored literary 回目: 第X回 + phrase and 中文数字 + space + phrase (天龙 '一 青衫磊落险峰行'), sequence-validated - yields 438 literary-phrase positives from 12 wuxia books (held out of the independent test to avoid leakage) Rebalance for v3: epub 7983 + wuxia 438 + English capped to 907 (was 4209). Co-Authored-By: Claude Fable 5 --- ml/data/build_dataset.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/ml/data/build_dataset.py b/ml/data/build_dataset.py index 58c3c3b..595277a 100644 --- a/ml/data/build_dataset.py +++ b/ml/data/build_dataset.py @@ -162,22 +162,45 @@ def build_records(epub: Epub, book_id: str) -> list[dict]: # 高精度章节行正则(弱标注用)。英文 Gutenberg 格式规整,误报率极低; -# 中文只收「第X章」这类强标记,纯语义标题留给 epub 真值,不在 txt 里猜。 +# 中文收「第X章/回」以及**锚点式文学回目**——第X回 + 空格 + 短语(射雕「第一回 风雪惊变」)、 +# 中文数字 + 空格 + 短语(天龙「一 青衫磊落险峰行」)。后者靠 parse_txt_weak 的序列+跨度校验滤噪。 +# 无锚点的纯裸短语(累到无力抵抗)不在 txt 里猜,留给 epub 真值。 _ROMAN = r"[ivxlcdm]{1,7}" +_CN = r"零一二两三四五六七八九十百千" # 中文数字字符(不含括号) +_SP = r"[  ]" # 半角或全角空格 CHAPTER_RE = re.compile( - rf"^\s*(?:(?:chapter|part|book|section)\s+(?:\d{{1,4}}|{_ROMAN})" - rf"|第\s*[0-9零一二两三四五六七八九十百千]{{1,8}}\s*[章节節回卷])\b", + rf"^\s*(?:" + rf"(?:chapter|part|book|section)\s+(?:\d{{1,4}}|{_ROMAN})" # 英文 + rf"|第\s*[0-9{_CN}]{{1,8}}\s*[章节節回卷]" # 第X章/回(可带短语) + rf"|[{_CN}]{{1,3}}{_SP}+\S{{2,}}" # 中文数字 + 空格 + 短语(天龙式回目) + rf")", re.IGNORECASE, ) +def decode_txt(buf: bytes) -> str: + """稳健解码中文 txt:试 utf-8/gb18030/utf-16,取替换字符最少的(无外部依赖)。""" + best = None + for enc in ("utf-8", "gb18030", "utf-16le", "utf-16"): + try: + text = buf.decode(enc) + except (UnicodeDecodeError, LookupError): + continue + bad = text.count("�") + if bad == 0: + return text + if best is None or bad < best[1]: + best = (text, bad) + return best[0] if best else buf.decode("utf-8", "ignore") + + def parse_txt_weak(path: Path, book_id: str) -> list[dict] | None: """ 对无 TOC 的 txt 做规则弱标注:只有当章节行构成足够长、基本递增的序列时才采用, 否则返回 None(宁可不要,也不引入噪声标签)。正样本来自高精度正则,其余为负。 """ try: - raw = path.read_text(encoding="utf-8", errors="ignore") + raw = decode_txt(path.read_bytes()) except OSError: return None lines = [normalize(l) for l in raw.splitlines()] From ef92b2821e05cc74d9f230927e84372521dcbf04 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 17:15:17 +0800 Subject: [PATCH 19/54] =?UTF-8?q?docs:=20v2->v3=20investigation=20?= =?UTF-8?q?=E2=80=94=20aggregate=20metrics=20hid=20flagship=20failure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New section 7.5 + lessons 13-15. v2's 0.90 recall masked that it scored ~0.001 on ALL pure literary titles (青衫磊落险峰行, 累到无力抵抗) — the flagship case. Root cause: academic epub corpus lacks literary phrases + 4209 English CHAPTER-N drowned the signal. v3 (wuxia weak-supervision, capped English) recovered anchored 回目 (0.001->0.945, generalizing past the number anchor) but bare colloquial phrases remain a representation limit of flattened text — a boundary to document, not to keep throwing data at. Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index a075dc3..1f5eeaa 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -175,6 +175,39 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 --- +## 7.5 聚合指标掩盖了旗舰用例的失败(v2 → v3) + +拿 v2 做接入前的手工抽查,发现**验证集 recall 0.90 是「好看的假象」**:v2 对**所有纯文学短语标题**系统性判 ~0.001——青衫磊落险峰行、累到无力抵抗、意志力的本能全挂,甚至比 v1 还差。而这恰恰是当初上模型要解决的旗舰用例(规则接不住的语义标题)。 + +**根因**(查训练数据组成才看清): + +- epub 语料是**学术/非虚构书**,目录以编号 + 序跋词为主;那 31% 的「语义」正样本大多是书名/作者名/「后记」「译序」等样板,**真正的文学短语标题少得可怜**。 +- 英文弱标注又加了 **4209 条纯结构化 CHAPTER N**,把微弱的语义信号彻底淹没。 +- 结果模型学成「有结构标记 = 标题」——而结构化正是规则本就做得好的,**模型没拿到独有价值,同义反复陷阱部分回归**。 + +**v3 修复**:给 12 本武侠书做锚点式文学回目弱标注(「第一回 风雪惊变」「一 青衫磊落险峰行」,共 438 条),英文从 4209 砍到 907 再平衡。顺带修了个 charset bug——`parse_txt_weak` 硬编码 utf-8,gb18030/utf-16le 的武侠书全读成乱码被静默跳过。 + +**v3 结果(探针)**,和事前预测精确吻合: + +| 标题 | v2 | v3 | 类型 | +| -------------- | ----- | --------- | ---------------------------- | +| 青衫磊落险峰行 | 0.001 | **0.945** | 锚点文学回目——**规则接不住** | +| 玉壁月华明 | — | **0.805** | 同上 | +| 第一章 风雪夜 | 0.97 | 0.876 | 结构化——规则也行 | +| 累到无力抵抗 | 0.001 | 0.002 | 裸口语短语——**固有极限** | +| 意志力的本能 | 0.001 | 0.024 | 同上 | + +- **锚点文学回目拿回来了**(0.001 → 0.945),且探针测的是**去掉「一 」前缀的纯短语**,模型仍判对——说明它没靠数字锚点作弊,真学会了「这类文学短语是标题」。这是模型相对规则的**独有价值**(空格分隔的金庸/古龙回目)。 +- **裸口语短语仍难**:原书里它是居中大字标题,靠视觉排版;拍平成一行后无锚点、风格又和普通口语句无异,模型(和人一样)区分不出。有趣的不对称:青衫磊落险峰行是古典对仗腔(可学),累到无力抵抗是大白话(学不了)。 + +> **经验 13**:**聚合指标会掩盖子类失败**。0.90 的召回若被结构化正样本主导,就看不出它对旗舰子类(文学短语)全军覆没。接入前一定要按**用例子类**手工抽查,而不是只看一个总召回。 +> +> **经验 14**:**弱标注的语料构成会悄悄决定模型的能力边界**。学术 epub + 英文 CHAPTER N 训出来的模型只会做结构化——等于又训了一遍规则。要模型学会某类样本,训练集里就得**真的有**那类、且不被其他类淹没。 +> +> **经验 15**:**分清「数据能补的差距」和「表征的固有极限」**。锚点文学回目是前者(补武侠数据就回来了);裸口语短语是后者(拍平文本丢了视觉排版,再多数据也难)。后者该记录为已知边界,交给别的机制(目录手动编辑 + 用户修正回流),而不是无止境堆数据。 + +--- + ## 8. 评估的严谨性(用户的关键提醒) 用户追问:验证集和训练集是否同源、会不会过拟合。核查后: From 6416405501ee26e71729b4debb91435f294afe50 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 17:43:05 +0800 Subject: [PATCH 20/54] =?UTF-8?q?docs:=20v3=20milestone=20=E2=80=94=20best?= =?UTF-8?q?=20model,=20honest=20capability=20boundary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v3 full-dev: precision 0.339 / recall 0.879 / f1 0.49 — beats v2 (0.24/0.90/ 0.38) on precision and f1 while recovering 金庸回目 (0.945). Documents the honest boundary: structural + anchored literary 回目 work; bare colloquial phrase titles are a flattened-text representation limit, deferred to manual edit + user-correction feedback. Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index 1f5eeaa..dd2d9ad 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -276,20 +276,25 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 ## 10. 里程碑数字(诚实版) -| 阶段 | 召回 | 精度 | 备注 | -| --------------------------------------- | --------- | ------------------- | -------------------- | -| 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | -| 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | -| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回喂结构层 | -| 独立测试集(40 本训练零接触中文书) | **0.988** | 0.21\* | 泛化真值,排除过拟合 | +| 阶段 | 召回 | 精度 | 备注 | +| ---------------------------------------------- | --------- | ------------------- | --------------------------------------------- | +| 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | +| 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | +| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回,但文学标题全挂(7.5 节) | +| 独立测试集(40 本训练零接触中文书) | **0.988** | 0.21\* | 泛化真值,排除过拟合 | +| **模型 v3(+武侠回目,英文降量,完整验证集)** | **0.879** | **0.339** | **金庸回目 0.001→0.945,精度/f1 全面优于 v2** | \* 独立测试的标签来自规则(仅标「第X章」类),模型额外找出的序言/楔子/语义标题被算作假阳性, 所以精度被低估,真实值更高。召回 0.988 是可信的关键信号——在训练与模型选择都零接触的书上 近满分,直接排除「0.90 是模型选择乐观」的可能。注意两套考卷难度不同:验证集含难的纯语义标题 (召回 0.90),独立测试是结构化中文章节(召回 0.988),不能直接比高低,但都证明泛化成立。 -- 英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充,+4209 正样本)。 -- 数据规模:epub 真值 7983 正 + 英文 txt 弱标注 4209 正 = 12192 正样本(多语言数据集)。 +- 英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充)。 +- v3 数据规模:epub 真值 7983 正 + 武侠回目 438 正 + 英文 907 正 = 9328 正样本。英文从 v2 的 4209 + 砍到 907 是关键——避免结构化正样本淹没文学短语信号(见 7.5 节)。 +- **能力边界(诚实记录)**:结构化标题(第X章/CHAPTER N)与**锚点文学回目**(金庸/古龙的「一 青衫磊落险峰行」) + 都能识别;**裸口语短语标题**(「累到无力抵抗」,无任何锚点)是拍平文本的固有极限,模型做不到, + 交给目录手动编辑 + 用户修正回流。 --- From ec72f1333a44758c8b00914c363ea9960c55f95c Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 18:11:28 +0800 Subject: [PATCH 21/54] feat: wire v3 model into browser worker; hit DeBERTa-v3 quant wall MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Browser end-to-end inference PROVEN CORRECT with fp32: structural 0.992, 金庸回目 0.914, body 0.000 — matches PyTorch exactly. Tokenization verified byte-identical to Python. nlpWorker changes: - load local model from public/models via env.localModelPath (must be a PATH not absolute URL, or transformers.js existence-check skips local) - AutoTokenizer + AutoModel + manual softmax instead of pipeline (pipeline threw 'this.tokenizer is not a function' on the DeBERTa-v2 tokenizer) - drop token_type_ids (multi-[SEP] input gives nonzero type ids mDeBERTa doesn't want) - default dtype fp32 Size is the remaining blocker: int8 breaks DeBERTa-v3 accuracy (logits nearly negated), fp16 conversion has a graph type bug, fp32 works but is 1.1GB. Documented in deployment doc 2.0 with next steps (vocab pruning, fixed fp16, static int8, smaller backbone). export_onnx now per_channel=True. Co-Authored-By: Claude Fable 5 --- .gitignore | 1 + docs/chapter-model-deployment.md | 37 ++++++++++++++---- ml/export/export_onnx.py | 6 ++- workers/nlpWorker.ts | 66 +++++++++++++++++++++++--------- 4 files changed, 81 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index 32de593..cb4d529 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ dist report # tesseract *.traineddata +public/models/ diff --git a/docs/chapter-model-deployment.md b/docs/chapter-model-deployment.md index 1978a6a..68aaa7c 100644 --- a/docs/chapter-model-deployment.md +++ b/docs/chapter-model-deployment.md @@ -36,18 +36,39 @@ --- -## 二、减体积(分包之前先做,性价比更高) +## 二、减体积(当前的**首要阻塞**,见 2.0 血泪教训) -按收益排序: +### 2.0 ⚠️ DeBERTa-v3 的量化血泪(实测,2026-07-18) -1. **词表裁剪(最大头,322 → ~150-180MB)** - mDeBERTa 的 322MB 里近 2/3 是 25 万 token 的多语言 embedding。裁到实际用到的语系(CJK + 拉丁 + 西里尔,约 5-8 万 token),精度几乎无损。做成两档:**桌面全量 / 移动裁剪版**,按 `navigator.deviceMemory`、UA 选。(当初保留全量词表就是为多语言,这里正好落地分档。) +浏览器端到端已跑通、**fp32 完全正确**(结构化 0.992、金庸回目 0.914、正文 0.000,与 PyTorch 一致), +但**体积是当前唯一阻塞**: -2. **q4 量化(~322 → ~160MB,或裁剪后 ~90MB)** - 现为 int8。transformers.js 支持 q4 dtype,再砍一半,代价是些许精度——需实测。裁剪 + q4 可叠加。 +| 格式 | 体积 | 浏览器结果 | 结论 | +| --------------------------------------- | --------- | ------------------------------------------------- | --------------------------------- | +| **fp32** | **1.1GB** | ✅ 正确 | 太大,不能直接上 | +| **int8**(per_channel=False) | 338MB | ❌ logits 几乎取反(第一章 title=0.01) | **DeBERTa-v3 对 int8 敏感,坏了** | +| **int8**(per_channel=True) | ~340MB | ⚠️ 改善但仍错(第一章 0.45、金庸 0.01) | 仍不可用 | +| **fp16**(onnxconverter keep_io_types) | 559MB | ❌ 图型错误(embeddings Cast float16 vs float32) | 转换需处理 Cast 节点 | -3. **换更小骨干(能降一个数量级,但工作量大)** - 关键洞察:**加了格式特征后,很多判别信号已在 token 里**,模型未必需要 base 级。可蒸馏小学生模型,或试更小的多语言编码器。留作后续大优化,非首期。 +**根因**:DeBERTa-v3 的 disentangled attention 对 int8 动态量化本质不友好(社区已知问题)。 +**下一步该试**(按优先级): + +- **词表裁剪先做**(见下 2.1):把 fp32 的 1.1GB 砍到 ~500-600MB,再叠加 fp16 有望到 ~300MB; +- **修 fp16 转换**:用 `op_block_list` 排除 Cast/LayerNorm 等,或用 optimum 的 fp16 优化路径而非裸 onnxconverter; +- **QDQ / 静态量化 + 校准集**:动态量化太糙,带校准的静态 int8 可能救回精度; +- 实在不行**换更小骨干**(见下)。 + +> **经验(部署)**:导出后**必须用部署运行时**(onnxruntime-web / 浏览器)验证**量化模型**的预测, +> 而不是只信 PyTorch 或只验证过别的版本。v3 导出时我没重验量化模型,直到浏览器接入才发现 int8 坏了, +> 白跑一轮。量化对不同架构差异极大(同样 int8,RoFormer 没事、DeBERTa-v3 崩)。 + +### 2.1 词表裁剪(最大头) + +mDeBERTa 的体积里近 2/3 是 25 万 token 的多语言 embedding。裁到实际用到的语系(CJK + 拉丁 + 西里尔,约 5-8 万 token),精度几乎无损。做成两档:**桌面全量 / 移动裁剪版**,按 `navigator.deviceMemory`、UA 选。(当初保留全量词表就是为多语言,这里正好落地分档。)**这是绕开量化难题的最稳一步**——先把 fp32/fp16 的体积压下来。 + +### 2.2 换更小骨干(能降一个数量级,但工作量大) + +关键洞察:**加了格式特征后,很多判别信号已在 token 里**,模型未必需要 base 级。可蒸馏小学生模型,或试更小的、量化更友好的多语言编码器(如 MiniLM 系)。留作后续大优化。 --- diff --git a/ml/export/export_onnx.py b/ml/export/export_onnx.py index c99eb61..d85108d 100644 --- a/ml/export/export_onnx.py +++ b/ml/export/export_onnx.py @@ -39,9 +39,11 @@ def main() -> int: model.save_pretrained(out) AutoTokenizer.from_pretrained(args.model).save_pretrained(out) - # 2. int8 动态量化(avx512 配置,兼容大多数 CPU;WebGPU 侧仍可用量化权重) + # 2. int8 动态量化。**per_channel=True 必须开**:DeBERTa-v3 对量化敏感, + # per_channel=False 会让量化模型输出错乱(v3 实测 logits 几乎取反、title 概率反向)。 + # 逐通道量化精度高得多,正好修这种退化。 quantizer = ORTQuantizer.from_pretrained(out) - qconfig = AutoQuantizationConfig.avx512_vnni(is_static=False, per_channel=False) + qconfig = AutoQuantizationConfig.avx512_vnni(is_static=False, per_channel=True) quantizer.quantize(save_dir=out, quantization_config=qconfig) print(f"导出完成: {out}") diff --git a/workers/nlpWorker.ts b/workers/nlpWorker.ts index e33c595..fb36f3a 100644 --- a/workers/nlpWorker.ts +++ b/workers/nlpWorker.ts @@ -1,5 +1,5 @@ -import { env, pipeline } from '@huggingface/transformers'; -import type { ProgressInfo, TextClassificationPipeline } from '@huggingface/transformers'; +import { AutoModelForSequenceClassification, AutoTokenizer, env, softmax } from '@huggingface/transformers'; +import type { PreTrainedModel, PreTrainedTokenizer, ProgressInfo } from '@huggingface/transformers'; import { DEVICE_PRIORITY } from '@/lib/nlp/protocol'; import type { ClassifyRequest, @@ -10,13 +10,22 @@ import type { NlpRequest, NlpResponse, } from '@/lib/nlp/protocol'; -import { normalizeClassifierOutput } from '@/lib/nlp/score'; -// 模型一律走远端 + 浏览器缓存(Cache API),不探测本地路径 -env.allowLocalModels = false; +// 本地模型(自训 v3)放在应用同源路径下:只从本地加载,不回退 HF 远端 +env.allowLocalModels = true; +env.allowRemoteModels = false; env.useBrowserCache = true; +// 本地模型基路径:必须用「绝对路径」而非绝对 URL——transformers.js 的存在性检查 +// 会把 http(s):// 开头的 localModelPath 当成远端而跳过本地文件检查(配合 allowRemoteModels=false +// 就判成文件不存在)。用 pathname(/weread/models/)让本地分支生效。worker 在 /weread/workers/,故上一级。 +env.localModelPath = new URL('../models/', self.location.href).pathname; +env.backends.onnx.wasm.numThreads = 1; -let classifier: TextClassificationPipeline | null = null; +// 用 AutoTokenizer + AutoModel 分开加载:pipeline 抽象在 DeBERTa-v2 tokenizer 上会 +// 报「this.tokenizer is not a function」,手动 tokenize + 推理更稳 +let tokenizer: PreTrainedTokenizer | null = null; +let model: PreTrainedModel | null = null; +let id2label: Record = { 0: 'not_title', 1: 'title' }; let activeDevice: NlpDevice | null = null; let loading: Promise | null = null; @@ -43,31 +52,42 @@ const toModelProgress = (info: ProgressInfo): ModelProgress => { return progress; }; -/** 按 DEVICE_PRIORITY 依次尝试创建 pipeline,全部失败抛出最后一个错误 */ +/** 按 DEVICE_PRIORITY 依次尝试加载 tokenizer + model,全部失败抛出最后一个错误 */ const createClassifier = async (request: LoadRequest): Promise => { + const progress_callback = (info: ProgressInfo): void => { + post({ operationId: request.operationId, type: 'progress', progress: toModelProgress(info) }); + }; + // tokenizer 只需加载一次(与设备无关) + if (!tokenizer) { + tokenizer = await AutoTokenizer.from_pretrained(request.modelId, { progress_callback }); + } let lastError: unknown = null; const devices = request.device ? [request.device] : DEVICE_PRIORITY; for (const device of devices) { try { - classifier = await pipeline('text-classification', request.modelId, { + model = await AutoModelForSequenceClassification.from_pretrained(request.modelId, { device, - dtype: request.dtype ?? 'q8', - progress_callback: (info: ProgressInfo) => { - post({ operationId: request.operationId, type: 'progress', progress: toModelProgress(info) }); - }, + // 默认 fp32:DeBERTa-v3 的 int8 量化会坏精度、fp16 转换有图型 bug(见 + // docs/chapter-model-deployment.md 2.0)。体积优化(词表裁剪等)解决前先用 fp32。 + dtype: request.dtype ?? 'fp32', + progress_callback, }); + const cfgLabels = (model.config as { id2label?: Record }).id2label; + if (cfgLabels) { + id2label = cfgLabels; + } activeDevice = device; return device; } catch (error) { lastError = error; - classifier = null; + model = null; } } throw lastError instanceof Error ? lastError : new Error(String(lastError)); }; const handleLoad = async (request: LoadRequest): Promise => { - if (classifier && activeDevice) { + if (model && tokenizer && activeDevice) { post({ operationId: request.operationId, type: 'loaded', device: activeDevice }); return; } @@ -81,16 +101,24 @@ const handleLoad = async (request: LoadRequest): Promise => { }; const handleClassify = async (request: ClassifyRequest): Promise => { - if (!classifier) { + if (!model || !tokenizer) { throw new Error('Model not loaded, send a load request first'); } if (request.lines.length === 0) { post({ operationId: request.operationId, type: 'result', scores: [] }); return; } - // top_k: null 返回每行全部标签的得分,交给主线程按标签取用 - const output = (await classifier(request.lines, { top_k: null })) as LabelScore[] | LabelScore[][]; - const scores = normalizeClassifierOutput(output, request.lines.length); + const inputs = tokenizer(request.lines, { padding: true, truncation: true, max_length: 128 }); + // mDeBERTa 不使用 token_type_ids;且多个 [SEP] 会让分词器按段落递增 type_id,与训练时 + // (单串输入全 0)不一致,删掉更稳(实测模型本就忽略它,删除不影响正确的 fp32 结果) + delete (inputs as Record).token_type_ids; + const { logits } = (await model(inputs)) as { logits: { tolist: () => number[][] } }; + // logits 形状 [batch, numLabels],逐行 softmax 后映射成 LabelScore[] + const rows = logits.tolist(); + const scores: LabelScore[][] = rows.map((row) => { + const probs = softmax(row); + return probs.map((score: number, i: number) => ({ label: id2label[i] ?? `LABEL_${i}`, score })); + }); post({ operationId: request.operationId, type: 'result', scores }); }; @@ -106,7 +134,7 @@ self.onmessage = async (event: MessageEvent) => { post({ operationId: request.operationId, type: 'error', - message: error instanceof Error ? error.message : String(error), + message: error instanceof Error ? `${error.message}\n${error.stack ?? ''}`.slice(0, 600) : String(error), }); } }; From 3cfbffa3ad8a380de4226f504f017a1ddcae6823 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 21:46:05 +0800 Subject: [PATCH 22/54] docs: record per-language model direction; update all docs to current state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - deployment 2.3: SELECTED direction — per-language small models + standard- attention backbone (bert-base-chinese/MiniLM), solves size AND the DeBERTa-v3 quantization wall at once (int8 works on standard attention). Table of size/ quant tradeoffs; keep multilingual v3 as fallback; Chinese version first. - journey 9.7/9.8: browser integration proven correct (fp32), three pitfalls (localModelPath must be path not URL, pipeline tokenizer bug, token_type_ids), int8 broke on v3, lesson 16 (trained != deployable). Milestone row for browser. - journey 11 + plan header: current status, per-language next steps. Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 57 +++++++++++++++++++++++++----- docs/chapter-detection-plan.md | 9 ++++- docs/chapter-model-deployment.md | 58 ++++++++++++++++++++++++++----- 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index dd2d9ad..cade8e9 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -266,11 +266,35 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 - 全部走 `ml/.gitignore`(`train/out/`、`export/out/`、`data/out/`、`.venv/`、`*.jsonl`),**模型和数据集绝不进 git**。 - **经验**:训练前就把产物目录加进 gitignore,别等 `git status` 里冒出 1GB 文件才补。定期清 checkpoint。 -### 9.7 ONNX 导出与量化 +### 9.7 ONNX 导出与量化(DeBERTa-v3 的 int8 血泪) - 用 `optimum[onnxruntime]` 导出 + int8 动态量化,optimum 2.1 上脚本直接可用。 -- **量化不损伤判别力**:验证量化后 ONNX 预测与 PyTorch 一致(标题 0.92-0.98、正文 0.002),用**浏览器同款 onnxruntime** 加载 `model_quantized.onnx` 复核,而不是只信 PyTorch。 -- **经验**:量化后必须用**部署时的运行时**(这里是 onnxruntime,不是 PyTorch)复核几个样本,int8 偶尔会显著掉点,早发现。 +- **v3 的 int8 量化坏了**:导出 v3 时我没重验量化模型(只验过 v1/v2),直到浏览器接入才发现—— + int8 的 logits 几乎取反(第一章 title=0.01,per_channel=True 也只到 0.45)。fp32 正确、int8 崩。 + 根因:**DeBERTa-v3 的 disentangled attention 对 int8 动态量化本质不友好**(社区已知)。 +- **经验**:量化后**必须用部署运行时(onnxruntime-web / 浏览器)复核量化模型本身**,别只信 PyTorch, + 也别因为「上个版本没事」就跳过——量化对不同架构差异极大(同 int8,RoFormer 没事、DeBERTa-v3 崩)。 + 这个疏忽让我白导出一轮。详见 [部署文档 2.0](./chapter-model-deployment.md)。 + +### 9.8 浏览器接入:链路全通,踩平三坑,撞上量化墙 + +把 v3 接进浏览器(transformers.js + onnxruntime-web),**fp32 端到端证明正确**:结构化 0.992、 +金庸回目 0.914、正文 0.000,与 PyTorch 完全一致;token id 也逐字比对一致。过程踩平三个真坑: + +1. **`env.localModelPath` 必须是绝对路径不是绝对 URL**:写成 `http://.../models/` 时,transformers.js + 的存在性检查(`get_file_metadata`)把它当远端,配合 `allowRemoteModels=false` 就判成「文件不存在」 + → tokenizer 配置返回 undefined → 崩。改用 `.pathname`(`/weread/models/`)本地分支才生效。 +2. **pipeline 在 DeBERTa-v2 tokenizer 上报 `this.tokenizer is not a function`**:改用 + `AutoTokenizer + AutoModelForSequenceClassification + 手动 softmax`,绕开 pipeline 抽象。 +3. **多个 `[SEP]` 让分词器给出非零 token_type_ids**,与训练时(单串输入全 0)不一致;mDeBERTa 本就 + 不用 token_type_ids,删掉更稳。 + +**结论**:除体积外一切都通。int8 崩(9.7)、fp16 转换有图型 bug、fp32 正确但 1.1GB(其中 771MB 是 +25.1 万多语言词表嵌入,占 69%)。→ **选定新方向:按语言训小模型 + 换标准注意力骨干**(同时解决体积与 +量化,见 [部署文档 2.3](./chapter-model-deployment.md))。 + +> **经验 16**:**「模型训好」离「能上线」还有一整个部署层**——量化、运行时兼容、路径解析、tokenizer +> 特殊字段,每一步都可能静默出错且只在真实运行时暴露。端到端在**目标运行时**里验证,比任何离线指标都重要。 --- @@ -284,6 +308,8 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 | 独立测试集(40 本训练零接触中文书) | **0.988** | 0.21\* | 泛化真值,排除过拟合 | | **模型 v3(+武侠回目,英文降量,完整验证集)** | **0.879** | **0.339** | **金庸回目 0.001→0.945,精度/f1 全面优于 v2** | +| **v3 浏览器实测(fp32,端到端)** | — | — | 结构化 0.992 / 金庸回目 0.914 / 正文 0.000,与 PyTorch 一致 | + \* 独立测试的标签来自规则(仅标「第X章」类),模型额外找出的序言/楔子/语义标题被算作假阳性, 所以精度被低估,真实值更高。召回 0.988 是可信的关键信号——在训练与模型选择都零接触的书上 近满分,直接排除「0.90 是模型选择乐观」的可能。注意两套考卷难度不同:验证集含难的纯语义标题 @@ -298,10 +324,23 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 --- -## 11. 待办 / 后续方向 +## 11. 现状与后续方向 + +**已完成**:规则层(P1,上线级);数据管线(epub TOC + txt 弱标注);模型 v3(验证集 recall 0.879 / +金庸回目 0.945,能力边界清晰);**浏览器端到端推理证明正确**(fp32);懒加载/分包/部署规划成文。 + +**当前唯一阻塞:体积**。v3 fp32 1.1GB,int8 因 DeBERTa-v3 崩、fp16 转换有 bug。 + +**选定方向(2026-07-18):按语言训小模型 + 换标准注意力骨干**(见 [部署文档 2.3](./chapter-model-deployment.md)): + +- **中文版先做**:base `bert-base-chinese`(词表 2.1万、标准注意力 int8 友好),数据用中文 epub 7983 + - 武侠 438。**成败判据:int8 后金庸回目仍判对**(验证「标准注意力 int8 不崩」)。目标 ~50-100MB。 +- **英文版**:MiniLM / distilbert,英文 txt 弱标注数据。 +- **其他语言按需补**;多语言 mDeBERTa v3 保留作兜底(桌面 fp32)。 +- 格式特征(`ml/textfeat.py` / `lib/nlp/features.ts`)语言无关,一套复用,零改动。 + +**体积解决后的接入**:模型输出 union 到规则候选 → `validate.ts` 结构层过滤 → 置信度门控 UI +(low/none 才提示「AI 增强」)→ app 用金庸 / 四世同堂 / 英文书端到端验证。衔接点见部署文档第 7 节。 -- 独立测试集数字回填,若召回仍 ~0.85+ 则泛化成立。 -- 导出 ONNX → 前端候选层接入(模型输出 union 到规则候选 → `validate.ts` 结构层过滤)→ app 用金庸 / 四世同堂 / 英文书验证端到端。 -- **产品决策**:322MB 模型进 PWA 的下载成本;移动端词表裁剪版(~150MB,按 CJK+拉丁+西里尔裁剪);懒加载策略(规则高置信度时不下模型)。 -- 进一步提召回:目录手动编辑 UI 收集用户修正(`source: manual`)作为增量标注 → 迭代飞轮。 -- 精度若仍不够被结构层消化:提高训练 neg-ratio、或阈值上调、或给 validate.ts 加更强的序列约束。 +**长期**:目录手动编辑 UI 收集用户修正(`source: manual`)作为增量标注 → 迭代飞轮;裸口语短语标题 +(能力边界)主要靠这条路补,而非堆训练数据。 diff --git a/docs/chapter-detection-plan.md b/docs/chapter-detection-plan.md index bb909df..32390a1 100644 --- a/docs/chapter-detection-plan.md +++ b/docs/chapter-detection-plan.md @@ -2,8 +2,15 @@ > 分支:`feat/txt-chapter-detection` > 目标:对用户导入的任意格式 txt,自动识别章节边界并提取标题。 -> 架构:三层规则流水线为基座,mDeBERTa-v3-base(浏览器端 ONNX 推理)作为候选生成的增强层。 +> 架构:三层规则流水线为基座,逐行分类模型(浏览器端 ONNX 推理)作为候选生成的增强层。 > 制定日期:2026-07-16 +> +> **⚠️ 本文是初版阶段计划,部分已被后续实践更新。当前进展与决策以这两份为准**: +> [chapter-detection-journey.md](./chapter-detection-journey.md)(历程 + 16 条经验 + 里程碑)、 +> [chapter-model-deployment.md](./chapter-model-deployment.md)(部署方向:按语言小模型)。 +> +> **一句话现状(2026-07-18)**:规则层上线级;模型 v3 训成(金庸回目 0.945)且浏览器 fp32 端到端验证正确; +> 唯一阻塞是体积(DeBERTa-v3 int8 崩),已选定「按语言训标准注意力小模型」解决。 ## 总体架构 diff --git a/docs/chapter-model-deployment.md b/docs/chapter-model-deployment.md index 68aaa7c..d0b58b5 100644 --- a/docs/chapter-model-deployment.md +++ b/docs/chapter-model-deployment.md @@ -1,13 +1,18 @@ # 章节识别模型的浏览器部署规划(懒加载 / 分包 / 缓存) -> 目标:把 322MB 的章节标题模型接进纯前端 PWA,而**不让绝大多数用户付出这个下载成本**。 -> 前置:模型已训成(v2,验证集 recall 0.90 / 独立测试 recall 0.988),推理设施 `lib/nlp/ChapterClassifier` + `workers/nlpWorker.ts` 已就绪。 +> 目标:把章节标题模型接进纯前端 PWA,而**不让绝大多数用户付出下载成本**。 +> 前置:模型 v3 已训成(完整验证集 recall 0.879 / precision 0.339,金庸回目 0.945), +> **浏览器端到端推理已跑通并证明正确**(fp32:结构化 0.992 / 金庸回目 0.914 / 正文 0.000,与 PyTorch 一致); +> 推理设施 `lib/nlp/ChapterClassifier` + `workers/nlpWorker.ts` 已改为本地加载。 > 配套:模型的由来与效果见 [chapter-detection-journey.md](./chapter-detection-journey.md)。 +> +> **当前状态**:推理链路全通,唯一阻塞是**体积**(v3 fp32 1.1GB,int8 因 DeBERTa-v3 崩,见 2.0)。 +> **选定解法:按语言分小模型 + 换标准注意力骨干**(见 2.3),同时解决体积与量化。 这是两个**不同**的问题,杠杆和收益完全不同,分开处理: - **懒加载**:_什么时候_才去下模型(多数用户永远不下)。 -- **分包 / 减体积**:真要下时,_怎么把 322MB 拆小、拆开、可恢复_。 +- **分包 / 减体积**:真要下时,_怎么把模型拆小、拆开、可恢复_(当前走 2.3 的按语言小模型)。 --- @@ -70,6 +75,39 @@ mDeBERTa 的体积里近 2/3 是 25 万 token 的多语言 embedding。裁到实 关键洞察:**加了格式特征后,很多判别信号已在 token 里**,模型未必需要 base 级。可蒸馏小学生模型,或试更小的、量化更友好的多语言编码器(如 MiniLM 系)。留作后续大优化。 +### 2.3 ✅ 选定方向:按语言分模型 + 换标准注意力骨干(同时解决体积与量化) + +**决策(2026-07-18)**:不再走「裁剪那个多语言 mDeBERTa」的路,改为**按语言训练多个小模型,页面按需加载**;多语言 mDeBERTa v3 保留作兜底。 + +**为什么这条路更好**——体积的病根有两个(词表大 + 骨干是 DeBERTa-v3 不好量化),按语言分 + 换骨干**一次解决两个**: + +| | 多语言 mDeBERTa-v3 | 中文版 bert-base-chinese | 中文版 MiniLM-L6 | +| ----------- | -------------------------------- | ------------------------ | ---------------- | +| 词表 | 25.1 万(771MB 嵌入) | 2.1 万(~65MB 嵌入) | 小 | +| 骨干 | 12 层 340MB | 12 层 340MB | **6 层 ~170MB** | +| int8 量化 | **崩**(disentangled attention) | ✅ 标准注意力,正常 | ✅ 正常 | +| int8 后体积 | 338MB(坏的) | **~100MB** | **~50MB** | + +- **关键点:换掉 DeBERTa-v3 骨干,量化墙就没了。** DeBERTa-v3 的 int8 崩溃源于它特殊的 disentangled attention;换成标准 BERT/MiniLM,int8 正常——本会话早期那个 RoFormer 占位模型 int8 就没事,正是标准注意力的佐证(见 [journey 文档](./chapter-detection-journey.md))。 +- **按语言分让词表天然小**:中文版只需中文词表(~2万),不必背 25 万多语言词表。 +- **格式特征语言无关**:`ml/textfeat.py` / `lib/nlp/features.ts` 一套喂所有模型,零改动。 + +**架构**: + +``` +页面检测书的语言(CJK 占比 / 拉丁占比,极简,无需额外模型) + ├─ 中文书 → 中文版(bert-base-chinese 或中文 MiniLM,int8 ~50-100MB) + ├─ 英文书 → 英文版(MiniLM / distilbert,int8 ~50MB) + ├─ 其他语言 → 逐步补(缺什么补什么) + └─ 混合/罕见 → 多语言 mDeBERTa v3 兜底(保留,桌面 fp32,下载罕见) +``` + +**训练数据现成**:中文 epub 7983 + 武侠 438;英文 1840 本 txt(已用 907,可加)。管线搭好,换 base + 换数据子集即可训。 + +**代价(诚实)**:要训 N 个模型(但每个又小又快);多语言 v3 兜底的体积/量化问题不解决,但兜底罕用可接受(桌面 fp32 或以后再裁);换 base = 从头训,不复用 v3 权重。 + +**首个落地**:中文版(主场景 + 数据最多),base 先试 `bert-base-chinese`(已知稳、词表 2.1万、int8 友好)。**成败判据:int8 量化后金庸回目「青衫磊落险峰行」还判对不对**——验证「标准注意力 int8 不崩」这个关键假设。想更小再试中文 MiniLM。 + --- ## 三、分包(怎么把字节拆开传) @@ -104,17 +142,19 @@ mDeBERTa 的体积里近 2/3 是 25 万 token 的多语言 embedding。裁到实 ## 六、落地建议(分层,从零成本到高投入) -| 层 | 做什么 | 成本 | 谁受影响 | -| ----- | ---------------------------------------------------------------- | ----------------- | ------------------------------- | -| **0** | 规则先跑;high 置信度永不下模型;low/none 显示「AI 增强」入口 | 已有信号,改 UI | 所有人,多数在这层就完事 | -| **1** | 运行时代码动态 import + 权重 Range 流式 + 进度条 + OPFS 持久缓存 | 中 | 点了「AI 增强」的少数人,下一次 | -| **2** | 词表裁剪出移动版 + q4,按设备选档 + 版本化 CDN + manifest | 高(要重训/重导) | 移动端 / 全量优化 | +| 层 | 做什么 | 成本 | 谁受影响 | +| ----- | ---------------------------------------------------------------- | ---------------- | ------------------------------- | +| **0** | 规则先跑;high 置信度永不下模型;low/none 显示「AI 增强」入口 | 已有信号,改 UI | 所有人,多数在这层就完事 | +| **1** | 运行时代码动态 import + 权重 Range 流式 + 进度条 + OPFS 持久缓存 | 中 | 点了「AI 增强」的少数人,下一次 | +| **2** | 按语言小模型(2.3):先中文版 bert-base-chinese int8 ~100MB | 中(重训,但轻) | 按书语言各下对应小模型 | +| **3** | 补更多语言版 + manifest 按语言选 + 多语言 v3 兜底 | 逐步 | 长尾语言 / 桌面兜底 | **推荐顺序**: 1. **先做第 0 层**(置信度门控 + 渐进 UX + 「AI 增强」按钮)。纯前端,不碰模型重训,决定 90% 体验,并验证「多数用户不需要下模型」的假设。 2. **接入时顺带第 1 层**(代码分包 + 流式 + OPFS)。这一步同时完成「模型接进浏览器」这件事本身。 -3. **看第 0/1 层的真实下载触发率,再决定第 2 层投入**。如果触发率很低(多数书规则就够),移动裁剪版可以延后甚至不做。 +3. **第 2 层:中文版小模型**(换标准注意力骨干解决量化)。成败判据:int8 后金庸回目仍判对。 +4. **第 3 层按需补语言**,多语言 v3 作兜底。 --- From 70646aa81a88955977d14c9bc5c8775d4c1e5e6d Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 21:50:06 +0800 Subject: [PATCH 23/54] feat: train.py --base for per-language models Swap the backbone (default mdeberta-v3-base) to bert-base-chinese / MiniLM etc. Per docs 2.3: standard-attention backbones quantize to int8 cleanly, avoiding the DeBERTa-v3 quantization wall, and per-language keeps the vocab small. First target: Chinese model on bert-base-chinese. Co-Authored-By: Claude Fable 5 --- ml/train/train.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ml/train/train.py b/ml/train/train.py index b6cf7f2..e161891 100644 --- a/ml/train/train.py +++ b/ml/train/train.py @@ -32,7 +32,9 @@ sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from textfeat import make_text # noqa: E402 -MODEL_ID = "microsoft/mdeberta-v3-base" +# 默认多语言 base;按语言分模型时用 --base 换成 bert-base-chinese / MiniLM 等 +# (标准注意力骨干 int8 量化友好,避开 DeBERTa-v3 的量化崩溃,见 docs/chapter-model-deployment.md 2.3) +DEFAULT_BASE = "microsoft/mdeberta-v3-base" MAX_LEN = 128 # 正类标签需与前端 lib/nlp/index.ts 的 DEFAULT_POSITIVE_LABEL 保持一致 LABELS = ["not_title", "title"] @@ -98,6 +100,7 @@ def compute_metrics(pred) -> dict: def main() -> int: ap = argparse.ArgumentParser() ap.add_argument("--data", required=True) + ap.add_argument("--base", default=DEFAULT_BASE, help="预训练 base,如 bert-base-chinese(标准注意力,int8 友好)") ap.add_argument("--out", default="out/model") ap.add_argument("--epochs", type=float, default=2.0) ap.add_argument("--batch", type=int, default=16) @@ -138,7 +141,7 @@ def main() -> int: dev_pos = sum(r["label"] for r in dev_recs) print(f"训练 {len(train_recs)} 行(正 {train_pos}), 验证 {len(dev_recs)} 行(正 {dev_pos})") - tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) + tokenizer = AutoTokenizer.from_pretrained(args.base) def encode(batch): texts = [ @@ -154,7 +157,7 @@ def encode(batch): dev_ds = Dataset.from_list(dev_recs).map(encode, batched=True, remove_columns=cols) model = AutoModelForSequenceClassification.from_pretrained( - MODEL_ID, + args.base, num_labels=len(LABELS), id2label=dict(enumerate(LABELS)), label2id={label: i for i, label in enumerate(LABELS)}, From 5bf14a193e054f151f36bdb6cf4ab957eefedd1e Mon Sep 17 00:00:00 2001 From: chaxus Date: Sat, 18 Jul 2026 23:36:56 +0800 Subject: [PATCH 24/54] =?UTF-8?q?docs:=20per-language=20architecture=20val?= =?UTF-8?q?idated=20=E2=80=94=20Chinese=20model=20int8=20works?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Decisive result: standard-attention backbone quantizes to int8 cleanly, solving both size and the DeBERTa-v3 quantization wall. - bert-base-chinese too weak (recall 0.43, fails 第一章) — weak base memorizes vs generalizes; switched to chinese-roberta-wwm-ext (recall 0.81, structural titles 0.95) - int8 preserved: 第一章 0.921 (fp32 0.948) vs DeBERTa-v3 int8 0.01 (inverted) - 103MB; browser onnxruntime-web int8 matches Python (第一章 0.917) - lesson: 'quantizable' and 'strong enough' are separate axes — verify both Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 1 + docs/chapter-model-deployment.md | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index cade8e9..7500da2 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -309,6 +309,7 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 | **模型 v3(+武侠回目,英文降量,完整验证集)** | **0.879** | **0.339** | **金庸回目 0.001→0.945,精度/f1 全面优于 v2** | | **v3 浏览器实测(fp32,端到端)** | — | — | 结构化 0.992 / 金庸回目 0.914 / 正文 0.000,与 PyTorch 一致 | +| **中文版 chinese-roberta-wwm-ext(int8 103MB)** | 0.81 | 0.85 | **int8 不崩**(第一章 0.92)、浏览器实测一致——按语言路线验证成立 | \* 独立测试的标签来自规则(仅标「第X章」类),模型额外找出的序言/楔子/语义标题被算作假阳性, 所以精度被低估,真实值更高。召回 0.988 是可信的关键信号——在训练与模型选择都零接触的书上 diff --git a/docs/chapter-model-deployment.md b/docs/chapter-model-deployment.md index d0b58b5..ea1a2ba 100644 --- a/docs/chapter-model-deployment.md +++ b/docs/chapter-model-deployment.md @@ -79,6 +79,16 @@ mDeBERTa 的体积里近 2/3 是 25 万 token 的多语言 embedding。裁到实 **决策(2026-07-18)**:不再走「裁剪那个多语言 mDeBERTa」的路,改为**按语言训练多个小模型,页面按需加载**;多语言 mDeBERTa v3 保留作兜底。 +> **✅ 已验证成立(2026-07-18)——中文版跑通端到端**: +> +> - base 选型踩了一步:**bert-base-chinese 太弱**(recall 0.43,连「第一章 风雪夜」都判 0.02,只认高频词「后记」——弱 base 只记忆不泛化);换 **chinese-roberta-wwm-ext** 后结构化标题全部拿下(第一章 0.948、第二章 0.956、后记 0.957),eval recall 0.81。 +> - **int8 量化不崩**(决定性判据):roberta int8 后第一章 0.921(fp32 0.948,掉点微乎其微),对照 DeBERTa-v3 的 int8 第一章 0.01(取反崩溃)。**证明「标准注意力 int8 友好」这个核心假设成立**。 +> - **体积 103MB**(v3 是坏掉的 338MB)。 +> - **浏览器 onnxruntime-web int8 实测一致**:第一章 0.917、第二章 0.939、后记 0.953、正文 0.001,与 Python 一致。 +> - 唯一弱点:裸金庸短语(去数字前缀的「青衫磊落险峰行」)0.21,比 v3 的 0.945 弱;但真实武侠回目带数字前缀(「一 青衫磊落险峰行」)能接住,结构化书(绝大多数)完美。 +> - 产物:`ml/train/out/model_zh`、`ml/export/out/zh/model_quantized.onnx`、部署于 `public/models/chapter-title-zh/`。 +> - **经验**:「量化友好」和「够强」是两个维度——bert-base-chinese 占前者不占后者,DeBERTa-v3 反之,chinese-roberta-wwm-ext 两者兼得。选 base 要同时验证这两点。 + **为什么这条路更好**——体积的病根有两个(词表大 + 骨干是 DeBERTa-v3 不好量化),按语言分 + 换骨干**一次解决两个**: | | 多语言 mDeBERTa-v3 | 中文版 bert-base-chinese | 中文版 MiniLM-L6 | From 00807b9432a171a5e3e25717686d280b9ff57a99 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sun, 19 Jul 2026 06:48:15 +0800 Subject: [PATCH 25/54] feat: wire per-language model into chapter detection (browser e2e proven) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit detectChaptersWithModel: language-agnostic pipeline that runs the model on title-like lines, unions with rule candidates, and hands off to the validate.ts structure layer (model titles = an unnumbered family that competes with rule families — structural books let precise numbered rules win, semantic books let the model win). Browser end-to-end verified with the Chinese int8 model (103MB, WebGPU): - structural book: 楔子/第一章.../第四章 correct - 金庸-style space-separated 回目 (一 青衫磊落险峰行 …): rules return [], model+structure returns all four — the exact value rules can't deliver - lib/nlp/detectLanguage.ts: CJK/Latin ratio → pick language model - pre-filter to short + non-terminal-punct lines cut runtime 33s→1.8s - ChapterClassifier positive label 'title' (matches trained id2label) - 3 modelDetect tests with a mock classifier Co-Authored-By: Claude Fable 5 --- lib/chapter/__tests__/modelDetect.test.ts | 55 ++++++++++++ lib/chapter/modelDetect.ts | 104 ++++++++++++++++++++++ lib/chapter/validate.ts | 3 + lib/nlp/__tests__/nlp.test.ts | 10 +-- lib/nlp/detectLanguage.ts | 41 +++++++++ lib/nlp/index.ts | 3 +- 6 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 lib/chapter/__tests__/modelDetect.test.ts create mode 100644 lib/chapter/modelDetect.ts create mode 100644 lib/nlp/detectLanguage.ts diff --git a/lib/chapter/__tests__/modelDetect.test.ts b/lib/chapter/__tests__/modelDetect.test.ts new file mode 100644 index 0000000..2c71887 --- /dev/null +++ b/lib/chapter/__tests__/modelDetect.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it, vi } from 'vitest'; +import { detectChaptersWithModel } from '../modelDetect'; + +const filler = (chars: number): string => { + const sentence = '段誉在无量剑湖畔遇到了神农帮的众人,一场恶斗即将展开,局势凶险万分。'; + let out = ''; + while (out.length < chars) { + out += sentence + '\n'; + } + return out; +}; + +/** 模拟分类器:makeModelInput 里 text 段短且不像正文的判为标题 */ +const fakeClassify = (titleTexts: Set) => { + return vi.fn(async (inputs: string[]) => { + return inputs.map((input) => { + // makeModelInput 格式:feats [SEP] prev [SEP] text [SEP] next + const parts = input.split(' [SEP] '); + const text = parts[2] ?? ''; + return titleTexts.has(text) ? 0.95 : 0.02; + }); + }); +}; + +describe('detectChaptersWithModel', () => { + it('模型接住规则漏掉的空格分隔回目(金庸式)', async () => { + const titles = ['一 青衫磊落险峰行', '二 玉壁月华明', '三 马疾香幽', '四 崖高人远']; + const text = titles.map((t) => `${t}\n${filler(500)}`).join('\n'); + const classify = fakeClassify(new Set(titles)); + + const chapters = await detectChaptersWithModel(text, classify, { threshold: 0.5 }); + expect(chapters.map((c) => c.title)).toEqual(titles); + // 只对短的标题候选行调用模型,不对每一行 + const classifiedCount = classify.mock.calls[0][0].length; + expect(classifiedCount).toBeLessThan(text.split('\n').filter(Boolean).length); + }); + + it('预过滤:以句末标点结尾的正文行不送模型', async () => { + const text = ['第一章 起点', filler(300), '第二章 结局', filler(300)].join('\n'); + const classify = fakeClassify(new Set(['第一章 起点', '第二章 结局'])); + await detectChaptersWithModel(text, classify, { threshold: 0.5 }); + const sentToModel: string[] = classify.mock.calls[0][0].map((input: string) => input.split(' [SEP] ')[2]); + // 填充正文以「。」结尾,不应出现在送模型的候选里 + expect(sentToModel.some((t) => t.endsWith('。'))).toBe(false); + }); + + it('边界成链,end 指向下一章起点', async () => { + const titles = ['一 起点', '二 转折', '三 结局']; + const text = titles.map((t) => `${t}\n${filler(500)}`).join('\n'); + const chapters = await detectChaptersWithModel(text, fakeClassify(new Set(titles)), { threshold: 0.5 }); + expect(chapters).toHaveLength(3); + expect(chapters[0].end).toBe(chapters[1].start); + expect(chapters[2].end).toBe(text.length); + }); +}); diff --git a/lib/chapter/modelDetect.ts b/lib/chapter/modelDetect.ts new file mode 100644 index 0000000..5f2ec9c --- /dev/null +++ b/lib/chapter/modelDetect.ts @@ -0,0 +1,104 @@ +import { makeModelInput } from '@/lib/nlp/features'; +import { collectCandidates, MAX_TITLE_LENGTH } from './candidates'; +import type { Candidate } from './candidates'; +import { validateCandidates } from './validate'; +import type { DetectedChapter } from './index'; + +/** 模型判出的标题构成一个无编号家族,与规则家族一起竞争,交 validate 结构层过滤 */ +export const MODEL_FAMILY_ID = 'model'; + +/** 句末标点:以这些结尾的行几乎不是标题,预过滤时排除(与 ml/textfeat.py TERMINAL_PUNCT 一致) */ +const TERMINAL_PUNCT = new Set('。!?.!?;;::,,、'); + +interface Line { + text: string; + start: number; +} + +/** 按 \n 切成非空行(去首尾空白),记录每行在原文的偏移 */ +const splitLines = (text: string): Line[] => { + const lines: Line[] = []; + let offset = 0; + while (offset <= text.length) { + const nl = text.indexOf('\n', offset); + const end = nl === -1 ? text.length : nl; + const t = text.slice(offset, end).replace(/\r/g, '').trim(); + if (t.length > 0) { + lines.push({ text: t, start: offset }); + } + if (nl === -1) { + break; + } + offset = nl + 1; + } + return lines; +}; + +/** 逐行分类器:输入 makeModelInput 拼好的字符串数组,返回每行「是标题」的概率 */ +export type ClassifyLines = (inputs: string[]) => Promise; + +export interface ModelDetectOptions { + /** 判为标题的概率阈值 */ + threshold?: number; +} + +/** + * @description: 模型增强的章节识别。只对「像标题的短行」跑模型(省算力,特征仍取真实前后行), + * 模型判出的标题作为一个无编号家族,与规则候选 union 后交 `validate.ts` 结构层过滤 + * (家族竞争 / 间距 / 覆盖度)。结构化书规则家族胜出(更精确),语义书模型家族胜出。 + * @param {string} text 已将换行归一化为 \n 的全文 + * @param {ClassifyLines} classify 逐行分类器(来自 ChapterClassifier) + * @return {DetectedChapter[]} + */ +export const detectChaptersWithModel = async ( + text: string, + classify: ClassifyLines, + options: ModelDetectOptions = {}, +): Promise => { + const threshold = options.threshold ?? 0.5; + const lines = splitLines(text); + const total = lines.length || 1; + + // 预过滤「可能是标题的行」:够短、且不以句末标点结尾(标题几乎不以「。」结尾, + // 这是最强特征)。把绝大多数正文行挡在模型之外,推理量从「所有短行」降到真正的标题候选。 + const candIdx: number[] = []; + for (let i = 0; i < lines.length; i++) { + const t = lines[i].text; + const last = t[t.length - 1]; + if ([...t].length <= MAX_TITLE_LENGTH && !TERMINAL_PUNCT.has(last)) { + candIdx.push(i); + } + } + const inputs = candIdx.map((i) => + makeModelInput({ + prev: i > 0 ? lines[i - 1].text : '', + text: lines[i].text, + next: i + 1 < lines.length ? lines[i + 1].text : '', + pos: i / total, + }), + ); + + const probs = inputs.length > 0 ? await classify(inputs) : []; + const modelCands: Candidate[] = []; + candIdx.forEach((i, k) => { + if (probs[k] >= threshold) { + modelCands.push({ + familyId: MODEL_FAMILY_ID, + special: false, + title: lines[i].text, + start: lines[i].start, + lineIndex: i, + seq: null, + }); + } + }); + + // union 规则候选 → 结构层过滤(家族竞争选出规则或模型家族) + const all = [...collectCandidates(text), ...modelCands]; + const validation = validateCandidates(all, text.length); + return validation.chapters.map((chapter, index) => ({ + title: chapter.title, + start: chapter.start, + end: validation.chapters[index + 1]?.start ?? text.length, + })); +}; diff --git a/lib/chapter/validate.ts b/lib/chapter/validate.ts index e3e3261..407ce78 100644 --- a/lib/chapter/validate.ts +++ b/lib/chapter/validate.ts @@ -11,6 +11,9 @@ const FAMILY_WEIGHTS: Record = { 'roman-line': 0.8, 'num-enum': 0.7, bracket: 0.5, + // 模型判出的无编号标题家族;权重高于 bracket,低于带编号的规则家族, + // 使结构化书仍由精确的编号规则胜出,语义书才由模型家族接管 + model: 0.8, }; export interface ValidatedChapter { diff --git a/lib/nlp/__tests__/nlp.test.ts b/lib/nlp/__tests__/nlp.test.ts index 089cf09..10d7cb2 100644 --- a/lib/nlp/__tests__/nlp.test.ts +++ b/lib/nlp/__tests__/nlp.test.ts @@ -78,7 +78,7 @@ describe('ChapterClassifier 协议', () => { expect(worker.sent[0]).toMatchObject({ type: 'load', modelId: 'test/model' }); }); - it('classifyLines:按 LABEL_1 映射为标题概率', async () => { + it('classifyLines:按 title 标签映射为标题概率', async () => { const { classifier, worker } = createClassifier(); const promise = classifier.classifyLines(['第一章 起点', '正文内容']); @@ -88,12 +88,12 @@ describe('ChapterClassifier 协议', () => { type: 'result', scores: [ [ - { label: 'LABEL_0', score: 0.1 }, - { label: 'LABEL_1', score: 0.9 }, + { label: 'not_title', score: 0.1 }, + { label: 'title', score: 0.9 }, ], [ - { label: 'LABEL_0', score: 0.8 }, - { label: 'LABEL_1', score: 0.2 }, + { label: 'not_title', score: 0.8 }, + { label: 'title', score: 0.2 }, ], ], }); diff --git a/lib/nlp/detectLanguage.ts b/lib/nlp/detectLanguage.ts new file mode 100644 index 0000000..98cb0bf --- /dev/null +++ b/lib/nlp/detectLanguage.ts @@ -0,0 +1,41 @@ +/** + * 书籍语言检测——用于选择对应的语言专属模型(见 docs/chapter-model-deployment.md 2.3)。 + * 只需区分中文 / 英文 / 其他,靠字符占比即可,无需额外模型。 + */ + +export type BookLang = 'zh' | 'en' | 'other'; + +/** 已训练/部署的语言专属模型;其余语言走多语言兜底或纯规则 */ +export const MODEL_BY_LANG: Partial> = { + zh: 'chapter-title-zh', + // en: 'chapter-title-en', // 待训 +}; + +/** + * 按 CJK / 拉丁字符占比判定主语言。取前若干字符采样即可,不必扫全文。 + */ +export const detectLanguage = (text: string, sampleSize = 20000): BookLang => { + const sample = text.slice(0, sampleSize); + let cjk = 0; + let latin = 0; + for (const ch of sample) { + const c = ch.codePointAt(0) ?? 0; + // CJK 统一表意文字(含扩展 A 常用区) + if ((c >= 0x4e00 && c <= 0x9fff) || (c >= 0x3400 && c <= 0x4dbf)) { + cjk++; + } else if ((c >= 0x41 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a)) { + latin++; + } + } + if (cjk === 0 && latin === 0) { + return 'other'; + } + if (cjk >= latin) { + return 'zh'; + } + // 拉丁明显占多才判英文;夹杂少量 CJK 的仍归中文 + return latin > cjk * 3 ? 'en' : 'zh'; +}; + +/** 该语言是否有已部署的专属模型 */ +export const modelIdForLang = (lang: BookLang): string | undefined => MODEL_BY_LANG[lang]; diff --git a/lib/nlp/index.ts b/lib/nlp/index.ts index cc8142f..127eece 100644 --- a/lib/nlp/index.ts +++ b/lib/nlp/index.ts @@ -12,7 +12,8 @@ import type { import { toTitleScores } from './score'; /** 微调模型的正类标签,P3 训练脚本需与此保持一致 */ -export const DEFAULT_POSITIVE_LABEL = 'LABEL_1'; +// 自训模型的正类标签为 'title'(config.json id2label),与 ml/train/train.py LABELS 一致 +export const DEFAULT_POSITIVE_LABEL = 'title'; export interface LoadModelOptions { modelId?: string; From b90ec933f2d70dec7d1b6d09dd6f668f95b5eb20 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sun, 19 Jul 2026 07:07:25 +0800 Subject: [PATCH 26/54] =?UTF-8?q?feat:=20AI-enhance=20catalogue=20UI=20?= =?UTF-8?q?=E2=80=94=20confidence-gated=20model=20enhancement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wires the per-language model into the reading page end-to-end: - resolveBookChapters records detected lang; canEnhanceWithModel gates the 'Enhance with AI' entry (rules low/none confidence + a model exists for the language + not manual) - enhanceChaptersWithModel: lazy-loads the language model (progress callback), re-detects via detectChaptersWithModel, saves source:'model', returns null if the model didn't beat rules - book-detail (desktop+mobile): button + download/detecting progress; on success rebuilds the syntax tree; result cached so reopen skips the model - i18n strings (zh-CN/zh-HK/en) Verified in the app UI: 金庸 space-separated 回目 book — rules give low confidence and the button appears; enhancement yields all four 回目; reopen uses the cached model result and hides the button. Co-Authored-By: Claude Fable 5 --- locales/en.json | 6 ++- locales/zh-CN.json | 6 ++- locales/zh-HK.json | 6 ++- pages/book-detail/index.tsx | 86 ++++++++++++++++++++++++++++++++++++- store/chapters.ts | 76 ++++++++++++++++++++++++++++++++ 5 files changed, 175 insertions(+), 5 deletions(-) diff --git a/locales/en.json b/locales/en.json index 5af6cd0..d6d7475 100644 --- a/locales/en.json +++ b/locales/en.json @@ -25,5 +25,9 @@ "books-theHunchbackOfNotreDame-author": "Victor Hugo", "books-janeEyre-author": "Charlotte Brontë", "books-walden-author": "Henry David Thoreau", - "books-snowWhite-author": "The Brothers Grimm" + "books-snowWhite-author": "The Brothers Grimm", + "enhanceCatalogue": "Enhance with AI", + "enhanceHint": "Rules may miss chapters — re-detect with the AI model (downloads once)", + "modelDownloading": "Downloading model", + "modelEnhancing": "Detecting" } diff --git a/locales/zh-CN.json b/locales/zh-CN.json index 3a59b0b..13de9d0 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -25,5 +25,9 @@ "books-theHunchbackOfNotreDame-author": "维克多·雨果", "books-janeEyre-author": "夏洛蒂·勃朗特", "books-walden-author": "亨利·戴维·梭罗", - "books-snowWhite-author": "格林兄弟" + "books-snowWhite-author": "格林兄弟", + "enhanceCatalogue": "AI 增强目录", + "enhanceHint": "规则识别可能漏章,点击用 AI 模型重新识别(首次需下载模型)", + "modelDownloading": "下载模型", + "modelEnhancing": "识别中" } diff --git a/locales/zh-HK.json b/locales/zh-HK.json index 82ebe63..9355621 100644 --- a/locales/zh-HK.json +++ b/locales/zh-HK.json @@ -25,5 +25,9 @@ "books-theHunchbackOfNotreDame-author": "維克多·雨果", "books-janeEyre-author": "夏洛蒂·勃朗特", "books-walden-author": "亨利·戴維·梭羅", - "books-snowWhite-author": "格林兄弟" + "books-snowWhite-author": "格林兄弟", + "enhanceCatalogue": "AI 增強目錄", + "enhanceHint": "規則識別可能漏章,點擊用 AI 模型重新識別(首次需下載模型)", + "modelDownloading": "下載模型", + "modelEnhancing": "識別中" } diff --git a/pages/book-detail/index.tsx b/pages/book-detail/index.tsx index 55b4330..d75c459 100644 --- a/pages/book-detail/index.tsx +++ b/pages/book-detail/index.tsx @@ -2,9 +2,10 @@ import { useEffect, useRef, useState } from 'react'; import { debounce, getQuery } from 'ranuts/utils'; import { getBookById } from '@/store/books'; -import { resolveBookChapters } from '@/store/chapters'; +import { canEnhanceWithModel, enhanceChaptersWithModel, resolveBookChapters } from '@/store/chapters'; import { transformTextToExpectedFormat } from '@/lib/transformText'; import type { BookInfo } from '@/store/books'; +import type { DetectedChapter } from '@/lib/chapter'; import type { TextSyntaxTree } from '@/lib/transformText'; import { ROUTE_PATH } from '@/router'; import { BookDetailOperate, MobileBookDetailOperate } from '@/components/DetailOperate'; @@ -73,6 +74,11 @@ export const DesktopBookDetail = (): React.JSX.Element => { const bookDetail: BookInfo = getCurrentBookDetail(); const textSyntaxTree: TextSyntaxTree = getTextSyntaxTree(); const pageNum: number = getPageNum(); + // 模型增强:规则置信度低且该语言有模型时提供「AI 增强」入口 + const contentRef = useRef | null>(null); + const ruleChaptersRef = useRef([]); + const [canEnhance, setCanEnhance] = useState(false); + const [enhanceProgress, setEnhanceProgress] = useState(null); const updateUI = () => { debounce(() => { @@ -80,6 +86,31 @@ export const DesktopBookDetail = (): React.JSX.Element => { }, 16)(); }; + const runEnhance = async () => { + if (!id || !contentRef.current || enhanceProgress !== null) return; + setEnhanceProgress(0); + try { + const enhanced = await enhanceChaptersWithModel(id, contentRef.current, ruleChaptersRef.current, { + onProgress: (p) => { + if (typeof p.progress === 'number') setEnhanceProgress(Math.round(p.progress)); + }, + }); + setCanEnhance(false); + if (enhanced && showContainerRef.current) { + const tree = transformTextToExpectedFormat({ + content: contentRef.current, + title: bookDetail?.title ?? '', + container: showContainerRef.current, + chapters: enhanced.chapters, + }); + setTextSyntaxTree(tree); + setPageNum(0); + } + } finally { + setEnhanceProgress(null); + } + }; + const getTitle = () => { const textSyntaxTree: TextSyntaxTree = getTextSyntaxTree(); const pageNum: number = getPageNum(); @@ -120,6 +151,10 @@ export const DesktopBookDetail = (): React.JSX.Element => { chapters: bookChapters.chapters, }); setTextSyntaxTree(textSyntaxTree); + // 规则置信度低时,允许用户点击「AI 增强」用模型重识别 + contentRef.current = content; + ruleChaptersRef.current = bookChapters.chapters; + setCanEnhance(canEnhanceWithModel(bookChapters)); ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); }); } @@ -156,7 +191,21 @@ export const DesktopBookDetail = (): React.JSX.Element => { {bookDetail?.title} -
+
+ {enhanceProgress !== null && ( + + {enhanceProgress > 0 ? `${t('modelDownloading')} ${enhanceProgress}%` : t('modelEnhancing')} + + )} + {canEnhance && enhanceProgress === null && ( + + {t('enhanceCatalogue')} + + )} {t('home')} @@ -224,6 +273,35 @@ export const MobileBookDetail = (): React.JSX.Element => { const totalPage: number = textSyntaxTree.totalPage; const pageNum: number = getPageNum(); const { id } = getQuery(); + const contentRef = useRef | null>(null); + const ruleChaptersRef = useRef([]); + const [canEnhance, setCanEnhance] = useState(false); + const [enhanceProgress, setEnhanceProgress] = useState(null); + + const runEnhance = async () => { + if (!id || !contentRef.current || enhanceProgress !== null) return; + setEnhanceProgress(0); + try { + const enhanced = await enhanceChaptersWithModel(id, contentRef.current, ruleChaptersRef.current, { + onProgress: (p) => { + if (typeof p.progress === 'number') setEnhanceProgress(Math.round(p.progress)); + }, + }); + setCanEnhance(false); + if (enhanced && showContainerRef.current) { + const tree = transformTextToExpectedFormat({ + content: contentRef.current, + title: getCurrentBookDetail()?.title ?? '', + container: showContainerRef.current, + chapters: enhanced.chapters, + }); + setTextSyntaxTree(tree); + setPageNum(0); + } + } finally { + setEnhanceProgress(null); + } + }; const updateUI = () => { debounce(() => { @@ -251,6 +329,10 @@ export const MobileBookDetail = (): React.JSX.Element => { chapters: bookChapters.chapters, }); setTextSyntaxTree(textSyntaxTree); + // 规则置信度低时,允许用户点击「AI 增强」用模型重识别 + contentRef.current = content; + ruleChaptersRef.current = bookChapters.chapters; + setCanEnhance(canEnhanceWithModel(bookChapters)); ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); }); } diff --git a/store/chapters.ts b/store/chapters.ts index aa30838..dc9d080 100644 --- a/store/chapters.ts +++ b/store/chapters.ts @@ -1,6 +1,11 @@ import { db } from '@/store/index'; import { CHAPTER_ALGO_VERSION, detectChaptersDetailed } from '@/lib/chapter'; import type { ChapterConfidence, DetectedChapter } from '@/lib/chapter'; +import { detectChaptersWithModel } from '@/lib/chapter/modelDetect'; +import { ChapterClassifier } from '@/lib/nlp'; +import type { ModelProgress } from '@/lib/nlp'; +import { detectLanguage, modelIdForLang } from '@/lib/nlp/detectLanguage'; +import type { BookLang } from '@/lib/nlp/detectLanguage'; import { arrayBufferToString, extractCaptionTitleChapters } from '@/lib/transformText'; export const STORE_NAME_BOOKS_CHAPTERS_KEY = 'books_chapters'; @@ -15,6 +20,8 @@ export interface BookChapters { confidence: ChapterConfidence; familyId: string | null; source: ChapterSource; + /** 书籍主语言,决定用哪个语言模型增强;旧缓存可能无此字段 */ + lang?: BookLang; /** 生成结果时的规则算法版本,用于算法升级后失效重算 */ algoVersion: number; modifyTime: number; @@ -68,6 +75,7 @@ export const resolveBookChapters = async ( return cached; } const text = arrayBufferToString(content).replace(/(?:\r\n|\r|\n)+/g, '\n') || ''; + const lang = detectLanguage(text); const captionChapters = extractCaptionTitleChapters(text); let record: Omit; @@ -78,6 +86,7 @@ export const resolveBookChapters = async ( confidence: 'high', familyId: null, source: 'caption', + lang, }; } else { const detection = detectChaptersDetailed(text); @@ -87,12 +96,79 @@ export const resolveBookChapters = async ( confidence: detection.confidence, familyId: detection.familyId, source: 'rules', + lang, }; } await saveChapters(record); return { ...record, algoVersion: CHAPTER_ALGO_VERSION, modifyTime: Date.now() }; }; +/** + * 是否值得对这本书做模型增强:规则置信度低(可能漏章)、且该语言有已部署的模型、 + * 且当前不是手动修正结果(手动优先)。UI 据此决定要不要显示「AI 增强」入口。 + */ +export const canEnhanceWithModel = (record: BookChapters): boolean => { + if (record.source === 'manual' || record.source === 'model') { + return false; + } + if (record.confidence === 'high') { + return false; + } + return record.lang !== undefined && modelIdForLang(record.lang) !== undefined; +}; + +// 语言模型客户端单例:切换语言时才重建,避免重复下载 +let classifier: ChapterClassifier | null = null; +let loadedModelId: string | null = null; + +export interface EnhanceOptions { + onProgress?: (progress: ModelProgress) => void; + threshold?: number; +} + +/** + * 用语言模型重新识别章节,结果写缓存(source: 'model')并返回。 + * 模型未改善(识别数不多于规则)或该语言无模型时返回 null,调用方保持规则结果。 + * 模型懒加载:首次调用才下载对应语言模型(带进度回调)。 + */ +export const enhanceChaptersWithModel = async ( + id: string, + content: ArrayBuffer | Uint8Array, + ruleChapters: DetectedChapter[], + options: EnhanceOptions = {}, +): Promise => { + const text = arrayBufferToString(content).replace(/(?:\r\n|\r|\n)+/g, '\n') || ''; + const lang = detectLanguage(text); + const modelId = modelIdForLang(lang); + if (!modelId) { + return null; + } + if (!classifier || loadedModelId !== modelId) { + classifier?.dispose(); + classifier = new ChapterClassifier(); + await classifier.load({ modelId, dtype: 'q8', onProgress: options.onProgress }); + loadedModelId = modelId; + } + const activeClassifier = classifier; + const chapters = await detectChaptersWithModel(text, (inputs) => activeClassifier.classifyLines(inputs), { + threshold: options.threshold, + }); + // 模型没找到更多章节就不覆盖规则结果(避免越增强越差) + if (chapters.length <= ruleChapters.length) { + return null; + } + const record: Omit = { + id, + chapters, + confidence: 'high', + familyId: null, + source: 'model', + lang, + }; + await saveChapters(record); + return { ...record, algoVersion: CHAPTER_ALGO_VERSION, modifyTime: Date.now() }; +}; + /** 删除某本书的章节缓存(删书或手动重置时用) */ export const deleteChapters = async (id: string): Promise => { try { From 46047db45edee2f934226773f60182f0ed3474f8 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sun, 19 Jul 2026 07:32:24 +0800 Subject: [PATCH 27/54] feat: English chapter-title model (distilbert int8 67MB), register en MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second per-language model, same approach as Chinese: - distilbert-base-uncased on English epub TOCs + txt weak-supervision (8949 positives); eval recall 0.94 on real English titles - int8 verified identical to fp32 on real dev data (Chapter N - Title 0.999) — standard attention quantizes cleanly, 67MB (6-layer distil < roberta) - browser e2e: 'en' auto-detected → chapter-title-en loaded (WebGPU) → all four 'Chapter N - Title' detected, 763ms - register en in MODEL_BY_LANG Note: probe on isolated bare 'CHAPTER XII' misleads (0.001) — features from synthetic context don't match real distribution; on real prev/next/pos the model nails it. English chapter formats are regular so rules already cover much; the model mainly adds title-bearing/irregular variants. Co-Authored-By: Claude Fable 5 --- lib/nlp/detectLanguage.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/nlp/detectLanguage.ts b/lib/nlp/detectLanguage.ts index 98cb0bf..764c448 100644 --- a/lib/nlp/detectLanguage.ts +++ b/lib/nlp/detectLanguage.ts @@ -7,8 +7,8 @@ export type BookLang = 'zh' | 'en' | 'other'; /** 已训练/部署的语言专属模型;其余语言走多语言兜底或纯规则 */ export const MODEL_BY_LANG: Partial> = { - zh: 'chapter-title-zh', - // en: 'chapter-title-en', // 待训 + zh: 'chapter-title-zh', // chinese-roberta-wwm-ext int8 103MB + en: 'chapter-title-en', // distilbert-base-uncased int8 67MB }; /** From bb1e83bf445dcd540082e7b6b7c7d5087ddb2b85 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sun, 19 Jul 2026 07:40:06 +0800 Subject: [PATCH 28/54] docs: record per-language model lessons (Chinese + English) - journey 9.9: two per-language small models + frontend integration; new lessons 17-19 (quantizable vs strong-enough are separate axes; probe with real context not synthetic lines; weak-base failure mode is memorize-not- generalize) - milestone table: Chinese (int8 103MB, recall 0.81) + English (int8 67MB, recall 0.94) rows - deployment 2.3: English validation block + frontend integration summary Co-Authored-By: Claude Fable 5 --- docs/chapter-detection-journey.md | 15 +++++++++++++++ docs/chapter-model-deployment.md | 10 ++++++++++ 2 files changed, 25 insertions(+) diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index 7500da2..a12782e 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -296,6 +296,20 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 > **经验 16**:**「模型训好」离「能上线」还有一整个部署层**——量化、运行时兼容、路径解析、tokenizer > 特殊字段,每一步都可能静默出错且只在真实运行时暴露。端到端在**目标运行时**里验证,比任何离线指标都重要。 +### 9.9 按语言分模型:两个小模型 + 前端接入落地 + +体积/量化墙的解法是**按语言训小模型 + 换标准注意力骨干**(用户提出,见部署文档 2.3)。落地了两个: + +- **中文版**:base 踩了一步——`bert-base-chinese` **太弱**(eval recall 0.43,连「第一章 风雪夜」都判 0.02,只认高频词「后记」——弱 base 只记忆不泛化);换 `chinese-roberta-wwm-ext`(12 层,训练充分)→ recall 0.81、结构化标题 0.95。**int8 不崩**(第一章 fp32 0.948→int8 0.921,对照 DeBERTa-v3 int8 0.01 取反)。**103MB**。 +- **英文版**:`distilbert-base-uncased`(6 层,更小)→ eval recall 0.94(英文标题规整)。int8 与 fp32 在真实 dev 数据上**逐一相同**(Chapter N - Title 0.999)。**67MB**。 +- **前端接入**:`detectLanguage`(CJK/拉丁占比)自动选模型;`detectChaptersWithModel` 把模型标题作为无编号家族 union 规则候选、交 `validate.ts` 结构层竞争过滤(结构化书规则胜出、语义书模型胜出);**预过滤「短+非句末标点行」把耗时 33s→1.8s**。置信度门控 UI:规则 low/none 才显「AI 增强」按钮,点击懒加载模型、增强、缓存(source:'model'),重开用缓存。**实测**:金庸空格回目书规则给空、模型增强产出 4 回目。 + +> **经验 17**:**「量化友好」和「够强」是两个独立维度**。选小 base 时两个都要验证——bert-base-chinese 量化友好但太弱(只记忆),DeBERTa-v3 够强但量化崩,chinese-roberta-wwm-ext / distilbert 两者兼得。别只看体积或只看某个指标就定 base。 +> +> **经验 18**:**探针要用真实前后文,别用孤立合成行**。英文模型对真实「Chapter 1 - The Great Hall」判 0.999,但对我合成的裸「CHAPTER XII」(假的 prev/next/pos)判 0.001——差点误判成 int8 坏了。格式特征依赖真实上下文,合成输入的特征分布不匹配训练,会给出误导性的低分。判断模型好坏用**真实数据分布**的样本。 +> +> **经验 19**:**弱 base 的失败方式是「记忆而非泛化」**。bert-base-chinese 只认训练里高频的确切词(后记),学不会「第X章 + 短语」的结构泛化。识别这种失败:它对高频训练样本对、对同类新样本错——是能力上限,多训/调参救不回,得换更强的 base。 + --- ## 10. 里程碑数字(诚实版) @@ -310,6 +324,7 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 | **v3 浏览器实测(fp32,端到端)** | — | — | 结构化 0.992 / 金庸回目 0.914 / 正文 0.000,与 PyTorch 一致 | | **中文版 chinese-roberta-wwm-ext(int8 103MB)** | 0.81 | 0.85 | **int8 不崩**(第一章 0.92)、浏览器实测一致——按语言路线验证成立 | +| **英文版 distilbert-base-uncased(int8 67MB)** | 0.94 | 0.79 | int8 与 fp32 逐一相同(Chapter N-Title 0.999)、浏览器端到端 4 章全识别 | \* 独立测试的标签来自规则(仅标「第X章」类),模型额外找出的序言/楔子/语义标题被算作假阳性, 所以精度被低估,真实值更高。召回 0.988 是可信的关键信号——在训练与模型选择都零接触的书上 diff --git a/docs/chapter-model-deployment.md b/docs/chapter-model-deployment.md index ea1a2ba..0e214b1 100644 --- a/docs/chapter-model-deployment.md +++ b/docs/chapter-model-deployment.md @@ -89,6 +89,16 @@ mDeBERTa 的体积里近 2/3 是 25 万 token 的多语言 embedding。裁到实 > - 产物:`ml/train/out/model_zh`、`ml/export/out/zh/model_quantized.onnx`、部署于 `public/models/chapter-title-zh/`。 > - **经验**:「量化友好」和「够强」是两个维度——bert-base-chinese 占前者不占后者,DeBERTa-v3 反之,chinese-roberta-wwm-ext 两者兼得。选 base 要同时验证这两点。 +> **✅ 英文版跑通(2026-07-19)**:`distilbert-base-uncased`(6 层,更小)→ eval recall 0.94(英文标题规整)。 +> **int8 与 fp32 在真实 dev 数据上逐一相同**(Chapter N - Title 0.999),**67MB**。浏览器端到端:英文书自动 +> 检测 en → 加载 chapter-title-en(WebGPU)→ 4 章全识别 763ms。产物 `ml/train/out/model_en`、 +> `ml/export/out/en`、`public/models/chapter-title-en/`;已在 `lib/nlp/detectLanguage.ts` MODEL_BY_LANG 注册 en。 +> 注意:英文标题格式规整、规则覆盖本就好,英文模型边际价值小于中文(中文有金庸空格回目规则完全接不住)。 + +**前端接入(已落地)**:`detectLanguage`(CJK/拉丁占比)自动选模型 → `detectChaptersWithModel` +(预过滤短+非句末标点行,模型标题作无编号家族 union 规则 → validate.ts 竞争过滤)→ 置信度门控 UI +(规则 low/none 才显「AI 增强」,懒加载模型 + 进度,结果缓存 source:'model')。见 [journey 9.9](./chapter-detection-journey.md)。 + **为什么这条路更好**——体积的病根有两个(词表大 + 骨干是 DeBERTa-v3 不好量化),按语言分 + 换骨干**一次解决两个**: | | 多语言 mDeBERTa-v3 | 中文版 bert-base-chinese | 中文版 MiniLM-L6 | From e244380814657a1fe2ee102f2da0fb6a9418ae5b Mon Sep 17 00:00:00 2001 From: chaxus Date: Sun, 19 Jul 2026 07:56:55 +0800 Subject: [PATCH 29/54] fix: correct spacing in chapter detection documentation and deployment plan --- docs/chapter-detection-journey.md | 24 ++++----- docs/chapter-detection-plan.md | 2 +- docs/chapter-model-deployment.md | 69 ++++++++++++++++++++++++ docs/model-runtime-and-formats.md | 90 +++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 13 deletions(-) create mode 100644 docs/model-runtime-and-formats.md diff --git a/docs/chapter-detection-journey.md b/docs/chapter-detection-journey.md index a12782e..395f82c 100644 --- a/docs/chapter-detection-journey.md +++ b/docs/chapter-detection-journey.md @@ -17,7 +17,7 @@ 理由有四条,当时都成立: -1. **业界惯例**:calibre 的 structure detection、开源阅读 Legado、各种小说站,处理这问题都是「规则 + 统计」,不是模型。章节标题的**表面模式极强**(第X章、Chapter N),正则一行就能判。 +1. **业界惯例**:calibre 的 structure detection、开源阅读 Legado、各种小说站,处理这问题都是「规则 + 统计」,不是模型。章节标题的**表面模式极强**(第 X 章、Chapter N),正则一行就能判。 2. **部署成本**:mDeBERTa-v3-base int8 后约 280MB。weread 是纯前端 PWA,没有后端。让用户为导入一本 txt 先下几百 MB 模型不现实。 3. **可调试性**:正则错了改一行就行,能精确定位;模型错了是个黑盒,没法「改一行」。 4. **训练数据死结**:要微调得有标注好章节边界的语料。现实做法是拿 epub(自带目录)转 txt 自动生成标签——**但能被这样自动标注的样本,恰恰都是规则本就能匹配的样本**。模型学到的是规则的软化版,泛化不到规则覆盖不了的怪格式,因为怪格式你没有标签。这是最本质的反对理由,我称之为「同义反复陷阱」。 @@ -29,7 +29,7 @@ ### 1.3 两个信息改变了结论 - **「PWA 离线能接受体积」**:用户指出这是离线阅读器,模型下一次永久缓存,280MB 可接受。部署成本这条被消解了一半。 -- **「多语言呢?支持更多语言不是更好」**:这是**真正扭转判断的点**。规则库的多语言维护成本是**线性**的——中文「第X章」、英文 Chapter、法语 Chapitre、德语 Kapitel、日语「第X話」、俄语 Глава……每种语言都要人工攒模式库,长尾语言没人帮你踩坑。而多语言模型学到的「标题性」特征是**跨语言共享**的,还能靠零样本迁移覆盖没有训练数据的语言。280MB 全量词表换 ~100 种语言的入场券,对一个多语言阅读器是划算的买卖。 +- **「多语言呢?支持更多语言不是更好」**:这是**真正扭转判断的点**。规则库的多语言维护成本是**线性**的——中文「第 X 章」、英文 Chapter、法语 Chapitre、德语 Kapitel、日语「第 X 話」、俄语 Глава……每种语言都要人工攒模式库,长尾语言没人帮你踩坑。而多语言模型学到的「标题性」特征是**跨语言共享**的,还能靠零样本迁移覆盖没有训练数据的语言。280MB 全量词表换 ~100 种语言的入场券,对一个多语言阅读器是划算的买卖。 **于是结论定型**:值得上模型,但**架构上模型只替换候选生成层,不替换整条流水线**(这个判断从头到尾没变,也被后来的实践反复证明是对的,见第 4、7 节)。 @@ -43,7 +43,7 @@ `lib/chapter/` 落地了三层,这是无论上不上模型都要写的: -1. **候选生成** `patterns.ts` + `candidates.ts`:多语言模式库(第X章 / Chapter N / 一、/ 1. / 罗马数字 / 序章后记 / 【】),逐行匹配,行长过滤(≤50 字)。关键防误报:编号词后必须接分隔符或行尾,否则「他翻到第三章」这种正文短句会被误判。 +1. **候选生成** `patterns.ts` + `candidates.ts`:多语言模式库(第 X 章 / Chapter N / 一、/ 1. / 罗马数字 / 序章后记 / 【】),逐行匹配,行长过滤(≤50 字)。关键防误报:编号词后必须接分隔符或行尾,否则「他翻到第三章」这种正文短句会被误判。 2. **全局验证** `validate.ts`: - 家族竞争打分(同一本书里 cn-chapter、num-enum 等模式家族抢主导权,按数量 × 编号连贯度 × 家族精度权重); - 最长递增子序列剔除离群(正文里偶然出现的「第五章」引用不构成序列,被踢掉); @@ -71,10 +71,10 @@ **然后我尝试补正则,实测了一次改动的代价**: -- 修好 28 本、**碰坏 13 本**(本来好好的《陆小凤传奇全集》被挤成 0 章)、**23 本误报爆炸**(「世界营销绝招800例」被切成 522 章)。 +- 修好 28 本、**碰坏 13 本**(本来好好的《陆小凤传奇全集》被挤成 0 章)、**23 本误报爆炸**(「世界营销绝招 800 例」被切成 522 章)。 - 更狠的是:连我以为「结构性正确、精度安全」的多卷本修复,重跑后 high 仍从 147 掉到 130——因为「允许编号回落重启」等于放宽了序列校验,把更多噪声当成合法序列。 -> **经验 3(最重要)**:纯正则识别自由格式文本会**打地鼠**——每放宽一条规则接住新格式,就在别处放进一批假阳性。这是**方法本身的上限**,不是努力能绕过的。而且「看起来有原则」的改动也逃不过精度-召回的跷跷板。判断一个方案会不会打地鼠,唯一可靠的办法是拿真实语料量化 delta(修好几本 / 碰坏几本 / 爆炸几本),而不是看单个 case 是否修好。 +> **经验 3(最重要)**:纯正则识别自由格式文本会**打地鼠**——每放宽一条规则接住新格式,就在别处放进一批假阳性。这是**方法本身的上限**,不是努力能绕过的。而且「看起来有原则」的改动也逃不过精度 - 召回的跷跷板。判断一个方案会不会打地鼠,唯一可靠的办法是拿真实语料量化 delta(修好几本 / 碰坏几本 / 爆炸几本),而不是看单个 case 是否修好。 --- @@ -197,7 +197,7 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 | 累到无力抵抗 | 0.001 | 0.002 | 裸口语短语——**固有极限** | | 意志力的本能 | 0.001 | 0.024 | 同上 | -- **锚点文学回目拿回来了**(0.001 → 0.945),且探针测的是**去掉「一 」前缀的纯短语**,模型仍判对——说明它没靠数字锚点作弊,真学会了「这类文学短语是标题」。这是模型相对规则的**独有价值**(空格分隔的金庸/古龙回目)。 +- **锚点文学回目拿回来了**(0.001 → 0.945),且探针测的是**去掉「一」前缀的纯短语**,模型仍判对——说明它没靠数字锚点作弊,真学会了「这类文学短语是标题」。这是模型相对规则的**独有价值**(空格分隔的金庸/古龙回目)。 - **裸口语短语仍难**:原书里它是居中大字标题,靠视觉排版;拍平成一行后无锚点、风格又和普通口语句无异,模型(和人一样)区分不出。有趣的不对称:青衫磊落险峰行是古典对仗腔(可学),累到无力抵抗是大白话(学不了)。 > **经验 13**:**聚合指标会掩盖子类失败**。0.90 的召回若被结构化正样本主导,就看不出它对旗舰子类(文学短语)全军覆没。接入前一定要按**用例子类**手工抽查,而不是只看一个总召回。 @@ -302,13 +302,13 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 - **中文版**:base 踩了一步——`bert-base-chinese` **太弱**(eval recall 0.43,连「第一章 风雪夜」都判 0.02,只认高频词「后记」——弱 base 只记忆不泛化);换 `chinese-roberta-wwm-ext`(12 层,训练充分)→ recall 0.81、结构化标题 0.95。**int8 不崩**(第一章 fp32 0.948→int8 0.921,对照 DeBERTa-v3 int8 0.01 取反)。**103MB**。 - **英文版**:`distilbert-base-uncased`(6 层,更小)→ eval recall 0.94(英文标题规整)。int8 与 fp32 在真实 dev 数据上**逐一相同**(Chapter N - Title 0.999)。**67MB**。 -- **前端接入**:`detectLanguage`(CJK/拉丁占比)自动选模型;`detectChaptersWithModel` 把模型标题作为无编号家族 union 规则候选、交 `validate.ts` 结构层竞争过滤(结构化书规则胜出、语义书模型胜出);**预过滤「短+非句末标点行」把耗时 33s→1.8s**。置信度门控 UI:规则 low/none 才显「AI 增强」按钮,点击懒加载模型、增强、缓存(source:'model'),重开用缓存。**实测**:金庸空格回目书规则给空、模型增强产出 4 回目。 +- **前端接入**:`detectLanguage`(CJK/拉丁占比)自动选模型;`detectChaptersWithModel` 把模型标题作为无编号家族 union 规则候选、交 `validate.ts` 结构层竞争过滤(结构化书规则胜出、语义书模型胜出);**预过滤「短 + 非句末标点行」把耗时 33s→1.8s**。置信度门控 UI:规则 low/none 才显「AI 增强」按钮,点击懒加载模型、增强、缓存(source:'model'),重开用缓存。**实测**:金庸空格回目书规则给空、模型增强产出 4 回目。 > **经验 17**:**「量化友好」和「够强」是两个独立维度**。选小 base 时两个都要验证——bert-base-chinese 量化友好但太弱(只记忆),DeBERTa-v3 够强但量化崩,chinese-roberta-wwm-ext / distilbert 两者兼得。别只看体积或只看某个指标就定 base。 > > **经验 18**:**探针要用真实前后文,别用孤立合成行**。英文模型对真实「Chapter 1 - The Great Hall」判 0.999,但对我合成的裸「CHAPTER XII」(假的 prev/next/pos)判 0.001——差点误判成 int8 坏了。格式特征依赖真实上下文,合成输入的特征分布不匹配训练,会给出误导性的低分。判断模型好坏用**真实数据分布**的样本。 > -> **经验 19**:**弱 base 的失败方式是「记忆而非泛化」**。bert-base-chinese 只认训练里高频的确切词(后记),学不会「第X章 + 短语」的结构泛化。识别这种失败:它对高频训练样本对、对同类新样本错——是能力上限,多训/调参救不回,得换更强的 base。 +> **经验 19**:**弱 base 的失败方式是「记忆而非泛化」**。bert-base-chinese 只认训练里高频的确切词(后记),学不会「第 X 章 + 短语」的结构泛化。识别这种失败:它对高频训练样本对、对同类新样本错——是能力上限,多训/调参救不回,得换更强的 base。 --- @@ -318,7 +318,7 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 | ---------------------------------------------- | --------- | ------------------- | --------------------------------------------- | | 纯规则(273 txt 语料) | — | high 54% / none 35% | 打地鼠,撑不到 95% | | 模型 v1(纯文本,完整验证集) | 0.44 | 0.45 | 调阈值召回顶 0.6 | -| 模型 v2(+格式特征+多语言,完整验证集) | **0.90** | 0.24 | 高召回,但文学标题全挂(7.5 节) | +| 模型 v2(+格式特征 + 多语言,完整验证集) | **0.90** | 0.24 | 高召回,但文学标题全挂(7.5 节) | | 独立测试集(40 本训练零接触中文书) | **0.988** | 0.21\* | 泛化真值,排除过拟合 | | **模型 v3(+武侠回目,英文降量,完整验证集)** | **0.879** | **0.339** | **金庸回目 0.001→0.945,精度/f1 全面优于 v2** | @@ -326,7 +326,7 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 | **中文版 chinese-roberta-wwm-ext(int8 103MB)** | 0.81 | 0.85 | **int8 不崩**(第一章 0.92)、浏览器实测一致——按语言路线验证成立 | | **英文版 distilbert-base-uncased(int8 67MB)** | 0.94 | 0.79 | int8 与 fp32 逐一相同(Chapter N-Title 0.999)、浏览器端到端 4 章全识别 | -\* 独立测试的标签来自规则(仅标「第X章」类),模型额外找出的序言/楔子/语义标题被算作假阳性, +\* 独立测试的标签来自规则(仅标「第 X 章」类),模型额外找出的序言/楔子/语义标题被算作假阳性, 所以精度被低估,真实值更高。召回 0.988 是可信的关键信号——在训练与模型选择都零接触的书上 近满分,直接排除「0.90 是模型选择乐观」的可能。注意两套考卷难度不同:验证集含难的纯语义标题 (召回 0.90),独立测试是结构化中文章节(召回 0.988),不能直接比高低,但都证明泛化成立。 @@ -334,7 +334,7 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 - 英文覆盖:从「完全识别不了」→「CHAPTER N 类基本识别」(英文 txt 弱标注补充)。 - v3 数据规模:epub 真值 7983 正 + 武侠回目 438 正 + 英文 907 正 = 9328 正样本。英文从 v2 的 4209 砍到 907 是关键——避免结构化正样本淹没文学短语信号(见 7.5 节)。 -- **能力边界(诚实记录)**:结构化标题(第X章/CHAPTER N)与**锚点文学回目**(金庸/古龙的「一 青衫磊落险峰行」) +- **能力边界(诚实记录)**:结构化标题(第 X 章/CHAPTER N)与**锚点文学回目**(金庸/古龙的「一 青衫磊落险峰行」) 都能识别;**裸口语短语标题**(「累到无力抵抗」,无任何锚点)是拍平文本的固有极限,模型做不到, 交给目录手动编辑 + 用户修正回流。 @@ -349,7 +349,7 @@ epub 的目录是出版商/制作者手工确定的真实章节结构,和「 **选定方向(2026-07-18):按语言训小模型 + 换标准注意力骨干**(见 [部署文档 2.3](./chapter-model-deployment.md)): -- **中文版先做**:base `bert-base-chinese`(词表 2.1万、标准注意力 int8 友好),数据用中文 epub 7983 +- **中文版先做**:base `bert-base-chinese`(词表 2.1 万、标准注意力 int8 友好),数据用中文 epub 7983 - 武侠 438。**成败判据:int8 后金庸回目仍判对**(验证「标准注意力 int8 不崩」)。目标 ~50-100MB。 - **英文版**:MiniLM / distilbert,英文 txt 弱标注数据。 - **其他语言按需补**;多语言 mDeBERTa v3 保留作兜底(桌面 fp32)。 diff --git a/docs/chapter-detection-plan.md b/docs/chapter-detection-plan.md index 32390a1..0019a09 100644 --- a/docs/chapter-detection-plan.md +++ b/docs/chapter-detection-plan.md @@ -94,7 +94,7 @@ P4 的目录编辑 UI 顺延到模型就位后(用户修正即增量标注) - `data/build_dataset.py`:epub → 行级标签 JSONL(prev/text/next/label)。**本机已跑通**: 84/85 epub 解析成功,产出 23.6 万行、7983 标题正样本、正负比 1:29。标签是语义标题 - (「累到无力抵抗」「第1节 批《苦恋》」),正是规则接不住的那类 + (「累到无力抵抗」「第 1 节 批《苦恋》」),正是规则接不住的那类 - `train/train.py`:mDeBERTa-v3-base 逐行分类微调,按书划分 train/eval 防泄漏(需 GPU) - `export/export_onnx.py`:ONNX 导出 + int8 量化(需 optimum) - `eval/evalRules.ts`:规则层语料评估器(对照基线,high=147) diff --git a/docs/chapter-model-deployment.md b/docs/chapter-model-deployment.md index 0e214b1..66d6692 100644 --- a/docs/chapter-model-deployment.md +++ b/docs/chapter-model-deployment.md @@ -196,3 +196,72 @@ mDeBERTa 的体积里近 2/3 是 25 万 token 的多语言 embedding。裁到实 - q4 相对 int8 的精度损失。 - iOS 真机内存峰值与 OPFS 配额上限。 - 触发率:上线第 0 层后,实际有多少书落到 low/none、多少用户点了「AI 增强」——决定后续投入。 + +--- + +## 九、Cloudflare 部署可行性(2026-07-19 评估) + +**结论:可行,但必须把「代码」与「模型」拆成两条线部署。**直接把 `dist/`(含 1GB 模型)整个推 Pages 不可行。 + +### 9.1 app 本体 → Cloudflare Pages(原生兼容) + +- 构建产物是**纯静态 SSG**:`bin/build.sh` 跑 SSR bundle → `bin/build-ssg.js` 预渲染每条路由为静态 HTML → **删除 `dist/server`、`dist/client`**,`dist/` 只剩静态文件。无运行时 Node 服务器(DB / 推理全在浏览器 Worker)。→ Pages 纯静态托管即可,比现在的 GitHub Pages 更快。 +- **需改 base path**:全站硬编码 `/weread` 子路径(`vite.config.ts` `base:'/weread'`、`views/client.tsx`、`app.tsx` 的 `manifest-url`、`router` base)。CF Pages 部署在根域名要改成 `/`;保留子路径则要配 Pages 路由规则,改 base 更干净。 + +### 9.2 模型 → Cloudflare R2(Pages 装不下) + +- **Pages 有 25 MiB / 单文件硬上限**。三个 onnx 全部超限:mdeberta fp32 **1.0GB**、zh int8 **99MB**、en int8 **64MB**。且 `.gitignore` 已排除 `public/models/`,git 构建根本拿不到。 +- **R2 对象存储**:无单文件限制、S3 兼容、**出网流量免费**(正适合大模型下载)。建公开 bucket / 绑自定义域,`workers/nlpWorker.ts` 的 `env.localModelPath` 或远程 host 指向 R2 URL。模型走独立发布管线,与代码解耦(顺带解决「模型不进 git」)。 +- **配套**:R2 配 CORS 允许 app 域名跨域拉 onnx;模型文件名带版本 + `Cache-Control: immutable`(配合已有 Cache API / OPFS 缓存,见第四节)。 +- **顺手删 1.0GB 的 mdeberta 兜底**:int8 崩、只能 fp32、几乎不用,放 R2 用户也不会下 1GB。R2 上只留 zh(99MB) / en(64MB)。 + +--- + +## 十、模型压缩:哪些有效、哪些是误区 + +先纠一个常见误区(也是本轮提问的出发点): + +> **「把模型构建成 wasm 再 gzip」是一次范畴错误。** +> 模型是**权重(数据)**,WASM 是**运行时(代码)**。onnxruntime-web 的 `.wasm` 是*执行*模型的引擎(几 MB,那块该 gzip/brotli),模型本身不会因为「编译成 wasm」变小——权重就是权重,换个容器不改变字节量。 + +真正能动模型体积的杠杆,按「收益 / 工作量」排序: + +### 10.1 传输层压缩(gzip / brotli)—— 就是问题里「再 gzip」那步 + +- **有效但边际有限**。模型已是 **int8 量化**,量化权重接近高熵,gzip/brotli 通常只压 **~10-20%**(fp32 略好些但权重仍高熵)。 +- **brotli > gzip**,R2 可预压出 `.br` 并配 `Content-Encoding` 由浏览器透明解压。 +- **注意**:压的是*传输字节*,浏览器 / ORT 解压后**内存占用不变**(内存峰值仍是原始大小,见第五节 iOS 顾虑)。 +- 定位:**零成本叠加项**,能省点下载时间,但不是决定性杠杆。实测值应验证(int8 权重压缩率因分布而异)。 + +### 10.2 量化深度:int8 → int4(收益最大的下一步) + +- 现状 int8 已是 fp32 的 4×(zh 1.1GB→103MB)。**int4 / 4-bit 权重量化**(ORT 的 `MatMulNBits`、AWQ / GPTQ 系)可再约减半:zh ~50MB、en ~32MB。 +- **precision 风险**:DeBERTa-v3 连 int8 都崩(见 2.0),但本项目已换 **标准注意力骨干(roberta / distilbert),量化友好**——int4 有较大概率扛得住,**必须实测验证**(判据同 2.3:金庸回目 / 第一章仍判对)。 +- 定位:**中等工作量、收益最大**,是压缩方向的主攻点。 + +### 10.3 词表 / embedding 裁剪(CJK 收益小、英文尚可) + +- BERT/RoBERTa 的 embedding 表占参数不小(chinese-roberta ~21k 词表 × 768 ≈ 16M 参数)。裁到实际用到的 token 可省一块。 +- **但中文需广字符覆盖,裁剪空间有限**;英文 distilbert(30k 词表)相对可裁。收益中等,且要重导。 + +### 10.4 换更小 / 更蒸馏的骨干(最大降幅,最高成本) + +- distilbert 已是 6 层蒸馏。可再往 MiniLM-L6 / TinyBERT / 4 层走,能再降一个档,但要**重训**(工作量最大,且要重新验证能力边界)。 + +### 10.5 其它容器 / 格式(不改字节量,别指望减体积) + +- ONNX `.ort` 优化格式:加载更快,**体积基本不变**。 +- ONNX external data(图 / 权重分离):是「先加载图、权重后到」的渐进式加载基础(见 3.3),**不减总字节**。 + +### 压缩落地顺序建议 + +1. **零成本先叠**:R2 上 brotli 传输压缩(~10-20%)+ 删 1GB mdeberta。 +2. **主攻 int4**:验证 roberta/distilbert int4 精度,过关则 zh/en 再减半(→ ~50MB / ~32MB,是最实在的一跳)。 +3. **英文顺带裁词表**;中文词表裁剪收益小,优先级低。 +4. **换更小骨干**:仅当 int4 后仍嫌大、且愿意重训时再上。 + +--- + +## 附:通用背景知识(已拆分) + +「模型在浏览器里怎么加载运行」与「模型文件格式概览(不止 ONNX)」是与本项目部署解耦的通用知识,已移到 [model-runtime-and-formats.md](./model-runtime-and-formats.md)。本文只保留本项目的部署工程决策。 diff --git a/docs/model-runtime-and-formats.md b/docs/model-runtime-and-formats.md new file mode 100644 index 0000000..3358c84 --- /dev/null +++ b/docs/model-runtime-and-formats.md @@ -0,0 +1,90 @@ +# 模型运行机制与文件格式(通用参考) + +> 与本项目具体部署解耦的通用知识:**模型在浏览器里到底怎么被加载运行**、**模型文件有哪些格式、各自区别、怎么选**。 +> 本项目的具体落地(懒加载 / 减体积 / 缓存 / Cloudflare / 压缩方案)见 [chapter-model-deployment.md](./chapter-model-deployment.md)。 +> 模型的由来与效果见 [chapter-detection-journey.md](./chapter-detection-journey.md)。 + +--- + +## 一、模型在浏览器里到底怎么加载和运行 + +一句话:**模型是服务器上的一堆静态文件,被 JS 用 `fetch` 下载、缓存,再交给 WASM/WebGPU 引擎逐行算概率。「模型的字节」和「跑模型的代码」是两件事。** + +### 1.1 模型 = 一个文件目录(不进 JS bundle) + +``` +public/models/chapter-title-zh/ +├── config.json # 模型结构 + id2label(0=not_title 1=title) +├── tokenizer.json # 分词器:文字 → 数字 id +├── vocab.txt # 词表 +└── onnx/model_quantized.onnx # 99MB:权重(模型的「大脑」) +``` + +JS 代码里没有这些字节。运行时靠 HTTP 下载它们,和下载一张图片同理。**这就是「构建成 wasm 不减体积」的根因**:99MB 是 `.onnx` 权重文件本身,换什么代码去读它都不变。 + +### 1.2 三层调用栈 + +``` +页面(主线程) + │ postMessage + ▼ +workers/nlpWorker.ts(Web Worker,后台线程,不卡 UI) + │ 调用 + ▼ +@huggingface/transformers(transformers.js,npm 库) + │ 底层调 + ▼ +onnxruntime-web ←── 这才是真正的 WASM:执行模型的「引擎」(几 MB 代码) +``` + +**关键区分**:最底层的 `onnxruntime-web` 确实是 WASM,但它是*执行引擎(代码)*,不是模型*权重(数据)*。要 gzip/brotli 的是这块引擎(几 MB),跟 99MB 的模型是分开的两个东西。引擎优先用 **WebGPU**(显卡加速),失败退回 **WASM**(纯 CPU)。 + +### 1.3 一次完整流程(本项目「AI 增强」为例) + +1. **选模型** `lib/nlp/detectLanguage.ts`:数前 2 万字 CJK/拉丁占比 → `chapter-title-zh` 或 `-en`。 +2. **加载** `store/chapters.ts` → `classifier.load({ modelId, dtype:'q8', onProgress })` → worker 里 `AutoTokenizer.from_pretrained` + `AutoModelForSequenceClassification.from_pretrained` 用 fetch 下载。`dtype:'q8'` 决定去拿 `onnx/model_quantized.onnx`(int8 版)。`env.useBrowserCache=true` → 第二次秒开、离线可用。 +3. **逐行判断** `lib/chapter/modelDetect.ts`:全书切行 → **预过滤**(够短 + 不以句末标点结尾,把 33s 压到 1.8s)→ 每候选行拼 `[特征][SEP]上一行[SEP]本行[SEP]下一行` → `tokenizer(lines)` 文字转 id → `model(inputs)` 出 logits(这步跑 WASM/WebGPU)→ `softmax` 转 0~1 概率。 +4. **收敛** 概率 ≥ 阈值 (0.5) 的行 → 模型家族候选 → union 规则候选 → `validate.ts` 结构层过滤 → 缓存 `source:'model'` 进 IndexedDB,重开走缓存不再跑模型。 + +**减体积只能改权重文件本身**(量化 int8→int4 / 词表裁剪),不是换代码容器——因为字节在 `.onnx` 里。 + +--- + +## 二、模型文件格式概览(不止 ONNX) + +先建立一个分类维度:**只存权重** vs **权重 + 计算图**。 + +- **只存权重**(safetensors、.pt):一堆数字,本身不知道怎么算,必须配套模型代码(Python/transformers)才能跑。用于训练与分享。 +- **权重 + 计算图**(ONNX、GGUF、TFLite…):自带「怎么算」的描述,自包含、可直接部署推理。**浏览器/边缘部署要的是这一类。** + +### 2.1 主流格式一览 + +| 格式 | 生态 | 含计算图 | 典型用途 | 浏览器可跑 | +|---|---|---|---|---| +| **safetensors** | Hugging Face | ❌ 仅权重 | 训练/分享权重,取代不安全的 pickle `.pt` | ❌(需模型代码) | +| `.pt`/`.pth` | PyTorch | 部分 | 训练 checkpoint(pickle,能执行任意代码,有安全风险) | ❌ | +| **ONNX** `.onnx` | 跨框架标准 | ✅ | 跨平台/边缘/**浏览器**推理,量化友好 | ✅ onnxruntime-web | +| `.ort` | ONNX Runtime | ✅ | ONNX 的移动端优化二进制(加载更快,体积基本不变) | ✅ | +| **GGUF** | llama.cpp / Ollama | ✅ | **本地跑 LLM**(CPU/Metal/CUDA),激进量化 Q4_K_M 等 | 少数 wasm 移植,非主流 | +| **TFLite** `.tflite` | Google | ✅ | Android/移动端 | 有 TF.js,但另一套 | +| **CoreML** `.mlpackage` | Apple | ✅ | iOS/Mac 神经引擎 | ❌ | +| **TensorRT** `.engine` | NVIDIA | ✅ | 特定 N 卡上的极致性能(编译后不可移植) | ❌ | +| OpenVINO IR | Intel | ✅ | Intel 硬件 | ❌ | +| MLC/WebLLM 权重 | Apache TVM | ✅ | 浏览器里跑 LLM(编译 WebGPU shader + 自有权重格式) | ✅(专为此) | + +### 2.2「哪个最好」——没有通用最优,只有分场景最优 + +- **存/分享权重**(研究、HF Hub):**safetensors** 已胜出,取代 pickle。 +- **本地跑 LLM**(Ollama/llama.cpp/LM Studio):**GGUF** 事实标准。 +- **跨平台 / Web / 边缘部署通用模型**(非 LLM 或中小模型):**ONNX** 是最通用的开放标准。 +- **特定硬件极致性能**:厂商编译格式(N 卡 TensorRT、苹果 CoreML)。 + +### 2.3 本项目为什么是 ONNX(选型正确) + +浏览器 + 非 LLM 分类器 + 跨设备 + 需量化 → **ONNX 是目前唯一成熟解**: + +- safetensors 只有权重,浏览器里没有模型代码跑不起来; +- GGUF 面向 llama.cpp 本地 LLM,不是浏览器/分类模型的路子; +- CoreML/TensorRT/TFLite 都绑单一平台,违背「一份产物跑所有设备」。 + +ONNX 同时给了:一份产物跨端、onnxruntime-web 的 WASM/WebGPU 后端、以及成熟的量化工具链(fp32/fp16/int8/int4)。**注意量化精度(int8/int4)与文件格式是两个正交维度**——都在 ONNX 这个容器里选(压缩手段见 [chapter-model-deployment.md](./chapter-model-deployment.md) 第十节)。 From ef31138c4d3d0ee1c0be9f0b2db389222c2fb7e5 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sun, 19 Jul 2026 10:57:27 +0800 Subject: [PATCH 30/54] refactor: remove unused components and styles from BookCard, Catalogue, DetailMenu, DetailOperate, and Popover --- components/BookCard/index.scss | 18 ---- components/BookCard/index.tsx | 142 ----------------------------- components/Catalogue/index.tsx | 92 ------------------- components/DetailMenu/index.tsx | 139 ---------------------------- components/DetailOperate/index.tsx | 30 ------ components/Popover/index.tsx | 43 --------- 6 files changed, 464 deletions(-) delete mode 100644 components/BookCard/index.scss delete mode 100644 components/BookCard/index.tsx delete mode 100644 components/Catalogue/index.tsx delete mode 100644 components/DetailMenu/index.tsx delete mode 100644 components/DetailOperate/index.tsx delete mode 100644 components/Popover/index.tsx diff --git a/components/BookCard/index.scss b/components/BookCard/index.scss deleted file mode 100644 index b9def30..0000000 --- a/components/BookCard/index.scss +++ /dev/null @@ -1,18 +0,0 @@ -// @keyframes clip { -// from { -// clip-path: circle(0%); -// } -// to{ -// clip-path: circle(100%); -// } -// } - -// ::view-transition-old(book-info) { -// display: none; -// animation: none; -// animation-duration: 0.5s; -// } -// ::view-transition-new(book-info) { -// mix-blend-mode: normal; -// animation: clip 0.5s ease-in; -// } diff --git a/components/BookCard/index.tsx b/components/BookCard/index.tsx deleted file mode 100644 index cbddf2a..0000000 --- a/components/BookCard/index.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import { useEffect, useRef, useState } from 'react'; -import type { BookInfo } from '@/store/books'; -import { setCurrentBookDetail, setPageNum, setTextSyntaxTree } from '@/lib/subscribe'; -import { ROUTE_PATH } from '@/router'; -import './index.scss'; - -interface BookCardProps { - book: BookInfo; -} - -const useIsMobile = () => { - const [isMobile, setIsMobile] = useState(false); - - useEffect(() => { - const checkIsMobile = () => { - const isMobileDevice = window.matchMedia('(max-width: 768px)').matches; - setIsMobile(isMobileDevice); - }; - - checkIsMobile(); - window.addEventListener('resize', checkIsMobile); - return () => window.removeEventListener('resize', checkIsMobile); - }, []); - - return isMobile; -}; - -export const BookCard = ({ book }: BookCardProps): React.JSX.Element => { - const isMobile = useIsMobile(); - - return isMobile ? : ; -}; - -export const DesktopBookCard = ({ book }: BookCardProps): React.JSX.Element => { - const { id, image, title = '', author = '' } = book || {}; - const ref = useRef(null); - - const clear = () => { - setPageNum(0); - setCurrentBookDetail({}); - setTextSyntaxTree({ - sequences: [], - totalPage: 0, - pageText: [], - pageTitleId: [], - titleIdTitle: [], - titleIdPage: {}, - }); - }; - - const toDetail = () => { - clear(); - if (document.startViewTransition) { - ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); - document.startViewTransition(() => { - ref.current?.style.setProperty('view-transition-name', ''); - window.location.href = `${ROUTE_PATH.BOOK_DETAIL}?id=${id}`; - }); - } else { - window.location.href = `${ROUTE_PATH.BOOK_DETAIL}?id=${id}`; - } - }; - - useEffect(() => { - ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); - }, []); - - return ( - -
{image && {title}}
-
-
{title}
-
{author}
-
-
- ); -}; - -export const MobileBookCard = ({ book }: BookCardProps): React.JSX.Element => { - const { id, title = '', author = '' } = book || {}; - const ref = useRef(null); - - const clear = () => { - setPageNum(0); - setCurrentBookDetail({}); - setTextSyntaxTree({ - sequences: [], - totalPage: 0, - pageText: [], - pageTitleId: [], - titleIdTitle: [], - titleIdPage: {}, - }); - }; - - const toDetail = () => { - clear(); - if (document.startViewTransition) { - ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); - document.startViewTransition(() => { - ref.current?.style.setProperty('view-transition-name', ''); - window.location.href = `${ROUTE_PATH.BOOK_DETAIL}?id=${id}`; - }); - } else { - window.location.href = `${ROUTE_PATH.BOOK_DETAIL}?id=${id}`; - } - }; - - useEffect(() => { - ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); - }, []); - - return ( - - {/*
{image && {title}}
*/} -
-
- {title} -
-
- {author} -
-
-
- ); -}; diff --git a/components/Catalogue/index.tsx b/components/Catalogue/index.tsx deleted file mode 100644 index f181649..0000000 --- a/components/Catalogue/index.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import type { BookInfo } from '@/store/books'; -import type { TextSyntaxTree } from '@/lib/transformText'; -import { EVENT_NAME, getCurrentBookDetail, getTextSyntaxTree, setPageNum, syncHook } from '@/lib/subscribe'; -import { SORT_DIRECTION } from '@/lib/enums'; - -const SORT_ICON_STYLE = { - '--ran-icon-font-size': '20px', -}; - -const toPage = (e: Event) => { - const index = (e.target as HTMLElement)?.getAttribute('title') || ''; - if (index === undefined) return; - const textSyntaxTree: TextSyntaxTree = getTextSyntaxTree(); - const page = textSyntaxTree?.titleIdPage[index]; - if (page !== undefined) { - // Fallback for browsers that don't support View Transitions API - if (!document.startViewTransition) { - setPageNum(page); - return; - } - // With View Transition - document.startViewTransition(() => { - setPageNum(page); - }); - } - syncHook.call(EVENT_NAME.CLOSE_POPOVER); -}; - -export const Catalogue = (): React.JSX.Element => { - const sortRef = useRef(null); - const scrollRef = useRef(null); - const [sortDirection, setSortDirection] = useState(SORT_DIRECTION.DOWN); - const bookDetail: BookInfo = getCurrentBookDetail(); - const textSyntaxTree: TextSyntaxTree = getTextSyntaxTree(); - - const toSort = useCallback(() => { - setSortDirection(SORT_DIRECTION.UP); - if (sortDirection === SORT_DIRECTION.DOWN) { - const bottom = scrollRef.current?.scrollHeight; - scrollRef.current?.scrollTo({ top: bottom, behavior: 'smooth' }); - setSortDirection(SORT_DIRECTION.UP); - } - if (sortDirection === SORT_DIRECTION.UP) { - scrollRef.current?.scrollTo({ top: 0, behavior: 'smooth' }); - setSortDirection(SORT_DIRECTION.DOWN); - } - }, [sortDirection]); - - useEffect(() => { - scrollRef.current?.addEventListener('click', toPage); - sortRef.current?.addEventListener('click', toSort); - return () => { - scrollRef.current?.removeEventListener('click', toPage); - sortRef.current?.removeEventListener('click', toSort); - }; - }, [sortDirection]); - - return ( - <> -
- {bookDetail.image && } -
-
{bookDetail.title}
-
{bookDetail.author}
-
-
-
- -
-
- {textSyntaxTree?.titleIdTitle?.map((item: string, index: number) => { - return ( -
-
- {item} -
-
- ); - })} -
- - ); -}; diff --git a/components/DetailMenu/index.tsx b/components/DetailMenu/index.tsx deleted file mode 100644 index 3012b76..0000000 --- a/components/DetailMenu/index.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import { useEffect, useRef, useState } from 'react'; -import { debounce, getMatchingSentences } from 'ranuts/utils'; -import { trim } from '@/lib/transformText'; -import type { TextSyntaxTree } from '@/lib/transformText'; -import { Catalogue } from '@/components/Catalogue'; -import { getTextSyntaxTree, setPageNum } from '@/lib/subscribe'; -import { t } from '@/locales'; -const inputStyle = { - '--ran-input-border-radius': '2rem', - '--ran-input-content-border-radius': '2rem', - '--ran-input-content-padding': '10px', - '--ran-input-content-font-size': '14px', - '--ran-input-content-font-weight': '400', - '--ran-icon-font-size': '16px', - '--ran-icon-color': 'var(--icon-color-1)', - '--ran-icon-margin': '2px 0px 0px 12px', - '--ran-input-background-color': 'rgba(13,20,30,.04)', - '--ran-input-content-background-color': 'transparent', - '--ran-input-border': 'none', -}; - -interface SearchResult { - text: { pre: string; value: string; next: string; index: number }[]; - index: number; - title: string; -} - -const ICON_STYLE = { - '--ran-icon-font-size': '60px', -}; - -export const BookDetailMenu = (): React.JSX.Element => { - const searchRef = useRef(null); - const [showSearchResult, setShowSearchResult] = useState(false); - const [searchResult, setSearchResult] = useState([]); - const searchResultRef = useRef(null); - - const onSearch = debounce((e: Event) => { - const value = (e.target as HTMLInputElement)?.value || ''; - const searchValue = trim(value); - // 没有输入内容,则不进行搜索 - if (!searchValue) { - setShowSearchResult(false); - return; - } - // 展示搜索结果 - setShowSearchResult(true); - const textSyntaxTree: TextSyntaxTree = getTextSyntaxTree(); - const { pageText = [], pageTitleId, titleIdTitle } = textSyntaxTree || {}; - const pageSearchResult: SearchResult[] = []; - pageText.forEach((item, index) => { - if (item.text.includes(searchValue)) { - const text = getMatchingSentences(item.text, searchValue); - const textList = text.map((str: string) => { - const [pre, next] = str.split(searchValue); - return { pre, value: searchValue, next, index }; - }); - const title = titleIdTitle[pageTitleId[index]]; - const pageSearchResultItem = pageSearchResult.find((i) => i.title === titleIdTitle[pageTitleId[index]]); - if (pageSearchResultItem) { - pageSearchResultItem.text.push(...textList); - } else { - pageSearchResult.push({ text: textList, index, title }); - } - } - }); - setSearchResult(pageSearchResult); - }, 500); - - const onSearchResult = (e: Event) => { - const title = (e.target as HTMLElement)?.getAttribute('item-index'); - if (title === '') return; - setPageNum(Number(title)); - }; - - useEffect(() => { - searchRef.current?.addEventListener('change', onSearch); - return () => { - searchRef.current?.removeEventListener('change', onSearch); - }; - }, []); - - useEffect(() => { - searchResultRef.current?.addEventListener('click', onSearchResult); - return () => { - searchResultRef.current?.removeEventListener('click', onSearchResult); - }; - }, [searchResult]); - - return ( -
-
- -
- {!showSearchResult ? ( - - ) : ( -
- {searchResult.length > 0 ? ( - searchResult?.map((item) => { - const { text = [], index, title } = item; - return ( -
-
{title}
- {text.map((str, i) => { - const { pre, value, next } = str; - return ( -
- {pre} - {value} - {next} -
- ); - })} -
- ); - }) - ) : ( -
-
- -
{t('no_result')}
-
-
- )} -
- )} -
- ); -}; diff --git a/components/DetailOperate/index.tsx b/components/DetailOperate/index.tsx deleted file mode 100644 index 6d34153..0000000 --- a/components/DetailOperate/index.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Popover } from '@/components/Popover'; -import { BookDetailMenu } from '@/components/DetailMenu'; - -const MENU_ICON_STYLE = { - '--ran-icon-font-size': '24px', -}; - -export const BookDetailOperate = (): React.JSX.Element => { - return ( -
- }> -
- -
-
-
- ); -}; - -export const MobileBookDetailOperate = (): React.JSX.Element => { - return ( -
- }> -
- -
-
-
- ); -}; diff --git a/components/Popover/index.tsx b/components/Popover/index.tsx deleted file mode 100644 index 1daf9b0..0000000 --- a/components/Popover/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; -import { EVENT_NAME, syncHook } from '@/lib/subscribe'; -import 'ranui/popover'; - -export interface PopoverProps { - children: React.ReactNode; - overlay: React.ReactNode; - placement: 'top' | 'left' | 'right' | 'bottom'; - trigger: 'hover' | 'click'; - ref?: React.RefObject | null; -} - -export const Popover = ({ children, overlay, placement, trigger }: PopoverProps): React.JSX.Element => { - const [isClient, setIsClient] = useState(false); - const ref = useRef(null); - - const closePopover = useCallback(() => { - ref.current?.closePopover(); - }, []); - - useEffect(() => { - syncHook.tap(EVENT_NAME.CLOSE_POPOVER, closePopover); - setIsClient(true); - return () => { - syncHook.off(EVENT_NAME.CLOSE_POPOVER, closePopover); - }; - }, []); - - if (!isClient) { - return
; - } - - return ( -
- - {children} - -
{overlay}
-
-
-
- ); -}; From 326118e026a5cf4b5518dc8338a6ba156ab59cd6 Mon Sep 17 00:00:00 2001 From: chaxus Date: Sun, 19 Jul 2026 10:57:32 +0800 Subject: [PATCH 31/54] feat: Refactor UI layer to use ranui design system, replacing React and Tailwind - Implemented app structure with ranui builder and signal for reactive state management. - Created core components: BookCard, Catalogue, DetailMenu, DetailOperate, and Loading. - Established routing logic for MPA navigation with resolveRoute function. - Developed book detail and home page placeholders for future enhancements. - Integrated SSR capabilities with renderHTMLToString for pre-rendering. - Added utility styles for common classes to replace Tailwind utilities. - Registered built-in icons and initialized theme in client entry point. --- app.ts | 59 +++ app.tsx | 43 -- bin/build-ssg.js | 156 +++---- components/BookCard/index.ts | 67 +++ components/Catalogue/index.ts | 100 +++++ components/DetailMenu/index.ts | 132 ++++++ components/DetailOperate/index.ts | 29 ++ components/Loading/index.ts | 16 + components/Loading/index.tsx | 13 - components/Popover/index.ts | 40 ++ docs/ui-ranui-migration.md | 96 +++++ index.html | 4 +- index.tsx | 15 - lib/hooks.ts | 48 +-- lib/reactive.ts | 20 + package.json | 2 +- pages/book-detail/index.ts | 12 + pages/book-detail/index.tsx | 446 -------------------- pages/home/index.ts | 16 + pages/home/index.tsx | 662 ------------------------------ postcss.config.ts | 5 +- router/index.ts | 16 + router/index.tsx | 60 --- styles/base.css | 19 +- styles/theme.scss | 53 +-- styles/weread-components.css | 189 +++++++++ styles/weread-utilities.css | 29 ++ typings.d.ts | 15 +- variable/SERVICE_WORK_VERSION.ts | 2 +- views/client.ts | 10 + views/client.tsx | 12 - views/index.html | 4 +- views/server.ts | 34 ++ views/server.tsx | 15 - vite.config.ts | 24 +- 35 files changed, 986 insertions(+), 1477 deletions(-) create mode 100644 app.ts delete mode 100644 app.tsx create mode 100644 components/BookCard/index.ts create mode 100644 components/Catalogue/index.ts create mode 100644 components/DetailMenu/index.ts create mode 100644 components/DetailOperate/index.ts create mode 100644 components/Loading/index.ts delete mode 100644 components/Loading/index.tsx create mode 100644 components/Popover/index.ts create mode 100644 docs/ui-ranui-migration.md delete mode 100644 index.tsx create mode 100644 lib/reactive.ts create mode 100644 pages/book-detail/index.ts delete mode 100644 pages/book-detail/index.tsx create mode 100644 pages/home/index.ts delete mode 100644 pages/home/index.tsx create mode 100644 router/index.ts delete mode 100644 router/index.tsx create mode 100644 styles/weread-components.css create mode 100644 styles/weread-utilities.css create mode 100644 views/client.ts delete mode 100644 views/client.tsx create mode 100644 views/server.ts delete mode 100644 views/server.tsx diff --git a/app.ts b/app.ts new file mode 100644 index 0000000..b6acdd7 --- /dev/null +++ b/app.ts @@ -0,0 +1,59 @@ +import { createRoot } from 'ranui/builder'; +import { ROUTE_PATH, resolveRoute } from '@/router'; +import { closeDB, initDB, resumeDB } from '@/store'; +import { renderBookDetail } from '@/pages/book-detail'; +import { renderHome } from '@/pages/home'; +import { renderLoading } from '@/components/Loading'; +import '@khmyznikov/pwa-install'; +import '@/styles/view-transition.scss'; + +/** 命令式创建 pwa-install(原 React useEffect 里的逻辑,`/weread/` 字面量保持不变)。 */ +const createPwaInstall = (): (() => void) => { + const pwaInstall = document.createElement('pwa-install'); + pwaInstall.setAttribute('manifest-url', '/weread/manifest.json'); + pwaInstall.setAttribute('name', 'weread'); + pwaInstall.setAttribute('description', 'Progressive web application'); + pwaInstall.setAttribute('icon', '/weread/read.svg'); + document.body.appendChild(pwaInstall); + return () => document.body.removeChild(pwaInstall); +}; + +/** + * 客户端挂载:按 pathname 选页,在 `createRoot` 里构建并替换 #app 的 light DOM + * (自定义元素 upgrade 时复用 server 侧 shadow root)。含 DB / PWA / 可见性生命周期。 + */ +export const mountApp = (): void => { + initDB(); + const removePwa = createPwaInstall(); + const onVis = (): void => { + if (document.visibilityState === 'visible') resumeDB(); + }; + document.addEventListener('visibilitychange', onVis, false); + + const container = document.getElementById('app'); + if (!container) return; + const route = resolveRoute(location.pathname); + + const dispose = createRoot((d) => { + // 页面工厂必须在 createRoot 内调用,signal 绑定 / onCleanup 才有 owner + const node = + route === ROUTE_PATH.BOOK_DETAIL + ? renderBookDetail() + : route === ROUTE_PATH.LOADING + ? renderLoading() + : renderHome(); + container.replaceChildren(node.build()); + return d; + }); + + window.addEventListener( + 'pagehide', + () => { + dispose?.(); + closeDB(); + removePwa(); + document.removeEventListener('visibilitychange', onVis); + }, + { once: true }, + ); +}; diff --git a/app.tsx b/app.tsx deleted file mode 100644 index 0c81320..0000000 --- a/app.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { useCallback, useEffect } from 'react'; -import { Routes } from './router/index'; -import { closeDB, initDB, resumeDB } from './store'; -import 'ranui/button'; -import './styles/view-transition.scss'; -import '@khmyznikov/pwa-install'; - -export const App = (): React.JSX.Element => { - const onVisibilityChange = useCallback(() => { - if (document.visibilityState === 'visible') { - console.log('Page is visible'); - resumeDB(); - } else { - console.log('Page is hidden'); - } - }, []); - const createPwaInstall = () => { - const pwaInstall = document.createElement('pwa-install'); - pwaInstall.setAttribute('manifest-url', '/weread/manifest.json'); - pwaInstall.setAttribute('name', 'weread'); - pwaInstall.setAttribute('description', 'Progressive web application'); - pwaInstall.setAttribute('icon', '/weread/read.svg'); - document.body.appendChild(pwaInstall); - return () => { - document.body.removeChild(pwaInstall); - }; - }; - useEffect(() => { - initDB(); - const removePwaInstall = createPwaInstall(); - document.addEventListener('visibilitychange', onVisibilityChange, false); - return () => { - closeDB(); - document.removeEventListener('visibilitychange', onVisibilityChange); - removePwaInstall(); - }; - }, []); - return ( -
- -
- ); -}; diff --git a/bin/build-ssg.js b/bin/build-ssg.js index fb32ddb..d327529 100644 --- a/bin/build-ssg.js +++ b/bin/build-ssg.js @@ -1,124 +1,64 @@ -// Pre-render the app into static HTML. -// run `npm run generate` and then `dist/static` can be served as a static site. - +// 预渲染为静态 HTML(SSG)。 +// 流程:build:server(已在 build.sh 跑)→ 本脚本 build:client 一次 → 拷贝产物 → +// 注入 SW 缓存清单 → 对每条路由 render(url) 注入 。 import fs from 'node:fs'; import path from 'node:path'; import url from 'node:url'; import childProcess from 'node:child_process'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); - const toAbsolute = (p) => path.resolve(__dirname, p); -// const template = fs.readFileSync(toAbsolute('../dist/client/index.html'), 'utf-8'); + const { render } = await import('../dist/server/server.js'); -// determine routes to pre-render from src/pages + +// 从 pages/ 目录推断待预渲染路由(home → 根,其余 → 同名子路径)。 const routesToPrerender = fs.readdirSync(toAbsolute('../pages')).map((file) => { - const name = file.replace(/\.tsx$/, '').toLowerCase(); + const name = file.replace(/\.tsx?$/, '').toLowerCase(); return { name: name === 'home' ? 'index' : name, url: name === 'home' ? '/weread/' : `/weread/${name}` }; }); -const createClientTemplate = (url) => `import { StaticRouter } from 'react-router-dom'; -import { hydrateRoot } from 'react-dom/client'; -import { App } from '../app'; +// 1) 客户端只构建一次(所有路由共享同一份客户端 bundle + 模板)。 +childProcess.execSync('npm run build:client', { stdio: 'inherit' }); -const container = document.getElementById('app')!; - -hydrateRoot( - container, - - - , -); -`; - -(async () => { - // pre-render each route... - for (const { name, url } of routesToPrerender) { - const clientEntry = createClientTemplate(url); - // write client entry to views/client.tsx - fs.writeFileSync(toAbsolute(`../views/client.tsx`), clientEntry); - // run vite build - childProcess.execSync(`npm run build:client`); - // create a directory - // const distPath = '../dist'; - // if (name !== 'home') { - // distPath = `../dist/${name}`; - // } - // fs.mkdirSync(toAbsolute(distPath), { recursive: true }); - // copy the dist/client/views directory to dist/${name} - if (name === 'index') { - fs.cpSync(toAbsolute('../dist/client/views/index.html'), toAbsolute(`../dist/${name}.html`), { recursive: true }); +// 2) 把 dist/client/assets/* 合并到共享的 dist/assets/。 +const distAssets = toAbsolute('../dist/assets'); +fs.mkdirSync(distAssets, { recursive: true }); +const clientAssets = toAbsolute('../dist/client/assets'); +if (fs.existsSync(clientAssets)) { + for (const file of fs.readdirSync(clientAssets)) { + const src = path.join(clientAssets, file); + const dst = path.join(distAssets, file); + if (fs.statSync(src).isDirectory()) { + fs.mkdirSync(dst, { recursive: true }); + for (const sub of fs.readdirSync(src)) fs.copyFileSync(path.join(src, sub), path.join(dst, sub)); } else { - fs.mkdirSync(toAbsolute(`../dist/${name}`), { recursive: true }); - fs.cpSync(toAbsolute('../dist/client/views/index.html'), toAbsolute(`../dist/${name}/index.html`), { - recursive: true, - }); - } - // copy the dist/client/assets directory to dist/${name}/assets - // 复制 assets 目录到 dist 目录下的 assets 目录下,如果 assets 目录不存在,则创建,如果 assets 目录下文件同名,则覆盖 - // fs.cpSync(toAbsolute('../dist/client/assets'), toAbsolute(`../dist/assets`), { recursive: true }); - if (!fs.existsSync(toAbsolute(`../dist/assets`))) { - fs.mkdirSync(toAbsolute(`../dist/assets`), { recursive: true }); - } - // 复制 assets 目录下的所有文件 - const assetsPath = toAbsolute('../dist/client/assets'); - const distAssetsPath = toAbsolute(`../dist/assets`); - if (fs.existsSync(assetsPath)) { - const files = fs.readdirSync(assetsPath); - files.forEach((file) => { - const sourcePath = path.join(assetsPath, file); - const targetPath = path.join(distAssetsPath, file); - if (fs.statSync(sourcePath).isDirectory()) { - // 如果是目录,递归复制 - if (!fs.existsSync(targetPath)) { - fs.mkdirSync(targetPath, { recursive: true }); - } - const subFiles = fs.readdirSync(sourcePath); - subFiles.forEach((subFile) => { - fs.copyFileSync(path.join(sourcePath, subFile), path.join(targetPath, subFile)); - }); - } else { - // 如果是文件,直接复制 - fs.copyFileSync(sourcePath, targetPath); - } - }); + fs.copyFileSync(src, dst); } - // copy the dist/client/public directory to dist/${name}/public - // 读取 client 下的所有文件,非目录 - const clientFiles = fs.readdirSync(toAbsolute('../dist/client')); - // 将所有文件复制到 dist/${name}/public - clientFiles.forEach((file) => { - fs.cpSync(toAbsolute(`../dist/client/${file}`), toAbsolute(`../dist/${file}`), { recursive: true }); - }); - // 读取 dist/${name}/assets 目录下的所有文件的名称 - const assets = fs.readdirSync(toAbsolute(`../dist/assets`)); - // 将所有名称拼接成一个数组字符串,输出 - const assetsString = assets.map((asset) => `"/weread/assets/${asset}"`).join(','); - // 写入到 sw.js 文件开头 - const swContent = fs.readFileSync(toAbsolute(`../dist/sw.js`), 'utf-8'); - const newSwContent = 'const SERVICE_WORK_CACHE_FILE_PATHS = [' + assetsString + '];' + swContent; - fs.writeFileSync(toAbsolute(`../dist/sw.js`), newSwContent); - // render the app - const appHtml = await render(url); - // read the template - let template = ''; - if (name === 'index') { - template = fs.readFileSync(toAbsolute(`../dist/${name}.html`), 'utf-8'); - } else { - template = fs.readFileSync(toAbsolute(`../dist/${name}/index.html`), 'utf-8'); - } - // replace the ssr-outlet with the app html - const html = template.replace(``, appHtml); - // write to dist/${name}/index.html - let filePath = ''; - if (name === 'index') { - filePath = `../dist/${name}.html`; - } else { - filePath = `../dist/${name}/index.html`; - } - // create the dist/${name} directory if it doesn't exist - // fs.mkdirSync(toAbsolute(path.dirname(filePath)), { recursive: true }); - // write the file - fs.writeFileSync(toAbsolute(filePath), html); } -})(); +} + +// 3) 把 dist/client/ 顶层其余文件(public 拷来的 sw.js/manifest/图标/models 等)上移到 dist/。 +for (const file of fs.readdirSync(toAbsolute('../dist/client'))) { + fs.cpSync(toAbsolute(`../dist/client/${file}`), toAbsolute(`../dist/${file}`), { recursive: true }); +} + +// 4) 把资源清单注入 sw.js 头部(precache 列表),只做一次。 +const swPath = toAbsolute('../dist/sw.js'); +if (fs.existsSync(swPath)) { + const assetsString = fs + .readdirSync(distAssets) + .map((asset) => `"/weread/assets/${asset}"`) + .join(','); + const swContent = fs.readFileSync(swPath, 'utf-8'); + fs.writeFileSync(swPath, `const SERVICE_WORK_CACHE_FILE_PATHS = [${assetsString}];` + swContent); +} + +// 5) 逐路由注入 SSR 外壳。共享模板来自 dist/client/views/index.html。 +const template = fs.readFileSync(toAbsolute('../dist/client/views/index.html'), 'utf-8'); +for (const { name, url: routeUrl } of routesToPrerender) { + const appHtml = await render(routeUrl); + const html = template.replace('', appHtml); + const filePath = name === 'index' ? toAbsolute('../dist/index.html') : toAbsolute(`../dist/${name}/index.html`); + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, html); +} diff --git a/components/BookCard/index.ts b/components/BookCard/index.ts new file mode 100644 index 0000000..ce57e5e --- /dev/null +++ b/components/BookCard/index.ts @@ -0,0 +1,67 @@ +import 'ranui/card'; +import { Div, View, batch, createRef } from 'ranui/builder'; +import { setCurrentBookDetail, setPageNum, setTextSyntaxTree } from '@/lib/subscribe'; +import { ROUTE_PATH } from '@/router'; +import type { ElementBuilder } from 'ranui/builder'; +import type { BookInfo } from '@/store/books'; + +/** 进入详情前清空阅读态三信号(页码 / 当前书 / 语法树),批处理一次刷新。 */ +const clear = (): void => { + batch(() => { + setPageNum(0); + setCurrentBookDetail({}); + setTextSyntaxTree({ + sequences: [], + totalPage: 0, + pageText: [], + pageTitleId: [], + titleIdTitle: [], + titleIdPage: {}, + }); + }); +}; + +/** + * 书架卡片:``(封面 + 标题 + 作者)。点击清空阅读态并整页跳转书详情, + * 支持时用 View Transition 做 `book-info-${id}` 共享元素 morph。响应式尺寸交由 CSS。 + */ +export const renderBookCard = (book: BookInfo): ElementBuilder => { + const { id, image, title = '', author = '' } = book || {}; + const ref = createRef(); + const href = `${ROUTE_PATH.BOOK_DETAIL}?id=${id}`; + + const toDetail = (e: Event): void => { + e.preventDefault(); // 由 startViewTransition 接管导航,morph 才生效 + clear(); + if (document.startViewTransition) { + ref.current?.style.setProperty('view-transition-name', `book-info-${id}`); + document.startViewTransition(() => { + ref.current?.style.setProperty('view-transition-name', ''); + window.location.href = href; + }); + } else { + window.location.href = href; + } + }; + + return View('a') + .ref(ref) + .class('wr-book-card') + .attr('href', href) + .style('view-transition-name', `book-info-${id}`) + .on('click', toDetail) + .children( + View('r-card') + .class('wr-book-card-inner') + .boolAttr('hoverable', true) + .children( + image ? View('img').class('wr-book-card-cover').attr('src', image).attr('alt', title) : null, + Div() + .class('wr-book-card-meta') + .children( + Div().class('wr-book-card-title truncate').attr('title', title).text(title), + Div().class('wr-book-card-author truncate').attr('title', author).text(author), + ), + ), + ); +}; diff --git a/components/Catalogue/index.ts b/components/Catalogue/index.ts new file mode 100644 index 0000000..4d42797 --- /dev/null +++ b/components/Catalogue/index.ts @@ -0,0 +1,100 @@ +import 'ranui/icon'; +import { Div, View, createEffect, createRef, signal } from 'ranui/builder'; +import { EVENT_NAME, getCurrentBookDetail, getTextSyntaxTree, setPageNum, syncHook } from '@/lib/subscribe'; +import { fromStore } from '@/lib/reactive'; +import { SORT_DIRECTION } from '@/lib/enums'; +import type { ElementBuilder } from 'ranui/builder'; +import type { TextSyntaxTree } from '@/lib/transformText'; + +const SORT_ICON_FONT_SIZE = '20px'; + +/** + * 目录项点击(委托):读 `title`(章节 index)→ titleIdPage 换算页码 → + * `setPageNum`(包 View Transition)→ 关闭浮层。契约同原实现。 + */ +const toPage = (e: Event): void => { + const index = (e.target as HTMLElement)?.getAttribute('title'); + if (!index) return; + const page = getTextSyntaxTree()?.titleIdPage[index]; + if (page !== undefined) { + if (!document.startViewTransition) { + setPageNum(page); + } else { + document.startViewTransition(() => setPageNum(page)); + } + } + syncHook.call(EVENT_NAME.CLOSE_POPOVER); +}; + +/** 由语法树构建目录条目列表(title 属性承载章节 index,供委托点击读取)。 */ +const buildItems = (tree: TextSyntaxTree): ElementBuilder[] => + (tree?.titleIdTitle ?? []).map((item, index) => + Div() + .class('wr-catalogue-item') + .attr('title', `${index}`) + .children(Div().class('wr-catalogue-item-inner').attr('title', `${index}`).text(item)), + ); + +/** + * 目录:书籍信息头 + 排序按钮 + 可滚动章节列表。 + * 列表随 `SET_TEXT_SYNTAX_TREE` 响应式重建(数据从 IndexedDB 异步加载后填充)。 + * 必须在 `createRoot` 作用域内调用。 + */ +export const renderCatalogue = (): ElementBuilder => { + const bookDetail = fromStore(getCurrentBookDetail, EVENT_NAME.SET_CURRENT_BOOK_DETAIL); + const tree = fromStore(getTextSyntaxTree, EVENT_NAME.SET_TEXT_SYNTAX_TREE); + + const scrollRef = createRef(); + const [sortDirection, setSortDirection] = signal(SORT_DIRECTION.DOWN); + + const toSort = (): void => { + const el = scrollRef.current; + if (!el) return; + if (sortDirection() === SORT_DIRECTION.DOWN) { + el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' }); + setSortDirection(SORT_DIRECTION.UP); + } else { + el.scrollTo({ top: 0, behavior: 'smooth' }); + setSortDirection(SORT_DIRECTION.DOWN); + } + }; + + // 语法树到位后重建目录条目(首帧 el 尚未 build,跳过;store 更新后填充)。 + createEffect(() => { + const items = buildItems(tree()); + const el = scrollRef.current; + if (!el) return; + el.replaceChildren(...items.map((b) => b.build())); + }); + + return Div() + .class('wr-catalogue') + .children( + Div() + .class('wr-catalogue-header') + .children( + View('img') + .class('wr-catalogue-cover') + .attr('src', () => bookDetail().image ?? '') + .style('display', () => (bookDetail().image ? '' : 'none')), + Div().children( + Div().class('wr-catalogue-title').text(() => bookDetail().title ?? ''), + Div().class('wr-catalogue-author').text(() => bookDetail().author ?? ''), + ), + ), + Div() + .class('wr-catalogue-sort') + .on('click', toSort) + .children( + View('r-icon') + .class(() => `hover-icon wr-catalogue-sort-icon ${sortDirection()}`) + .attr('name', 'sort') + .cssVar('--ran-icon-font-size', SORT_ICON_FONT_SIZE), + ), + Div() + .class('wr-catalogue-list') + .ref(scrollRef) + .on('click', toPage) + .children(...buildItems(tree())), + ); +}; diff --git a/components/DetailMenu/index.ts b/components/DetailMenu/index.ts new file mode 100644 index 0000000..9aa7815 --- /dev/null +++ b/components/DetailMenu/index.ts @@ -0,0 +1,132 @@ +import 'ranui/input'; +import 'ranui/icon'; +import { debounce, getMatchingSentences } from 'ranuts/utils'; +import { Div, Span, View, createEffect, createRef, signal } from 'ranui/builder'; +import { getTextSyntaxTree, setPageNum } from '@/lib/subscribe'; +import { trim } from '@/lib/transformText'; +import { renderCatalogue } from '@/components/Catalogue'; +import { t } from '@/locales'; +import type { ElementBuilder } from 'ranui/builder'; +import type { TextSyntaxTree } from '@/lib/transformText'; + +interface SearchResultItem { + text: { pre: string; value: string; next: string; index: number }[]; + index: number; + title: string; +} + +const INPUT_CSS_VARS: Record = { + '--ran-input-border-radius': '2rem', + '--ran-input-content-border-radius': '2rem', + '--ran-input-content-padding': '10px', + '--ran-input-content-font-size': '14px', + '--ran-input-content-font-weight': '400', + '--ran-icon-font-size': '16px', + '--ran-icon-color': 'var(--icon-color-1)', + '--ran-icon-margin': '2px 0px 0px 12px', + '--ran-input-background-color': 'rgba(13,20,30,.04)', + '--ran-input-content-background-color': 'transparent', + '--ran-input-border': 'none', +}; + +const EMPTY_ICON_FONT_SIZE = '60px'; + +/** 在语法树里按关键词逐页匹配,聚合成按章节分组的搜索结果。 */ +const searchTree = (tree: TextSyntaxTree, keyword: string): SearchResultItem[] => { + const { pageText = [], pageTitleId = [], titleIdTitle = [] } = tree || {}; + const result: SearchResultItem[] = []; + pageText.forEach((item, index) => { + if (!item.text.includes(keyword)) return; + const textList = getMatchingSentences(item.text, keyword).map((str: string) => { + const [pre, next] = str.split(keyword); + return { pre, value: keyword, next, index }; + }); + const title = titleIdTitle[pageTitleId[index]]; + const existing = result.find((i) => i.title === title); + if (existing) { + existing.text.push(...textList); + } else { + result.push({ text: textList, index, title }); + } + }); + return result; +}; + +/** 构建单条搜索结果分组(item-index 承载页码,供委托点击读取)。 */ +const buildResultGroup = (item: SearchResultItem): ElementBuilder => + Div() + .attr('item-index', `${item.index}`) + .children( + Div().class('wr-menu-result-title').text(item.title), + ...item.text.map(({ pre, value, next, index }) => + Div() + .class('wr-menu-result-line') + .attr('item-index', `${index}`) + .children(pre, Span().class('wr-menu-result-hit').text(value), next), + ), + ); + +const buildEmpty = (): ElementBuilder => + Div() + .class('wr-menu-empty') + .children( + View('r-icon').attr('name', 'without-content').cssVar('--ran-icon-font-size', EMPTY_ICON_FONT_SIZE), + Div().class('wr-menu-empty-text').text(t('no_result')), + ); + +/** + * 书内菜单:搜索框(原生 `change`,防抖 500ms)+ 目录 / 搜索结果切换。 + * 有输入时展示按章节分组的命中,`item-index` 委托点击跳页;无输入回落到目录。 + * 必须在 `createRoot` 作用域内调用。 + */ +export const renderBookDetailMenu = (): ElementBuilder => { + const [showSearchResult, setShowSearchResult] = signal(false); + const [searchResult, setSearchResult] = signal([]); + const resultRef = createRef(); + + const onSearch = debounce((e: Event): void => { + const searchValue = trim((e.target as HTMLInputElement)?.value || ''); + if (!searchValue) { + setShowSearchResult(false); + return; + } + setShowSearchResult(true); + setSearchResult(searchTree(getTextSyntaxTree(), searchValue)); + }, 500); + + const onSearchResult = (e: Event): void => { + const index = (e.target as HTMLElement)?.getAttribute('item-index'); + if (!index) return; + setPageNum(Number(index)); + }; + + // 搜索结果响应式重建(首帧 el 尚未 build,跳过;输入后填充)。 + createEffect(() => { + const result = searchResult(); + const el = resultRef.current; + if (!el) return; + const nodes = result.length > 0 ? result.map((item) => buildResultGroup(item).build()) : [buildEmpty().build()]; + el.replaceChildren(...nodes); + }); + + return Div() + .class('wr-menu') + .children( + Div() + .class('wr-menu-search') + .children( + View('r-input') + .attr('icon', 'search') + .attr('placeholder', t('search')) + .style(INPUT_CSS_VARS) + .on('change', onSearch), + ), + // 目录常驻构建(保留其响应式),随搜索态切换显隐。 + renderCatalogue().style('display', () => (showSearchResult() ? 'none' : 'flex')), + Div() + .class('wr-menu-result') + .ref(resultRef) + .on('click', onSearchResult) + .style('display', () => (showSearchResult() ? 'block' : 'none')), + ); +}; diff --git a/components/DetailOperate/index.ts b/components/DetailOperate/index.ts new file mode 100644 index 0000000..5d16868 --- /dev/null +++ b/components/DetailOperate/index.ts @@ -0,0 +1,29 @@ +import 'ranui/icon'; +import { Div, View } from 'ranui/builder'; +import { renderPopover } from '@/components/Popover'; +import { renderBookDetailMenu } from '@/components/DetailMenu'; +import type { ElementBuilder } from 'ranui/builder'; + +const MENU_ICON_FONT_SIZE = '24px'; + +/** 菜单触发器(圆形按钮 + menu 图标)。 */ +const menuTrigger = (): ElementBuilder => + Div() + .class('wr-operate-trigger') + .children(View('r-icon').class('hover-icon').attr('name', 'menu').cssVar('--ran-icon-font-size', MENU_ICON_FONT_SIZE)); + +/** 桌面端:右上角浮动菜单按钮,点击左向弹出书内菜单。 */ +export const renderBookDetailOperate = (): ElementBuilder => + Div() + .class('wr-operate') + .children( + renderPopover({ placement: 'left', trigger: 'click', overlay: renderBookDetailMenu(), children: menuTrigger() }), + ); + +/** 移动端:底部 chrome 栏内的菜单按钮,点击向上弹出书内菜单。 */ +export const renderMobileBookDetailOperate = (): ElementBuilder => + Div() + .class('wr-operate-mobile') + .children( + renderPopover({ placement: 'top', trigger: 'click', overlay: renderBookDetailMenu(), children: menuTrigger() }), + ); diff --git a/components/Loading/index.ts b/components/Loading/index.ts new file mode 100644 index 0000000..1667324 --- /dev/null +++ b/components/Loading/index.ts @@ -0,0 +1,16 @@ +import 'ranui/loading'; +import { Div, View } from 'ranui/builder'; +import type { ElementBuilder } from 'ranui/builder'; + +/** + * 加载态:ranui `r-loading`(Geist 观感),居中铺满。 + * 返回 ElementBuilder:server 端 `.serialize()`,client 端 `.build()`。 + */ +export const renderLoading = (): ElementBuilder => + Div() + .class('flex-center wr-loading') + .children( + View('r-loading') + .attr('name', 'circle-fold') + .cssVar('--loading-circle-fold-item-before-background', 'var(--ran-color-primary)'), + ); diff --git a/components/Loading/index.tsx b/components/Loading/index.tsx deleted file mode 100644 index 89b7021..0000000 --- a/components/Loading/index.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import 'ranui/loading'; - -export const Loading: React.FC = () => { - const styles = { - '--loading-cube-grid-item-background': 'var(--blue-1)', - }; - return ( -
- -
- ); -}; diff --git a/components/Popover/index.ts b/components/Popover/index.ts new file mode 100644 index 0000000..7005d07 --- /dev/null +++ b/components/Popover/index.ts @@ -0,0 +1,40 @@ +import 'ranui/popover'; // 同时注册 +import { Div, View, createRef, onCleanup } from 'ranui/builder'; +import { EVENT_NAME, syncHook } from '@/lib/subscribe'; +import type { ElementBuilder } from 'ranui/builder'; + +/** builder 可接受的子节点(触发器 / 浮层内容)。 */ +type Node = ElementBuilder | HTMLElement | string; + +export interface PopoverOptions { + placement: 'top' | 'left' | 'right' | 'bottom'; + trigger: 'hover' | 'click'; + /** 触发器(默认插槽内容)。 */ + children: Node; + /** 浮层内容,进 ``。 */ + overlay: Node; +} + +/** r-popover 元素上挂着的命令式关闭方法(组件实例只读属性)。 */ +type PopoverEl = HTMLElement & { closePopover?: () => void }; + +/** + * `` + `` 的 builder 薄封装。 + * 订阅 `CLOSE_POPOVER`(如目录/搜索结果点击后关闭浮层),`onCleanup` 里解绑; + * 命令式 `closePopover()` 通过 ref 调用组件实例方法。必须在 `createRoot` 作用域内调用。 + */ +export const renderPopover = ({ placement, trigger, children, overlay }: PopoverOptions): ElementBuilder => { + const ref = createRef(); + const closePopover = (): void => ref.current?.closePopover?.(); + + syncHook.tap(EVENT_NAME.CLOSE_POPOVER, closePopover); + onCleanup(() => syncHook.off(EVENT_NAME.CLOSE_POPOVER, closePopover)); + + return Div().children( + View('r-popover') + .ref(ref) + .attr('placement', placement) + .attr('trigger', trigger) + .children(children, View('r-content').children(Div().children(overlay))), + ); +}; diff --git a/docs/ui-ranui-migration.md b/docs/ui-ranui-migration.md new file mode 100644 index 0000000..94c9e9f --- /dev/null +++ b/docs/ui-ranui-migration.md @@ -0,0 +1,96 @@ +# UI 层重构:去 React + Tailwind,改用 ranui 设计系统(builder + signal),保留 SSG + +> 进行中的迁移。原始规划见 Claude plan 文件;本文是仓库内的**权威进度追踪**,随实施更新。 + +## 背景与目标 + +weread 是隐私优先的纯前端阅读器(原 React 19 + Vite + Tailwind + PWA,MPA 整页导航,SSG 预渲染,IndexedDB/ML 都在 Worker)。目标: + +- **去掉 React 和 Tailwind**,UI 层改用 **ranui 的 `builder`(链式 DOM 构建)+ `signal`(Solid 式响应式)**。 +- **用 ranui 的 Geist 设计系统重新设计**(不是 1:1 照搬,重做视觉与组件)。 +- **保留 SSG**(改用 ranui SSR:`.serialize()` + `renderHTMLToString` 出 Declarative Shadow DOM)。 +- **导航维持 MPA**(`window.location.href` 整页跳转,不引入 r-router)。 + +**不变量(只换表现层,行为/数据层原样保留)**:`store/*`、`lib/subscribe.ts` 信号、章节识别与 AI 增强(`lib/chapter/*`、`lib/nlp/*`、`store/chapters.ts`)、两个 Worker(`workers/dbWorker.ts`、`workers/nlpWorker.ts`)、`lib/transformText.ts`、i18n(`locales/index.ts` 的 `t()`)、View Transitions 共享元素 morph、`/weread/` 各处字面量、`id = MD5(content)`、Worker 的 `item-id/item-index/title` 委托点击契约。 + +## 关键技术决策 + +1. **渲染**:ranui `builder`(`View(tag)`/`Div()` 链式,`.build()`→DOM、`.serialize()`→SSR 串)+ `signal`/`createEffect`/`createRoot`。无 JSX。 +2. **路由**:MPA,`router/index.ts` 只留 `base`、`ROUTE_PATH`、`resolveRoute(pathname)`。 +3. **设计系统**:`import 'ranui/style'`(Geist token);旧语义变量重映射到 `--ran-color-*`;真正的亮/暗主题(`initTheme` + `r-theme-switch`)。 +4. **状态桥**:`lib/reactive.ts` 的 `fromStore()` 把 store 事件桥成 ranui signal,喂给 builder 单值绑定;删掉 React 的 `useState` 计数器重渲染。 +5. **SSG**:`views/server.ts` 用 `.serialize()`+`renderHTMLToString()`;`bin/build-ssg.js` 改为 **client 只构建一次**再循环 `render(url)`。 +6. **图标**:`registerBuiltinIcons` 来自 **`ranui/icons`**(复数,非 `ranui/icon`),server + client 都要调。 +7. **验证网关**:`pnpm tsc`/`pnpm lint` 因 TS7 全仓坏;改用 `pnpm build`(esbuild 转译即事实类型门)+ `pnpm test`(vitest 数据层)+ chrome-devtools 浏览器走查。 + +## 进度总览 + +| 阶段 | 内容 | 状态 | +|---|---|---| +| Phase 0 | SSR 冒烟:验证 builder→DSD 往返 | ✅ 完成 | +| Phase 1 | 基建 + 入口骨架 + Loading 打通 | ✅ 完成(已浏览器验证;`pnpm test` 待补) | +| Phase 2 | 叶子组件(Popover/BookCard/Catalogue/DetailMenu/DetailOperate) | ✅ 完成(build 证毕;运行时走查随 P3/P4 接线补) | +| Phase 3 | home 页重设计 + 响应式合并 | ⬜ 未开始 | +| Phase 4 | book-detail 页(含 AI 增强) | ⬜ 未开始 | +| Phase 5 | 清理依赖/死代码,终版 build + 走查 | ⬜ 未开始 | + +## Phase 0 — SSR 可行性 ✅ + +一次性脚本验证:SSR 环境 `isSSR` 为真;builder `.serialize()` 出裸 `` 标签;`renderHTMLToString()` 内联 `