apphx 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/cli.js +41 -11
- package/dist/cli.js.map +1 -1
- package/dist/config.js +4 -2
- package/dist/config.js.map +1 -1
- package/dist/integrations.js +154 -95
- package/dist/integrations.js.map +1 -1
- package/dist/notify.js +267 -0
- package/dist/notify.js.map +1 -0
- package/dist/runner.js +119 -20
- package/dist/runner.js.map +1 -1
- package/dist/schemas.js +57 -2
- package/dist/schemas.js.map +1 -1
- package/dist/vendor/obfuscator/dist/config.js +119 -6
- package/dist/vendor/obfuscator/dist/config.js.map +1 -1
- package/dist/vendor/obfuscator/dist/dfa.js +528 -0
- package/dist/vendor/obfuscator/dist/dfa.js.map +1 -0
- package/dist/vendor/obfuscator/dist/flutter.js +3266 -0
- package/dist/vendor/obfuscator/dist/flutter.js.map +1 -0
- package/dist/vendor/obfuscator/dist/image-utils.js +335 -0
- package/dist/vendor/obfuscator/dist/image-utils.js.map +1 -0
- package/dist/vendor/obfuscator/dist/junk.js +1501 -0
- package/dist/vendor/obfuscator/dist/junk.js.map +1 -0
- package/dist/vendor/obfuscator/dist/lexicon-data.js +972 -0
- package/dist/vendor/obfuscator/dist/lexicon-data.js.map +1 -0
- package/dist/vendor/obfuscator/dist/obfuscate.js +51 -2
- package/dist/vendor/obfuscator/dist/obfuscate.js.map +1 -1
- package/dist/vendor/obfuscator/dist/objc-symbols.js +1819 -0
- package/dist/vendor/obfuscator/dist/objc-symbols.js.map +1 -0
- package/dist/vendor/obfuscator/dist/project-identity.js +852 -0
- package/dist/vendor/obfuscator/dist/project-identity.js.map +1 -0
- package/dist/vendor/obfuscator/dist/string-encrypt.js +330 -0
- package/dist/vendor/obfuscator/dist/string-encrypt.js.map +1 -0
- package/examples/android-java.factory.json +40 -5
- package/examples/expo.factory.json +68 -5
- package/examples/flutter.factory.json +40 -4
- package/examples/luggage.json +1 -0
- package/examples/multi-role-agents.md +129 -0
- package/examples/mygo.factory.json +54 -4
- package/examples/queue-loop-demo.md +146 -0
- package/examples/react-native.factory.json +58 -5
- package/examples/roles.example.json +31 -0
- package/examples/swift.factory.json +60 -5
- package/examples/uni-app.factory.json +58 -5
- package/package.json +1 -1
- package/skills/apphx/SKILL.md +39 -4
- package/skills/apphx/resources/requirement.json +1 -0
- package/skills/apphx-obfuscator/LICENSE +21 -0
- package/skills/apphx-obfuscator/SKILL.md +72 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flutter.js","names":[],"sources":["../src/flutter.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport type { TransformOutcome, WalkEntry } from './common.js';\nimport { deriveHash, deriveUuid, escapeRegExp, seededRandom, writeIfChanged } from './common.js';\n\n/**\n * Deterministic \"Flutter obfuscation\" core: naming rules, filter/whitelist sets,\n * comment-stripping behaviour, resource reference rewriting, resource hash padding and\n * project.pbxproj UUID remapping. Every random draw is seeded, so identical\n * (files + options + seed) always produce byte-identical output.\n */\n\ntype Rng = () => number;\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\n/** 0 = my-rule (default), 1 = enchant (falls back to my-rule), 2 = my-rule, 3 = random string. */\nexport type FlutterMissAlgorithm = 0 | 1 | 2 | 3;\n\nexport interface FlutterFeatures {\n variable?: boolean;\n className?: boolean;\n method?: boolean;\n resourceName?: boolean;\n resourceHash?: boolean;\n deleteNotes?: boolean;\n uuid?: boolean;\n}\n\nexport interface FlutterOptions {\n prefixWord?: string;\n missAlgorithmType?: FlutterMissAlgorithm;\n classWhiteList?: readonly string[];\n methodWhiteList?: readonly string[];\n variableWhiteList?: readonly string[];\n features?: FlutterFeatures;\n}\n\nexport interface NormalizedFlutterOptions {\n prefixWord: string;\n missAlgorithmType: FlutterMissAlgorithm;\n classWhiteList: readonly string[];\n methodWhiteList: readonly string[];\n variableWhiteList: readonly string[];\n features: Required<FlutterFeatures>;\n}\n\nconst ALL_FEATURES: Required<FlutterFeatures> = {\n variable: true, className: true, method: true, resourceName: true,\n resourceHash: true, deleteNotes: true, uuid: true,\n};\n\nexport function normalizeFlutterOptions(options: FlutterOptions = {}): NormalizedFlutterOptions {\n return {\n prefixWord: options.prefixWord ?? '',\n missAlgorithmType: options.missAlgorithmType ?? 0,\n classWhiteList: options.classWhiteList ?? [],\n methodWhiteList: options.methodWhiteList ?? [],\n variableWhiteList: options.variableWhiteList ?? [],\n features: { ...ALL_FEATURES, ...(options.features ?? {}) },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Fixed filter / whitelist sets from the original modules\n// ---------------------------------------------------------------------------\n\nexport const FLUTTER_MUST_WHITE_CLASSES: readonly string[] = ['MyApp'];\n\nexport const FLUTTER_IGNORE_METHODS: readonly string[] = [\n 'main', 'build', 'initState', 'dispose', 'didUpdateWidget', 'reassemble',\n 'setState', 'deactivate', 'activate', 'didChangeDependencies', 'debugFillProperties',\n];\n\nexport const FLUTTER_IGNORE_VARIABLES: readonly string[] = [\n 'value', 'size', 'width', 'height', 'length', 'r', 'msg', 'realUri', 'data',\n 'file', 'status', 'controller', 'key',\n];\n\nexport const FLUTTER_CONSTANT_KEYWORDS: readonly string[] = ['static', 'const', 'final', 'var', 'late'];\n\nexport const FLUTTER_BASIC_DATA_TYPES: readonly string[] = [\n 'Number', 'int', 'double', 'num', 'String', 'Boolean', 'bool', 'List', 'Map',\n 'symbol', 'abs', 'ceil', 'floor', 'void',\n];\n\nexport const FLUTTER_BASIC_CONTROL_TYPES: readonly string[] = [\n 'Widget', 'MaterialApp', 'MaterialColor', 'MaterialButton', 'RawMaterialButton',\n 'MaterialPageRoute', 'MaterialAccentColor', 'MergeableMaterialItem', 'AppBar',\n 'BottomAppBar', 'BottomNavigationBarItem', 'SnackBar', 'ScrollbarPainter',\n 'FlexileSpaceBar', 'ButtonBar', 'SnackBarAction', 'TabBar', 'AlertDialog', 'Dialog',\n 'AboutDialog', 'SimpleDialog', 'Scaffold', 'ScaffoldState', 'ScrollView', 'Scrollable',\n 'SingleChildScrollView', 'ScrollNotfication', 'NotificationListener', 'ScrollbarPainter',\n 'ScrollMetrics', 'ScrollPhysics', 'BoxScrollView', 'CustomScrollView', 'NestedScrollView',\n 'GridTile', 'GridView', 'GridPaper', 'SliverGrid', 'GridTileBar', 'AnimatedList',\n 'ListView', 'ListBody', 'ExpansionPanelList', 'PageView', 'Align', 'Stack', 'IndexdStack',\n 'Row', 'Column', 'Container', 'Center', 'ConstrainedBox', 'OverflowBox', 'DecoratedBox',\n 'RendorDecoratedBox', 'FittedBox', 'LimitedBox', 'RotatedBox', 'SizedBox',\n 'SizeOverflowBox', 'UnconstrainedBox', 'Expanded', 'Padding', 'SliverPadding',\n 'AnimatedPadding', 'Table', 'Card', 'TextField', 'Checkbox', 'CheckboxListTile',\n 'FlatButton', 'RaisedButton', 'IconButton', 'PopupMenuButton', 'FloatingActionButton',\n 'RawMaterialButton', 'DropdownButton', 'OutlineButton', 'Text', 'RichText', 'Radio',\n 'RadioListTile', 'Slider', 'SliderTheme', 'SliderThemeData', 'Switch', 'SwitchListTile',\n 'AnimatedSwitcher', 'AssetImage', 'DecorationImage', 'ExactAssetImage', 'FadeInImage',\n 'FileImage', 'NetworkImage', 'RawImage', 'MemoryImage', 'ImageImageIcon', 'IconTheme',\n 'IconData', 'IconThemeData', 'Canvas', 'PainterSketch', 'PainterPath',\n 'CircleProgressBarPainter', 'BottomNavigationBarItem', 'BottomNavigationBar', 'Tab',\n 'CheckedPopupMenuItem', 'DropdownMenuItem', 'PopupMenuBottom', 'PopupMenuDivider',\n 'PopopMenuEntry', 'PopupMenuItem', 'DayPicker', 'MonthPicker', 'YearPicker',\n 'ShowdatePicker', 'CityPicker', 'Chip', 'ChipTheme', 'ChipThemeData', 'ChoiceChip',\n 'FilterChip', 'InputChip', 'RawChip', 'ClipOval', 'ClipRect', 'ClipRRect', 'ClipPath',\n 'CustomClipper', 'BorderRadius', 'CircularPercentIndicator', 'LinearProgressIndicator',\n 'NestedScrollViewRefreshIndicator', 'SwipeRefreshLayout', 'BoxDecoration',\n 'ShapeDecoration', 'InkDecoration', 'FlutterLogoDecoration', 'InputDecoration',\n 'TextDecoration', 'RoundedRectangleBorder', 'BoxShape', 'CircleBorder', 'CupertinoApp',\n 'CupertinoButton', 'CupertinoColors', 'CupertinoIcons', 'CupertinoNavigationBar',\n 'CupertinoPageRoute', 'CupertinoPageScaffold', 'CupertinoPicker', 'CupertinoPopupSurface',\n 'CupertinoScrollbar', 'CupertinoSlider', 'CupertinoSegmentedControl',\n 'CupertinoSliverNavigationBar', 'CupertinoSwitch', 'CupertinoTabBar',\n 'CupertinoTabScafold', 'CupertinoTabView', 'CupertinoTimerPicker', 'SliverAppBar',\n 'SliverFixedExtentList', 'SliverList', 'SliverGrid', 'SliverPersistentHeader',\n 'SliverFixedExtentList', 'SliverToBoxAdapter', 'Localizations', 'Semantics', 'Label',\n 'Positioned', 'Ink', 'InkWell', 'ViewController', 'Drawer', 'Divider', 'GestureDetector',\n 'FocusScope', 'WillPopScope', 'SafeArea', 'Transform',\n];\n\nconst MUST_WHITE_CLASS_SET = new Set(FLUTTER_MUST_WHITE_CLASSES);\nconst IGNORE_METHOD_SET = new Set(FLUTTER_IGNORE_METHODS);\nconst IGNORE_VARIABLE_SET = new Set(FLUTTER_IGNORE_VARIABLES);\nconst CONSTANT_KEYWORD_SET = new Set(FLUTTER_CONSTANT_KEYWORDS);\nconst BASIC_DATA_SET = new Set(FLUTTER_BASIC_DATA_TYPES);\nconst BASIC_CONTROL_SET = new Set(FLUTTER_BASIC_CONTROL_TYPES);\n\nconst PUNCTUATION_EXCEPT_UNDERSCORE = new Set('!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^`{|}~');\nconst UPPER_AND_LOWER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n\n// ---------------------------------------------------------------------------\n// Lexicon (deterministic 2400-word subset, sampled with a fixed seed).\n// ---------------------------------------------------------------------------\n\nconst LEXICON: readonly string[] = [\n \"sideroblast\", \"siderochrome\", \"siderocyte\", \"siderography\", \"siderolite\", \"siderophilin\", \"sideroscope\", \"siderosis\", \"siderostat\", \"sidesaddle\", \"sideseat\", \"sideshow\",\n \"sideslip\", \"sidesman\", \"sidespin\", \"sidesplitter\", \"sidesplitting\", \"sidestep\", \"sidestream\", \"sidestroke\", \"sideswipe\", \"sidetone\", \"sidetrack\", \"sidewalk\",\n \"sideward\", \"sidewards\", \"sideway\", \"sideways\", \"sidewipe\", \"sidewise\", \"sidi\", \"siding\", \"sidle\", \"sidon\", \"sidonian\", \"sidra\",\n \"siege\", \"siegfried\", \"siena\", \"sienese\", \"sienna\", \"sierozem\", \"sierra\", \"sierran\", \"siesta\", \"sieur\", \"sieva\", \"sieve\",\n \"sievert\", \"sifaka\", \"siff\", \"siffleur\", \"siffleuse\", \"sift\", \"sifter\", \"sig\", \"sigh\", \"sight\", \"sighthole\", \"sightless\",\n \"sightline\", \"sightly\", \"sightproof\", \"sightsee\", \"sightseeing\", \"sightseer\", \"sightsinging\", \"sightworthy\", \"sigil\", \"sigillographer\", \"sigillography\", \"sigillum\",\n \"sigint\", \"sigla\", \"siglos\", \"sigmate\", \"sigmatropic\", \"sigmoid\", \"sigmoidectomy\", \"sigmoiditis\", \"sigmoidoscope\", \"sigmoidostomy\", \"sign\", \"signable\",\n \"signaler\", \"signaling\", \"signalise\", \"signality\", \"signalize\", \"signalled\", \"signally\", \"signalman\", \"signalment\", \"signans\", \"signary\", \"signatary\",\n \"signatory\", \"signatum\", \"signatureless\", \"signboard\", \"signed\", \"signee\", \"signet\", \"signifiable\", \"signifiant\", \"significance\", \"significancy\", \"significans\",\n \"significant\", \"significantly\", \"signification\", \"significative\", \"significatory\", \"significs\", \"signify\", \"signior\", \"signiory\", \"signman\", \"signor\", \"signore\",\n \"signori\", \"signorina\", \"signorine\", \"signorini\", \"signorino\", \"signory\", \"signpost\", \"signwriter\", \"sigri\", \"sigrid\", \"sigurd\", \"sihanouk\",\n \"sijo\", \"sika\", \"siker\", \"sikh\", \"sikkim\", \"sikkimese\", \"silage\", \"silane\", \"silanization\", \"silanize\", \"silas\", \"silastic\",\n \"silbador\", \"silbo\", \"sild\", \"sile\", \"silence\", \"silencer\", \"silent\", \"silentious\", \"silently\", \"silenus\", \"silesia\", \"silex\",\n \"silhouette\", \"silica\", \"silicate\", \"siliceous\", \"silicic\", \"silicicolous\", \"silicide\", \"silicidize\", \"silicification\", \"silicify\", \"silicious\", \"silicium\",\n \"silicize\", \"silicle\", \"silicomanganese\", \"silicon\", \"silicone\", \"silicosis\", \"silicothermic\", \"silicula\", \"silicular\", \"silicule\", \"siliqua\", \"silique\",\n \"silk\", \"silkaline\", \"silken\", \"silkgrower\", \"silkiness\", \"silklike\", \"silkman\", \"silkoline\", \"silkscreen\", \"silkweed\", \"silkworm\", \"silky\",\n \"sill\", \"sillabub\", \"sillar\", \"siller\", \"sillibub\", \"sillily\", \"sillimanite\", \"silliness\", \"sillographer\", \"silly\", \"silo\", \"siloam\",\n \"siloxane\", \"silphid\", \"silt\", \"siltstone\", \"silty\", \"silundum\", \"silures\", \"silurid\", \"siluroid\", \"silva\", \"silvan\", \"silvana\",\n \"silvanus\", \"silver\", \"silverback\", \"silverbeater\", \"silverberry\", \"silverfish\", \"silvering\", \"silverless\", \"silverly\", \"silvern\", \"silverpoint\", \"silverside\",\n \"silversides\", \"silversmith\", \"silvertail\", \"silverware\", \"silverweed\", \"silvery\", \"silvester\", \"silvical\", \"silvichemical\", \"silvicide\", \"silvicolous\", \"silvics\",\n \"silviculture\", \"sima\", \"simar\", \"simazine\", \"simba\", \"simbirsk\", \"simd\", \"simferopol\", \"simian\", \"similar\", \"similarity\", \"similarly\",\n \"simile\", \"similitude\", \"similize\", \"simious\", \"simitar\", \"simla\", \"simmer\", \"simoleon\", \"simoniac\", \"simoniacal\", \"simonist\", \"simonize\",\n \"simonstown\", \"simony\", \"simoom\", \"simp\", \"simpai\", \"simpatico\", \"simper\", \"simperingly\", \"simple\", \"simplehearted\", \"simpleminded\", \"simpleness\",\n \"simpleton\", \"simplex\", \"simplicidentate\", \"simplicist\", \"simpliciter\", \"simplicity\", \"simplification\", \"simplify\", \"simplism\", \"simplist\", \"simplistic\", \"simply\",\n \"simsim\", \"simtel\", \"simul\", \"simulacra\", \"simulacre\", \"simulacrum\", \"simuland\", \"simulant\", \"simular\", \"simulate\", \"simulation\", \"simulative\",\n \"simulator\", \"simulcast\", \"simulfix\", \"simultaneity\", \"simultaneous\", \"simultaneously\", \"sin\", \"sina\", \"sinaean\", \"sinai\", \"sinaic\", \"sinaitic\",\n \"sinal\", \"sinanthropus\", \"sinapin\", \"sinapine\", \"sinapism\", \"sinarquist\", \"sinbad\", \"since\", \"sincere\", \"sincerely\", \"sincerity\", \"sincipital\",\n \"sinciput\", \"sinclair\", \"sindolor\", \"sindon\", \"sindonology\", \"sine\", \"sinecure\", \"sinecurist\", \"sinew\", \"sinewy\", \"sinfonia\", \"sinful\",\n \"sinfully\", \"sing\", \"singapore\", \"singaporean\", \"singaradja\", \"singe\", \"singer\", \"singhalese\", \"singing\", \"single\", \"singlechip\", \"singlehanded\",\n \"singleness\", \"singlestick\", \"singlet\", \"singleton\", \"singletree\", \"singly\", \"singsong\", \"singspiel\", \"singular\", \"singularism\", \"singularity\", \"singularize\",\n \"singularly\", \"singulative\", \"singultation\", \"singultus\", \"sinhala\", \"sinhalese\", \"sinhalite\", \"sinic\", \"sinicism\", \"sinicize\", \"sinify\", \"sining\",\n \"sinister\", \"sinisterly\", \"sinistrad\", \"sinistral\", \"sinistrocular\", \"sinistrorse\", \"sinitic\", \"sink\", \"sinkable\", \"sinkage\", \"sinker\", \"sinkful\",\n \"sinkhole\", \"sinkiang\", \"sinking\", \"sinless\", \"sinlessly\", \"sinneh\", \"sinner\", \"sinnerite\", \"sinnet\", \"sinoatrial\", \"sinogram\", \"sinography\",\n \"sinoite\", \"sinological\", \"sinologist\", \"sinologue\", \"sinology\", \"sinophile\", \"sinophobia\", \"sinopis\", \"sinopite\", \"sinople\", \"sinpo\", \"sins\",\n \"sinsemilla\", \"sinsyne\", \"sinter\", \"sintering\", \"sintra\", \"sinuate\", \"sinuation\", \"sinuatrial\", \"sinuiju\", \"sinuosity\", \"sinuous\", \"sinus\",\n \"sinusitis\", \"sinusoid\", \"sinusoidal\", \"siogon\", \"sion\", \"siouan\", \"sioux\", \"siphon\", \"siphonaceous\", \"siphonage\", \"siphonal\", \"siphonate\",\n \"siphonein\", \"siphonet\", \"siphonic\", \"siphonophore\", \"siphonostele\", \"siphunculate\", \"siphunculated\", \"sippet\", \"sipunculan\", \"siquis\", \"sir\", \"sirach\",\n \"siracusa\", \"siratro\", \"sircar\", \"sirdar\", \"sire\", \"siree\", \"siren\", \"sirena\", \"sirenian\", \"siret\", \"sirgang\", \"sirian\",\n \"siriasis\", \"sirius\", \"sirloin\", \"sirocco\", \"sirrah\", \"sirree\", \"sirtaki\", \"sirup\", \"sirupy\", \"sirvente\", \"sirventes\", \"sis\",\n \"sisal\", \"siscowet\", \"sisera\", \"siskin\", \"sismogram\", \"sismograph\", \"sismographic\", \"sissified\", \"sissy\", \"sistan\", \"sister\", \"sisterhood\",\n \"sisterless\", \"sisterly\", \"sistern\", \"sistership\", \"sistine\", \"sistroid\", \"sistrum\", \"sisyphean\", \"sisyphus\", \"sit\", \"sitar\", \"sitcom\",\n \"site\", \"sitebuilder\", \"sitfast\", \"sith\", \"sitology\", \"sitomania\", \"sitophobia\", \"sitosterol\", \"sitotoxin\", \"sitrep\", \"sitsang\", \"sittable\",\n \"sittang\", \"sitten\", \"sitter\", \"sitting\", \"sittoung\", \"sittwe\", \"situate\", \"situated\", \"situation\", \"situla\", \"situp\", \"situs\",\n \"sitzkrieg\", \"sitzkrleg\", \"sitzmark\", \"siu\", \"siva\", \"sivaite\", \"sivan\", \"siwan\", \"six\", \"sixain\", \"sixer\", \"sixern\",\n \"sixfold\", \"sixpence\", \"sixpenny\", \"sixpennyworth\", \"sixscore\", \"sixte\", \"sixteen\", \"sixteenmo\", \"sixteenth\", \"sixteenthly\", \"sixth\", \"sixthly\",\n \"sixtieth\", \"sixtine\", \"sixty\", \"sixtyfold\", \"sizable\", \"sizar\", \"size\", \"sizeable\", \"sized\", \"sizer\", \"sizing\", \"sizy\",\n \"sizz\", \"sizzard\", \"sizzle\", \"sizzler\", \"sjaa\", \"sjab\", \"sjaelland\", \"sjambok\", \"sjc\", \"sjd\", \"skagerrak\", \"skald\",\n \"skandalon\", \"skat\", \"skate\", \"skatebarrow\", \"skateboard\", \"skatemobile\", \"skatepark\", \"skater\", \"skating\", \"skatol\", \"skatole\", \"skean\",\n \"sked\", \"skedaddle\", \"skee\", \"skeeler\", \"skeesicks\", \"skeet\", \"skeeter\", \"skeetshoot\", \"skegger\", \"skein\", \"skelecton\", \"skeletal\",\n \"skeletogenous\", \"skeleton\", \"skeletonize\", \"skeletonless\", \"skeletony\", \"skellum\", \"skelp\", \"skelter\", \"skeltonics\", \"sken\", \"skene\", \"skep\",\n \"skepsis\", \"skeptic\", \"skeptical\", \"skeptically\", \"skepticism\", \"skepticize\", \"skerrick\", \"skerry\", \"sket\", \"sketch\", \"sketchbook\", \"sketchily\",\n \"sketchpad\", \"sketchy\", \"skete\", \"skew\", \"skewback\", \"skewbald\", \"skewer\", \"skewwhiff\", \"skfros\", \"ski\", \"skiagram\", \"skiagraph\",\n \"skiagraphy\", \"skiamachy\", \"skiametry\", \"skiascope\", \"skiascopy\", \"skibby\", \"skibob\", \"skibobber\", \"skibobbing\", \"skice\", \"skid\", \"skidder\",\n \"skiddoo\", \"skiddy\", \"skidoo\", \"skidproof\", \"skier\", \"skiey\", \"skiff\", \"skiffle\", \"skiing\", \"skijoring\", \"skikda\", \"skilful\",\n \"skill\", \"skilled\", \"skillet\", \"skillful\", \"skillfully\", \"skillion\", \"skilly\", \"skim\", \"skimboard\", \"skimeister\", \"skimmer\", \"skimming\",\n \"skimo\", \"skimobile\", \"skimp\", \"skimpily\", \"skimpy\", \"skin\", \"skinbound\", \"skinch\", \"skinflint\", \"skinfold\", \"skinful\", \"skinhead\",\n \"skink\", \"skinner\", \"skinnerian\", \"skinniness\", \"skinny\", \"skinpopping\", \"skint\", \"skintight\", \"skiogram\", \"skiograph\", \"skip\", \"skipjack\",\n \"skiplane\", \"skippable\", \"skipper\", \"skippet\", \"skippingly\", \"skippy\", \"skirl\", \"skirmish\", \"skirmisher\", \"skirr\", \"skirret\", \"skirt\",\n \"skirting\", \"skiscooter\", \"skish\", \"skit\", \"skite\", \"skitter\", \"skittish\", \"skittle\", \"skive\", \"skiver\", \"skivey\", \"skivvy\",\n \"skiwear\", \"sklodowskite\", \"skoal\", \"skokiaan\", \"skolly\", \"skoob\", \"skookum\", \"skopje\", \"skoplje\", \"skosh\", \"skotophile\", \"skua\",\n \"skulduggery\", \"skulk\", \"skulker\", \"skull\", \"skullcap\", \"skullduggery\", \"skullfish\", \"skullguard\", \"skunk\", \"skunkery\", \"skupshtina\", \"skurfing\",\n \"skutari\", \"skutterudite\", \"sky\", \"skyborne\", \"skybridge\", \"skycap\", \"skycoach\", \"skydive\", \"skyer\", \"skyey\", \"skyful\", \"skyish\",\n \"skyjack\", \"skyjacking\", \"skylab\", \"skylark\", \"skylarker\", \"skylarking\", \"skyless\", \"skylight\", \"skyline\", \"skylit\", \"skylon\", \"skylounge\",\n \"skymark\", \"skymotel\", \"skyphone\", \"skyphos\", \"skyport\", \"skyrocket\", \"skysail\", \"skyscape\", \"skyscrape\", \"skyscraper\", \"skyscraping\", \"skysweeper\",\n \"skytrooper\", \"skytroops\", \"skywalk\", \"skyward\", \"skywards\", \"skywatch\", \"skyway\", \"skywriting\", \"sla\", \"slab\", \"slabber\", \"slabby\",\n \"slablike\", \"slabstone\", \"slack\", \"slackage\", \"slacken\", \"slacker\", \"sladang\", \"slade\", \"slag\", \"slagging\", \"slaggy\", \"slagheap\",\n \"slain\", \"slaister\", \"slake\", \"slakeless\", \"slaky\", \"slalom\", \"slam\", \"slammer\", \"slan\", \"slanchways\", \"slanchwise\", \"slander\",\n \"slanderella\", \"slanderer\", \"slanderous\", \"slanderously\", \"slang\", \"slangster\", \"slanguage\", \"slangy\", \"slank\", \"slant\", \"slantendicular\", \"slantindicular\",\n \"slantingways\", \"slantingwise\", \"slantways\", \"slantwise\", \"slap\", \"slapdab\", \"slapdash\", \"slapdashery\", \"slaphappy\", \"slapjack\", \"slapman\", \"slapping\",\n \"slapstick\", \"slash\", \"slashing\", \"slat\", \"slatch\", \"slate\", \"slater\", \"slather\", \"slating\", \"slatted\", \"slatter\", \"slattern\",\n \"slatternly\", \"slaty\", \"slaughter\", \"slaughterhouse\", \"slaughterous\", \"slav\", \"slavdom\", \"slave\", \"slaveholder\", \"slaveholding\", \"slaveocracy\", \"slaver\",\n \"slavery\", \"slavey\", \"slavic\", \"slavicist\", \"slavicize\", \"slavikite\", \"slavish\", \"slavishly\", \"slavism\", \"slavist\", \"slavocracy\", \"slavonia\",\n \"slavonian\", \"slavonic\", \"slavonize\", \"slavophil\", \"slavophile\", \"slavophobe\", \"slavophobist\", \"slaw\", \"slay\", \"sldram\", \"sleave\", \"sleazy\",\n \"sled\", \"sledding\", \"sledge\", \"sledgehammer\", \"sledgemeter\", \"sleek\", \"sleekly\", \"sleep\", \"sleepcoat\", \"sleeper\", \"sleepful\", \"sleepily\",\n \"sleepiness\", \"sleeping\", \"sleepless\", \"sleepwalker\", \"sleepwalking\", \"sleepwear\", \"sleepy\", \"sleepyhead\", \"sleet\", \"sleety\", \"sleeve\", \"sleeveboard\",\n \"sleeveen\", \"sleeveless\", \"sleevelet\", \"sleigh\", \"sleighing\", \"sleight\", \"slender\", \"slenderize\", \"slenderly\", \"slentando\", \"slept\", \"sleugh\",\n \"sleuth\", \"sleuthhound\", \"slew\", \"sley\", \"slezsko\", \"slic\", \"slice\", \"sliceable\", \"slicer\", \"slick\", \"slicken\", \"slickenside\",\n \"slicker\", \"slickness\", \"slickrock\", \"slickster\", \"slid\", \"slidden\", \"slide\", \"slideway\", \"sliding\", \"slight\", \"slighting\", \"slightingly\",\n \"slightly\", \"slightness\", \"slily\", \"slim\", \"slime\", \"slimicide\", \"sliminess\", \"slimline\", \"slimly\", \"slimmer\", \"slimming\", \"slimmish\",\n \"slimnastics\", \"slimsy\", \"slimy\", \"sling\", \"slingback\", \"slinger\", \"slingman\", \"slingshop\", \"slingshot\", \"slink\", \"slinkingly\", \"slinkskin\",\n \"slinkweed\", \"slinky\", \"slip\", \"slipcase\", \"slipcover\", \"slipform\", \"sliphorn\", \"slipknot\", \"slipover\", \"slippage\", \"slipper\", \"slipperwort\",\n \"slippery\", \"slippy\", \"sliprail\", \"slipsheet\", \"slipshod\", \"slipslop\", \"slipsole\", \"slipstick\", \"slipstone\", \"slipstream\", \"slipt\", \"slipup\",\n \"slipware\", \"slipway\", \"slit\", \"slither\", \"slithery\", \"sliver\", \"slivovitz\", \"sloak\", \"sloat\", \"slob\", \"slobber\", \"slobbery\",\n \"sloe\", \"slog\", \"slogan\", \"sloganeer\", \"slogger\", \"slogging\", \"sloid\", \"slojd\", \"sloop\", \"sloot\", \"slop\", \"slope\",\n \"slopehead\", \"slopewash\", \"sloping\", \"sloppy\", \"slopseller\", \"slopshop\", \"slopwork\", \"slopy\", \"slosh\", \"sloshy\", \"slotback\", \"slote\",\n \"sloth\", \"slothful\", \"slothfully\", \"slothfulness\", \"slotware\", \"slouch\", \"slouching\", \"slouchy\", \"slough\", \"sloughy\", \"slovak\", \"slovakian\",\n \"sloven\", \"slovene\", \"slovenia\", \"slovenian\", \"slovenly\", \"slovenry\", \"slovensko\", \"slow\", \"slowdown\", \"slower\", \"slowgoing\", \"slowhound\",\n \"slowish\", \"slowly\", \"slowness\", \"slowpaced\", \"slowpoke\", \"slowup\", \"slowworm\", \"sloyd\", \"slp\", \"slub\", \"slubber\", \"slubberdegullion\",\n \"slubbing\", \"sludge\", \"sludgeworm\", \"sludgy\", \"slue\", \"slug\", \"slugabed\", \"slugfest\", \"sluggard\", \"sluggardly\", \"slugger\", \"slugging\",\n \"sluggish\", \"sluice\", \"sluiceway\", \"sluit\", \"slum\", \"slumber\", \"slumbercoach\", \"slumberland\", \"slumberous\", \"slumbery\", \"slumbrous\", \"slumdweller\",\n \"slumgum\", \"slumland\", \"slumlord\", \"slummer\", \"slummock\", \"slummy\", \"slump\", \"slung\", \"slungshot\", \"slunk\", \"slup\", \"slur\",\n \"slurp\", \"slurry\", \"slurvian\", \"slush\", \"slushy\", \"slut\", \"sluttery\", \"sluttish\", \"slv\", \"sly\", \"slyboots\", \"slyly\",\n \"slype\", \"smack\", \"smacker\", \"smackeroo\", \"smackhead\", \"smacking\", \"smacksman\", \"small\", \"smallage\", \"smallboy\", \"smallclothes\", \"smallholder\",\n \"smallholding\", \"smallish\", \"smallmouth\", \"smallness\", \"smallpox\", \"smallshot\", \"smallsword\", \"smallwares\", \"smally\", \"smalt\", \"smalti\", \"smaltine\",\n \"smaltite\", \"smalto\", \"smaragd\", \"smaragdine\", \"smaragdite\", \"smarm\", \"smarmy\", \"smartdrive\", \"smarten\", \"smartless\", \"smartly\", \"smartness\",\n \"smartweed\", \"smarty\", \"smash\", \"smashed\", \"smasher\", \"smasheroo\", \"smashing\", \"smashup\", \"smatter\", \"smattering\", \"smattery\", \"smaze\",\n \"smb\", \"smd\", \"smds\", \"smear\", \"smearcase\", \"smeary\", \"smeech\", \"smegma\", \"smell\", \"smellage\", \"smeller\", \"smellie\",\n \"smelly\", \"smelt\", \"smelter\", \"smeltery\", \"smelting\", \"smerrebrxd\", \"smew\", \"smf\", \"smg\", \"smice\", \"smidgen\", \"smidgeon\",\n \"smiercase\", \"smilacaceous\", \"smile\", \"smileless\", \"smiley\", \"smiling\", \"smilingly\", \"smilodon\", \"smirch\", \"smirk\", \"smirky\", \"smirnoff\",\n \"smitch\", \"smite\", \"smith\", \"smithcraft\", \"smithereen\", \"smithereens\", \"smithery\", \"smithiantha\", \"smithite\", \"smithsonite\", \"smithwork\", \"smithy\",\n \"smitten\", \"smitty\", \"smock\", \"smocking\", \"smog\", \"smogbound\", \"smoggy\", \"smogout\", \"smokable\", \"smokables\", \"smoke\", \"smokeable\",\n \"smokebell\", \"smokebox\", \"smokechaser\", \"smokehouse\", \"smokeless\", \"smokemeter\", \"smokepot\", \"smokeproof\", \"smokery\", \"smokestack\", \"smoketight\", \"smokey\",\n \"smokily\", \"smoking\", \"smoko\", \"smoky\", \"smolder\", \"smolensk\", \"smolt\", \"smon\", \"smooch\", \"smoodge\", \"smooth\", \"smoothbore\",\n \"smoothen\", \"smoother\", \"smoothhound\", \"smoothie\", \"smoothly\", \"smoothness\", \"smoothy\", \"smorgasbord\", \"smorzando\", \"smote\", \"smother\", \"smotheration\",\n \"smothery\", \"smouch\", \"smoulder\", \"smriti\", \"smsa\", \"smtpd\", \"smudge\", \"smudgily\", \"smudginess\", \"smudgy\", \"smug\", \"smuggle\",\n \"smuggler\", \"smuggling\", \"smugness\", \"smut\", \"smutch\", \"smuttily\", \"smuttiness\", \"smutty\", \"smyrna\", \"smyrniot\", \"smythite\", \"snack\",\n \"snackery\", \"snacketeria\", \"snackette\", \"snaffle\", \"snafu\", \"snag\", \"snagged\", \"snaggletooth\", \"snaggletoothed\", \"snaggy\", \"snail\", \"snailery\",\n \"snailfish\", \"snaillike\", \"snake\", \"snakebird\", \"snakebite\", \"snakefly\", \"snakehead\", \"snakeless\", \"snakelet\", \"snakelike\", \"snakemouth\", \"snakeroot\",\n \"snakeskin\", \"snakestone\", \"snakewood\", \"snakey\", \"snakish\", \"snaky\", \"snallygaster\", \"snap\", \"snapback\", \"snapbolt\", \"snapdragon\", \"snaphance\",\n \"snaphaunce\", \"snapper\", \"snappish\", \"snappy\", \"snapshoot\", \"snare\", \"snark\", \"snarl\", \"snarler\", \"snarlingly\", \"snarly\", \"snash\",\n \"snatch\", \"snatchback\", \"snatchy\", \"snath\", \"snathe\", \"snax\", \"snazzy\", \"sncc\", \"sncf\", \"snead\", \"sneak\", \"sneaker\",\n \"sneaking\", \"sneakingly\", \"sneaksby\", \"sneaky\", \"sned\", \"sneer\", \"sneering\", \"sneeringly\", \"sneery\", \"sneesh\", \"sneeshing\", \"sneeze\",\n \"sneezes\", \"sneezy\", \"snell\", \"snelskrif\", \"snib\", \"snick\", \"snicker\", \"snickersnee\", \"snicket\", \"snide\", \"snidesman\", \"sniff\",\n \"sniffable\", \"sniffer\", \"sniffish\", \"sniffle\", \"sniffy\", \"snift\", \"snifter\", \"snifty\", \"snig\", \"sniggle\", \"snip\", \"snipe\",\n \"snipehunt\", \"snipehunter\", \"sniper\", \"sniperscope\", \"snipey\", \"snippers\", \"snippersnapper\", \"snippet\", \"snippety\", \"snipping\", \"snippy\", \"snit\",\n \"snitch\", \"snivel\", \"sniveler\", \"sniveller\", \"snmp\", \"snob\", \"snobbery\", \"snobbish\", \"snobbishness\", \"snobbism\", \"snobby\", \"snobism\",\n \"snobling\", \"snobol\", \"snockered\", \"snoek\", \"snofari\", \"snog\", \"snollygoster\", \"snood\", \"snook\", \"snooker\", \"snoop\", \"snooper\",\n \"snooperscope\", \"snoopery\", \"snoopy\", \"snoot\", \"snootful\", \"snooty\", \"snooze\", \"snopes\", \"snopesian\", \"snore\", \"snorer\", \"snort\",\n \"snorter\", \"snorty\", \"snot\", \"snotnose\", \"snotty\", \"snottynose\", \"snout\", \"snovian\", \"snow\", \"snowball\", \"snowbank\", \"snowbell\",\n \"snowberry\", \"snowbird\", \"snowblink\", \"snowbound\", \"snowbreak\", \"snowbrush\", \"snowbush\", \"snowcap\", \"snowcapped\", \"snowcat\", \"snowcem\", \"snowcraft\",\n \"snowcreep\", \"snowdon\", \"snowdrift\", \"snowdrop\", \"snowfall\", \"snowfield\", \"snowflake\", \"snowhole\", \"snowhouse\", \"snowmaking\", \"snowman\", \"snowmelt\",\n \"snowmobile\", \"snowmobilist\", \"snowpack\", \"snowplow\", \"snowscape\", \"snowshed\", \"snowshoe\", \"snowslide\", \"snowslip\", \"snowstorm\", \"snowsuit\", \"snowswept\",\n \"snowwhite\", \"snowy\", \"snr\", \"snub\", \"snubber\", \"snubbingly\", \"snubby\", \"snuck\", \"snuff\", \"snuffbox\", \"snuffcolored\", \"snuffcoloured\",\n \"snuffer\", \"snuffers\", \"snuffle\", \"snuffless\", \"snuffling\", \"snuffy\", \"snug\", \"snuggery\", \"snuggies\", \"snuggish\", \"snuggle\", \"snugly\",\n \"snurfing\", \"snuzzle\", \"snye\", \"soak\", \"soakage\", \"soaked\", \"soaker\", \"soapbark\", \"soapberry\", \"soapbox\", \"soapboxer\", \"soaper\",\n \"soapery\", \"soapie\", \"soapmaking\", \"soapolallie\", \"soaprock\", \"soapstone\", \"soapsuds\", \"soapwort\", \"soapy\", \"soar\", \"soarable\", \"soaraway\",\n \"soaring\", \"soave\", \"soavemente\", \"sob\", \"sobbing\", \"sobby\", \"sobeit\", \"sober\", \"soberano\", \"sobering\", \"soberize\", \"soberly\",\n \"soberminded\", \"sobersides\", \"sobranje\", \"sobriety\", \"sobriquet\", \"socage\", \"soccage\", \"soccer\", \"sochi\", \"sociability\", \"sociable\", \"sociably\",\n \"social\", \"socialise\", \"socialism\", \"socialist\", \"socialistic\", \"socialistically\", \"socialite\", \"sociality\", \"socialization\", \"socialize\", \"socializee\", \"socially\",\n \"societal\", \"society\", \"socinian\", \"socinianism\", \"sociobiology\", \"sociocentric\", \"sociocentrism\", \"sociocracy\", \"sociocultural\", \"socioecology\", \"socioeconomic\", \"sociogenetic\",\n \"sociogenic\", \"sociogenous\", \"sociogeny\", \"sociogram\", \"sociogroup\", \"sociolect\", \"sociolinguistics\", \"sociologese\", \"sociological\", \"sociologically\", \"sociologise\", \"sociologism\",\n \"sociologist\", \"sociologize\", \"sociology\", \"sociometry\", \"sociopath\", \"sociopathic\", \"sociopolitical\", \"socioreligious\", \"sociosexual\", \"sociotechnological\", \"socius\", \"sock\",\n \"sockdolager\", \"socker\", \"sockeroo\", \"socket\", \"sockeye\", \"socko\", \"socle\", \"socman\", \"socotra\", \"socratic\", \"socratism\", \"socred\",\n \"sod\", \"soda\", \"sodalist\", \"sodalite\", \"sodality\", \"sodamide\", \"sodar\", \"sodden\", \"soddish\", \"soddy\", \"sodic\", \"sodium\",\n \"sodom\", \"sodomist\", \"sodomite\", \"sodomize\", \"sodomy\", \"sodwork\", \"soed\", \"soekarno\", \"soemba\", \"soembawa\", \"soerabaja\", \"soerakarta\",\n \"soever\", \"sof\", \"sofa\", \"sofar\", \"soffit\", \"sofia\", \"soft\", \"softback\", \"softball\", \"softbank\", \"softboard\", \"softbound\",\n \"soften\", \"softening\", \"softgoods\", \"softhead\", \"softheaded\", \"softhearted\", \"softish\", \"softland\", \"softly\", \"softness\", \"softpanel\", \"softwood\",\n \"softy\", \"sogat\", \"soggy\", \"soho\", \"soigne\", \"soignee\", \"soil\", \"soilage\", \"soilborne\", \"soilless\", \"soily\", \"soiree\",\n \"soja\", \"sojourn\", \"sojourner\", \"soke\", \"sokeman\", \"sokol\", \"sokotra\", \"sol\", \"solace\", \"solaceful\", \"solacet\", \"solan\",\n \"solanaceous\", \"solander\", \"solanine\", \"solano\", \"solanum\", \"solar\", \"solaria\", \"solarimeter\", \"solaris\", \"solarise\", \"solarism\", \"solarium\",\n \"solarization\", \"solarize\", \"solarometer\", \"solate\", \"solatia\", \"solatium\", \"sold\", \"soldan\", \"soldanella\", \"solder\", \"solderability\", \"solderable\",\n \"soldi\", \"soldier\", \"soldierlike\", \"soldierly\", \"soldiership\", \"soldiery\", \"soldo\", \"sole\", \"solebar\", \"solecism\", \"solecist\", \"solecistic\",\n \"solecize\", \"soleiform\", \"solely\", \"solemn\", \"solemnify\", \"solemnise\", \"solemnity\", \"solemnization\", \"solemnize\", \"solemnly\", \"solemnness\", \"solen\",\n \"solenocyte\", \"solenodon\", \"solenoglyph\", \"solenoid\", \"soleplate\", \"soleprint\", \"soleus\", \"solfatara\", \"solfege\", \"solfeggio\", \"solgel\", \"soli\",\n \"solicit\", \"solicitant\", \"solicitation\", \"solicitor\", \"solicitorship\", \"solicitous\", \"solicitously\", \"solicitude\", \"solicitudinous\", \"solid\", \"solidago\", \"solidaric\",\n \"solidarist\", \"solidarity\", \"solidarize\", \"solidary\", \"solidi\", \"solidification\", \"solidify\", \"solidity\", \"solidly\", \"solidness\", \"solidungulate\", \"solidus\",\n \"solifidian\", \"solifidianism\", \"soliflucted\", \"solifluction\", \"solifluxion\", \"soligenous\", \"soliloquise\", \"soliloquist\", \"soliloquize\", \"soliloquy\", \"solingen\", \"solion\",\n \"soliped\", \"solipsism\", \"solitaire\", \"solitarily\", \"solitary\", \"solitude\", \"solitudinarian\", \"soljanka\", \"solleret\", \"sollicker\", \"solmisation\", \"solmizate\",\n \"solmization\", \"soln\", \"solo\", \"solodize\", \"soloist\", \"soloistic\", \"solon\", \"solonchak\", \"solonetz\", \"solstice\", \"solstitial\", \"solubilisation\",\n \"solubilise\", \"solubility\", \"solubilization\", \"solubilize\", \"solubilizer\", \"soluble\", \"solunar\", \"solus\", \"solute\", \"solutionist\", \"solutizer\", \"solutrean\",\n \"solvability\", \"solvable\", \"solvate\", \"solve\", \"solvency\", \"solvend\", \"solvent\", \"solvolysis\", \"solyanka\", \"soma\", \"somal\", \"somali\",\n \"somaliland\", \"somaplasm\", \"somascope\", \"somasteroid\", \"somatic\", \"somatization\", \"somatocoel\", \"somatogamy\", \"somatogenetic\", \"somatogenic\", \"somatological\", \"somatology\",\n \"somatomedin\", \"somatoplasm\", \"somatopleure\", \"somatopsychic\", \"somatosensory\", \"somatostatin\", \"somatotherapy\", \"somatotonic\", \"somatotopic\", \"somatotopical\", \"somatotroph\", \"somatotrophic\",\n \"somatotrophin\", \"somatotropin\", \"somatotype\", \"somber\", \"somberly\", \"sombre\", \"sombrero\", \"sombrous\", \"some\", \"somebody\", \"someday\", \"somedeal\",\n \"somehow\", \"someone\", \"someplace\", \"somersault\", \"somerset\", \"somersetshire\", \"somerville\", \"somesthetic\", \"somesuch\", \"something\", \"sometime\", \"sometimes\",\n \"sometimey\", \"someway\", \"someways\", \"somewhat\", \"somewhere\", \"somewhile\", \"somewhither\", \"somewhy\", \"somewise\", \"somite\", \"sommelier\", \"somnambulance\",\n \"somnambulant\", \"somnambular\", \"somnambulary\", \"somnambulate\", \"somnambule\", \"somnambulic\", \"somnambulism\", \"somnambulist\", \"somnial\", \"somnifacient\", \"somniferous\", \"somnific\",\n \"somniloquence\", \"somniloquism\", \"somniloquist\", \"somniloquous\", \"somniloquy\", \"somnivolency\", \"somnolence\", \"somnolency\", \"somnolent\", \"somnus\", \"sompa\", \"son\",\n \"sonable\", \"sonagram\", \"sonagraph\", \"sonal\", \"sonance\", \"sonant\", \"sonantize\", \"sonar\", \"sonarman\", \"sonata\", \"sonatina\", \"sonation\",\n \"sondage\", \"sonderclass\", \"sonderkommando\", \"sone\", \"sonet\", \"song\", \"songbird\", \"songbook\", \"songcraft\", \"songfest\", \"songful\", \"songkhla\",\n \"songkok\", \"songless\", \"songlet\", \"songlike\", \"songman\", \"songsmith\", \"songster\", \"songstress\", \"sonic\", \"sonicate\", \"sonication\", \"sonicguide\",\n \"sonifer\", \"soniferous\", \"sonifier\", \"sonless\", \"sonlike\", \"sonly\", \"sonnet\", \"sonneteer\", \"sonnetist\", \"sonnetize\", \"sonny\", \"sonobuoy\",\n \"sonochemical\", \"sonochemistry\", \"sonofabitch\", \"sonofer\", \"sonograph\", \"sonography\", \"sonoluminescence\", \"sonolyse\", \"sonolysis\", \"sonolyze\", \"sonometer\", \"sonorant\",\n \"sonorific\", \"sonority\", \"sonorization\", \"sonorize\", \"sonorous\", \"sonorously\", \"sonorousness\", \"sonovox\", \"sonship\", \"sonsie\", \"sonsy\", \"sonuvabitch\",\n \"sony\", \"sonya\", \"soochong\", \"soochow\", \"soodling\", \"sooey\", \"soogan\", \"soogee\", \"sook\", \"sool\", \"soon\", \"soot\",\n \"sootfall\", \"sooth\", \"soothe\", \"soother\", \"soothing\", \"soothingly\", \"soothly\", \"soothsay\", \"soothsayer\", \"soothsaying\", \"sootily\", \"sootiness\",\n \"sootlike\", \"sooty\", \"sop\", \"sopaipilla\", \"sopapilla\", \"soper\", \"soph\", \"sophi\", \"sophic\", \"sophism\", \"sophist\", \"sophister\",\n \"sophistic\", \"sophistical\", \"sophisticate\", \"sophisticated\", \"sophistication\", \"sophisticator\", \"sophistry\", \"sophoclean\", \"sophomore\", \"sophomoric\", \"sophomorical\", \"sophonias\",\n \"sopite\", \"sopor\", \"soporiferous\", \"soporific\", \"soporose\", \"soporous\", \"sopot\", \"sopped\", \"sopping\", \"soppy\", \"soprani\", \"sopranino\",\n \"sopranist\", \"soprano\", \"soqotra\", \"sora\", \"sorb\", \"sorbefacient\", \"sorbent\", \"sorbian\", \"sorbitol\", \"sorbo\", \"sorbol\", \"sorbonne\",\n \"sorbonnist\", \"sorbose\", \"sorcerer\", \"sorceress\", \"sorcerize\", \"sorcery\", \"sordamente\", \"sordid\", \"sordidly\", \"sore\", \"soredial\", \"soredium\",\n \"sorefalcon\", \"sorehawk\", \"sorehead\", \"sorel\", \"sorely\", \"soreness\", \"sorgho\", \"sorghum\", \"sorgo\", \"sori\", \"sorites\", \"sorn\",\n \"soroban\", \"soroptimist\", \"sororal\", \"sororate\", \"sororial\", \"sororicide\", \"sorority\", \"sororize\", \"sorosilicate\", \"sorosis\", \"sorption\", \"sorrel\",\n \"sorrily\", \"sorriness\", \"sorrow\", \"sorrowful\", \"sorrowfully\", \"sorry\", \"sort\", \"sorta\", \"sortable\", \"sortation\", \"sorter\", \"sortes\",\n \"sortie\", \"sortilege\", \"sortita\", \"sortition\", \"sorus\", \"sos\", \"sostenuto\", \"sot\", \"soterial\", \"soteriology\", \"sothiac\", \"sothiacal\",\n \"sothic\", \"sothis\", \"sotol\", \"sots\", \"sotted\", \"sottish\", \"sou\", \"souari\", \"soubise\", \"soubresaut\", \"soubrette\", \"soubriquet\",\n \"soucar\", \"souchong\", \"soudan\", \"soudanese\", \"souffle\", \"sough\", \"sought\", \"soul\", \"soulful\", \"soulless\", \"sound\", \"soundboard\",\n \"sounder\", \"soundex\", \"soundful\", \"sounding\", \"soundless\", \"soundlessly\", \"soundly\", \"soundness\", \"soundproof\", \"soundrec\", \"soundscape\", \"soundscriber\",\n \"soupcon\", \"soupfin\", \"soupiness\", \"soupy\", \"sour\", \"sourball\", \"sourcebook\", \"sourcrout\", \"sourdine\", \"sourdough\", \"sourish\", \"sourkrout\",\n \"sourly\", \"sourness\", \"sourpuss\", \"soursop\", \"sousaphone\", \"souse\", \"souslik\", \"sousse\", \"soutache\", \"soutane\", \"soutar\", \"souteneur\",\n \"souter\", \"souterrain\", \"south\", \"southabout\", \"southampton\", \"southbound\", \"southdown\", \"southeast\", \"southeaster\", \"southeasterly\", \"southeastern\", \"southeasternmost\",\n \"southeastward\", \"southeastwards\", \"souther\", \"southerly\", \"southern\", \"southerner\", \"southernization\", \"southernly\", \"southernmost\", \"southernwood\", \"southing\", \"southland\",\n \"southmost\", \"southpaw\", \"southron\", \"southward\", \"southwardly\", \"southwards\", \"southwest\", \"southwester\", \"southwesterly\", \"southwestern\", \"southwesternmost\", \"southwestward\",\n \"southwestwards\", \"southwide\", \"souvenir\", \"souvlaki\", \"souwester\", \"souzalite\", \"sov\", \"sovereign\", \"sovereignty\", \"soviet\", \"sovietise\", \"sovietism\",\n \"sovietist\", \"sovietization\", \"sovietize\", \"sovietologist\", \"sovietology\", \"sovkhoz\", \"sovnarkhoz\", \"sovprene\", \"sovran\", \"sovranty\", \"sow\", \"sowback\",\n \"sowbelly\", \"sowbread\", \"sowbug\", \"sowcar\", \"sowens\", \"sower\", \"soweto\", \"sown\", \"sowntown\", \"soy\", \"soya\", \"soyaburger\",\n \"soybean\", \"soymilk\", \"sozin\", \"sozzled\", \"spa\", \"space\", \"spacearium\", \"spaceband\", \"spacebar\", \"spacecraft\", \"spacefarer\", \"spaceflight\",\n \"spaceless\", \"spacelift\", \"spaceman\", \"spacemark\", \"spaceplane\", \"spaceport\", \"spacer\", \"spaceship\", \"spacesickness\", \"spacewalk\", \"spaceward\", \"spaceway\",\n \"spacewoman\", \"spaceworthy\", \"spacial\", \"spacing\", \"spacious\", \"spaciously\", \"spacistor\", \"spackle\", \"spadable\", \"spade\", \"spadebone\", \"spadefoot\",\n \"spadeful\", \"spadework\", \"spadger\", \"spadices\", \"spadicose\", \"spadille\", \"spadish\", \"spadix\", \"spado\", \"spae\", \"spaeman\", \"spaetzle\",\n \"spaewife\", \"spag\", \"spaggers\", \"spaghetti\", \"spaghettini\", \"spagyric\", \"spahee\", \"spahi\", \"spain\", \"spaish\", \"spait\", \"spake\",\n \"spalato\", \"spall\", \"spallation\", \"spalpeen\", \"span\", \"spanaemia\", \"spancel\", \"spandrel\", \"spandril\", \"spandy\", \"spang\", \"spangle\",\n \"spanglish\", \"spaniard\", \"spaniel\", \"spanish\", \"spank\", \"spanker\", \"spanking\", \"spanless\", \"spanned\", \"spanner\", \"spanning\", \"spanrail\",\n \"spanwise\", \"spanworm\", \"spar\", \"sparable\", \"sparaxis\", \"spare\", \"sparely\", \"spareness\", \"sparerib\", \"sparganosis\", \"sparganum\", \"sparge\",\n \"sparid\", \"sparing\", \"sparingly\", \"spark\", \"sparkish\", \"sparkle\", \"sparkler\", \"sparkless\", \"sparklet\", \"sparkling\", \"sparklingly\", \"sparkplug\",\n \"sparkproof\", \"sparmate\", \"sparrow\", \"sparrowgrass\", \"sparry\", \"sparse\", \"sparsely\", \"sparseness\", \"sparsity\", \"sparta\", \"spartacist\", \"spartacus\",\n \"spartan\", \"spartanism\", \"spartanize\", \"sparteine\", \"spasm\", \"spasmic\", \"spasmodic\", \"spasmodical\", \"spasmodically\", \"spasmodism\", \"spasmodist\", \"spasmogen\",\n \"spasmogenic\", \"spasmolysis\", \"spasmolytic\", \"spasmophilia\", \"spastic\", \"spat\", \"spatchcock\", \"spate\", \"spathal\", \"spathe\", \"spathic\", \"spathiform\",\n \"spathulate\", \"spatial\", \"spatiality\", \"spatiography\", \"spatioperceptual\", \"spatiotemporal\", \"spatted\", \"spatter\", \"spatterdash\", \"spatterdock\", \"spatterware\", \"spatula\",\n \"spatulate\", \"spatuliform\", \"spatzle\", \"spavin\", \"spavined\", \"spawn\", \"spawny\", \"spay\", \"spaz\", \"spc\", \"spca\", \"spcc\",\n];\n\n// ---------------------------------------------------------------------------\n// Small faithful primitives\n// ---------------------------------------------------------------------------\n\n/** Python `str.capitalize`: uppercase first char, lowercase the rest. */\nexport function capitalize(value: string): string {\n return value.length === 0 ? value : value[0]!.toUpperCase() + value.slice(1).toLowerCase();\n}\n\n/** Python `str.islower` on a single character. */\nfunction isLowerChar(char: string): boolean {\n return char >= 'a' && char <= 'z';\n}\n\n/** `re.sub('[A-Z]', lambda x: '_' + x.group(0), name).split('_')`. */\nexport function splitCamel(name: string): string[] {\n return name.replace(/[A-Z]/g, ch => `_${ch}`).split('_');\n}\n\n/** Random string of the given length over the 52-letter alphabet. */\nexport function randomString(length: number, rng: Rng): string {\n let out = '';\n for (let index = 0; index < length; index += 1) {\n out += UPPER_AND_LOWER[Math.floor(rng() * UPPER_AND_LOWER.length)]!;\n }\n return out;\n}\n\n/** True when the value contains at least one digit. */\nexport function isNumberString(value: string): boolean {\n return /[0-9]/.test(value);\n}\n\n/** True when the value contains any ASCII punctuation except '_'. */\nexport function hasSpecialString(value: string): boolean {\n for (const char of value) if (PUNCTUATION_EXCEPT_UNDERSCORE.has(char)) return true;\n return false;\n}\n\n/** UTF-8 md5 hex digest (node:crypto createHash). */\nexport function md5Hex(value: string): string {\n return createHash('md5').update(value, 'utf8').digest('hex');\n}\n\n/** MD5 of the first 8096 bytes of a file. */\nexport function getFileMd5Value(buffer: Buffer): string {\n return createHash('md5').update(buffer.subarray(0, 8096)).digest('hex');\n}\n\n/** Draw a cleaned word from the lexicon pool. */\nexport function lexiconWord(rng: Rng): string {\n const index = Math.min(LEXICON.length - 1, Math.floor(rng() * LEXICON.length));\n let word = LEXICON[index] ?? '';\n if (word === 'virtual') word = 'virtualObj';\n return word === '' ? 'word' : word;\n}\n\nfunction randomInt(rng: Rng, min: number, max: number): number {\n return min + Math.floor(rng() * (max - min + 1));\n}\n\n/** Whole-word swap of one identifier using `\\b\\w+\\b` (matching the original `re.sub`). */\nfunction replaceWord(text: string, name: string, obscured: string): string {\n if (!name) return text;\n return text.replace(new RegExp(`\\\\b${escapeRegExp(name)}\\\\b`, 'g'), () => obscured);\n}\n\n// ---------------------------------------------------------------------------\n// Naming rules (my-rule)\n// ---------------------------------------------------------------------------\n\n/** Generate an obscured class name via the my-rule algorithm. */\nexport function obscureClassNameByMyRule(name: string, _prefixWord: string, rng: Rng): string {\n let parts = splitCamel(name);\n const firstKeyWord = capitalize(lexiconWord(rng));\n let lastKeyWord: string;\n if (parts.length > 0 && parts[0]!.length === 0) {\n while (parts.length > 0 && parts[0]!.length === 0) parts = parts.slice(1);\n }\n if (parts.length > 0) {\n lastKeyWord = capitalize(parts[parts.length - 1]!);\n } else {\n lastKeyWord = capitalize(lexiconWord(rng));\n }\n const add: string[] = [firstKeyWord];\n let addCount = parts.length - 2;\n if (addCount <= 0) addCount = 1;\n for (let index = 0; index < addCount + randomInt(rng, 0, 1); index += 1) {\n add.push(capitalize(lexiconWord(rng)));\n }\n add.push(lastKeyWord);\n let result = add.join('');\n if (name.startsWith('_')) result = `_${result}`;\n return result;\n}\n\n/** Generate an obscured method name via the my-rule algorithm (dead branch omitted). */\nexport function obscureMethodNameByMyRule(name: string, prefixWord: string, rng: Rng): string {\n const parts = splitCamel(name);\n let firstKeyWord = lexiconWord(rng);\n if (prefixWord.length > 0 && !prefixWord.endsWith('_')) {\n firstKeyWord = capitalize(firstKeyWord);\n } else if (name.startsWith('_')) {\n void capitalize(lexiconWord(rng)); // draw consumed but overwritten by the original\n }\n const kept = parts.filter(item => item.length > 2);\n let lastKeyWord: string;\n if (kept.length > 0) {\n lastKeyWord = kept[kept.length - 1]!;\n } else {\n lastKeyWord = capitalize(lexiconWord(rng));\n }\n let result = firstKeyWord + capitalize(lexiconWord(rng)) + capitalize(lastKeyWord);\n if (name.startsWith('_')) result = `_${result}`;\n return result;\n}\n\n/** Generate an obscured variable/constant name via the my-rule algorithm. */\nexport function obscureVariableNameByMyRule(name: string, prefixWord: string, rng: Rng): string {\n const parts = splitCamel(name);\n let firstKeyWord = lexiconWord(rng);\n if (prefixWord.length > 0 && !prefixWord.endsWith('_')) {\n firstKeyWord = capitalize(firstKeyWord);\n } else if (name.startsWith('_')) {\n void capitalize(lexiconWord(rng)); // draw consumed but overwritten by the original\n }\n let lastKeyWord: string;\n if (parts.length > 0) {\n lastKeyWord = capitalize(parts[parts.length - 1]!);\n } else {\n lastKeyWord = capitalize(lexiconWord(rng));\n }\n let result = firstKeyWord + lastKeyWord;\n if (name.startsWith('_')) result = `_${result}`;\n return result;\n}\n\n/** Generate an obscured resource name via the my-rule algorithm. */\nexport function obscureResourceNameByMyRule(name: string, _prefixWord: string, rng: Rng): string {\n let parts = splitCamel(name);\n const firstKeyWord = lexiconWord(rng);\n let lastKeyWord: string;\n if (parts.length > 0 && parts[0]!.length === 0) {\n while (parts.length > 0 && parts[0]!.length === 0) parts = parts.slice(1);\n }\n if (parts.length > 0) {\n lastKeyWord = capitalize(parts[parts.length - 1]!);\n } else {\n lastKeyWord = capitalize(lexiconWord(rng));\n }\n const add: string[] = [firstKeyWord];\n let addCount = parts.length - 2;\n if (addCount <= 0) addCount = 1;\n for (let index = 0; index < addCount; index += 1) add.push(capitalize(lexiconWord(rng)));\n add.push(lastKeyWord);\n let result = add.join('');\n if (name.startsWith('_')) result = `_${result}`;\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Full generators (prefix '#', whitelist, algorithm selection, case normalization)\n// ---------------------------------------------------------------------------\n\nfunction prefixHashReturn(prefix: string, name: string): string | undefined {\n if (prefix.endsWith('#')) return (prefix.split('#')[0] ?? '') + name;\n return undefined;\n}\n\nfunction finishGenerated(prefix: string, name: string, obscured: string): string {\n if (prefix.length > 0 && name.includes('_')) {\n if (prefix.endsWith('_') && name.startsWith('_')) return (prefix.split('_')[0] ?? '') + obscured;\n return prefix + obscured;\n }\n const first = obscured[0] ?? '';\n const rest = obscured.slice(1);\n const adjusted = isLowerChar(name[0] ?? '') ? first.toLowerCase() : first.toUpperCase();\n return prefix + adjusted + rest;\n}\n\n/** Generate an obscured class name (whitelist/prefix/algorithm selection). */\nexport function generateClassName(name: string, prefixWord: string, rng: Rng, options: NormalizedFlutterOptions): string {\n if (MUST_WHITE_CLASS_SET.has(name) || options.classWhiteList.includes(name)) return name;\n const hashed = prefixHashReturn(prefixWord, name);\n if (hashed !== undefined) return hashed;\n const obscured = options.missAlgorithmType === 3\n ? randomString(name.length * 2, rng)\n : obscureClassNameByMyRule(name, prefixWord, rng);\n return finishGenerated(prefixWord, name, obscured);\n}\n\n/** Generate an obscured method name (whitelist/prefix/algorithm selection). */\nexport function generateMethodName(name: string, prefixWord: string, rng: Rng, options: NormalizedFlutterOptions): string {\n if (IGNORE_METHOD_SET.has(name) || options.methodWhiteList.includes(name)) return name;\n const hashed = prefixHashReturn(prefixWord, name);\n if (hashed !== undefined) return hashed;\n const obscured = options.missAlgorithmType === 3\n ? randomString(name.length * 2, rng)\n : obscureMethodNameByMyRule(name, prefixWord, rng);\n return finishGenerated(prefixWord, name, obscured);\n}\n\n/** Generate an obscured variable/constant name (whitelist/prefix/algorithm selection). */\nexport function generateVariableName(name: string, prefixWord: string, rng: Rng, options: NormalizedFlutterOptions): string {\n if (IGNORE_VARIABLE_SET.has(name) || options.variableWhiteList.includes(name)) return name;\n const hashed = prefixHashReturn(prefixWord, name);\n if (hashed !== undefined) return hashed;\n const obscured = options.missAlgorithmType === 3\n ? randomString(name.length * 2, rng)\n : obscureVariableNameByMyRule(name, prefixWord, rng);\n return finishGenerated(prefixWord, name, obscured);\n}\n\n/** Generate an obscured resource name (prefix/algorithm selection). */\nexport function generateResourceName(name: string, prefixWord: string, rng: Rng, options: NormalizedFlutterOptions): string {\n const hashed = prefixHashReturn(prefixWord, name);\n if (hashed !== undefined) return hashed;\n const obscured = options.missAlgorithmType === 3\n ? randomString(name.length * 2, rng)\n : obscureResourceNameByMyRule(name, prefixWord, rng);\n return finishGenerated(prefixWord, name, obscured);\n}\n\n// ---------------------------------------------------------------------------\n// Dart line analysis (declaration detection)\n// ---------------------------------------------------------------------------\n\nexport interface DartClassMatch { name: string }\nexport interface DartMethodMatch { name: string }\nexport type DartVariableMatch = { kind: 'constructor'; names: string[] } | { kind: 'declaration'; name: string };\n\n/** Class declaration analysis: a `class ` line returns the second token. */\nexport function analyzeDartClassLine(line: string): DartClassMatch | undefined {\n if (!line.startsWith('class ')) return undefined;\n const tokens = line.split(/\\s+/).filter(Boolean);\n const name = tokens[1];\n return name ? { name } : undefined;\n}\n\n/** Method declaration analysis: a return-typed method declaration line. */\nexport function analyzeDartMethodLine(line: string): DartMethodMatch | undefined {\n const tokens = line.trim().split(/\\s+/).filter(Boolean);\n if (tokens.length <= 1) return undefined;\n const returnWord = tokens[0]!;\n if (!BASIC_DATA_SET.has(returnWord) && !BASIC_CONTROL_SET.has(returnWord)) return undefined;\n if (line.split('(').length - 1 !== 1 || line.split(')').length - 1 !== 1) return undefined;\n if (line.endsWith(';')) return undefined;\n const open = line.indexOf('(');\n if (open < 0) return undefined;\n const methodString = line.slice(2, open);\n const methodTokens = methodString.split(/\\s+/).filter(Boolean);\n const name = methodTokens[methodTokens.length - 1];\n if (!name || hasSpecialString(name)) return undefined;\n if (IGNORE_METHOD_SET.has(name)) return undefined;\n if (name.startsWith('did') && name.endsWith('State')) return undefined;\n return { name };\n}\n\n/** Variable declaration analysis: variable / const-constructor declarations. */\nexport function analyzeDartVariableLine(line: string): DartVariableMatch | undefined {\n if (line.startsWith('//')) return undefined;\n const noSpace = line.trim();\n if (noSpace.length === 0) return undefined;\n\n if (noSpace.startsWith('const ') && noSpace.endsWith(');')) {\n const names = [...noSpace.matchAll(/this\\.(\\w+)/g)].map(match => match[1]!);\n return names.length > 0 ? { kind: 'constructor', names } : undefined;\n }\n\n if (!line.startsWith(' ')) return undefined;\n if (!line.endsWith(';')) return undefined;\n\n const tokens = noSpace.split(/\\s+/).filter(Boolean);\n let name: string | undefined;\n\n const branchA = !line.includes('=') || line.includes('=>') || line.includes('==');\n if (branchA) {\n if (tokens.length < 2 || tokens.length > 3) return undefined;\n const first = tokens[0]!;\n if (!CONSTANT_KEYWORD_SET.has(first) && !BASIC_DATA_SET.has(first) && !BASIC_CONTROL_SET.has(first)) return undefined;\n name = tokens[tokens.length - 1];\n if (name !== undefined && name.includes(';')) name = name.slice(0, name.indexOf(';'));\n if (name !== undefined && (name.includes('({') || name.includes('('))) name = undefined;\n if (name !== undefined && (name.includes('})') || name.includes(')'))) name = undefined;\n } else {\n if (!line.includes('=')) return undefined;\n const eq = line.indexOf('=');\n if (line[eq - 1] !== ' ' || line[eq + 1] !== ' ') return undefined;\n const lhs = noSpace.split('=')[0]!.trim();\n const lhsTokens = lhs.split(/\\s+/).filter(Boolean);\n if (lhsTokens.length <= 1) return undefined;\n name = lhsTokens[lhsTokens.length - 1];\n }\n\n if (!name) return undefined;\n return { kind: 'declaration', name };\n}\n\n// ---------------------------------------------------------------------------\n// Whole-word line replacement (with the original string-literal protections)\n// ---------------------------------------------------------------------------\n\n/** Replace a class name on a line: plain `\\b\\w+\\b` swap. */\nexport function replaceClassNameInLine(line: string, name: string, obscured: string): string {\n return replaceWord(line, name, obscured);\n}\n\n/** Replace a method name on a line, protecting `\"name\"` string literals. */\nexport function replaceMethodNameInLine(line: string, name: string, obscured: string): string {\n const mark = '$Z-F-J$';\n let work = line;\n if (work.includes(`\"${name}\"`)) work = work.split(`\"${name}\"`).join(mark);\n let result = replaceWord(work, name, obscured);\n if (result.includes(mark)) result = result.split(mark).join(`\"${name}\"`);\n return result;\n}\n\n/** Replace a variable/constant name on a line, protecting string/literal/call/regex forms. */\nexport function replaceVariableNameInLine(line: string, name: string, obscured: string): string {\n if (line.startsWith('import')) return line;\n const mark = '$Z-F-J$';\n const single = `'${name}'`;\n const call = `${name}(`;\n const slash = `/${name}/`;\n let work = line;\n const hadDouble = work.includes(`\"${name}\"`);\n const hadSingle = work.includes(single);\n const hadCall = work.includes(call);\n const hadSlash = work.includes(slash);\n if (hadDouble) work = work.split(`\"${name}\"`).join(mark);\n if (hadSingle) work = work.split(single).join(md5Hex(single));\n if (hadCall) work = work.split(call).join(md5Hex(call));\n if (hadSlash) work = work.split(slash).join(md5Hex(slash));\n let result = replaceWord(work, name, obscured);\n if (result.includes(mark)) result = result.split(mark).join(`\"${name}\"`);\n if (hadSingle) result = result.split(md5Hex(single)).join(single);\n if (hadCall) result = result.split(md5Hex(call)).join(call);\n if (hadSlash) result = result.split(md5Hex(slash)).join(slash);\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Comment deletion\n// ---------------------------------------------------------------------------\n\nexport interface DeleteNotesLineResult { text: string | null; inBlock: boolean }\n\n/** Delete Dart comments from a single line (trailing newline already removed). */\nexport function deleteNotesInLine(line: string, inBlock: boolean): DeleteNotesLineResult {\n let noNotes: string | null = null;\n const stripped = line.trim();\n if (stripped.includes('//')) {\n const ds = line.indexOf('//');\n if (line.includes('\"') && (line.split('\"').length - 1) === 2) {\n const start = line.indexOf('\"');\n const end = line.indexOf('\"', start + 1);\n noNotes = ds > end ? line.slice(0, ds) : line;\n } else if (line.includes(\"'\") && (line.split(\"'\").length - 1) === 2) {\n const start = line.indexOf(\"'\");\n const end = line.indexOf(\"'\", start + 1);\n noNotes = ds > end ? line.slice(0, ds) : line;\n } else {\n noNotes = line.slice(0, ds);\n }\n } else if (stripped.includes('/*') && !stripped.includes('*/')) {\n noNotes = line.slice(0, line.indexOf('/*'));\n inBlock = true;\n } else if (!stripped.includes('/*') && stripped.includes('*/')) {\n noNotes = line.slice(line.indexOf('*/') + 2);\n inBlock = false;\n } else if (stripped.includes('/*') && stripped.includes('*/')) {\n const start = line.indexOf('/*');\n const end = line.indexOf('*/') + 2;\n const mark = line.slice(start, end);\n noNotes = line.split(mark).join('');\n } else if (inBlock && !stripped.includes('/*') && !stripped.includes('*/')) {\n noNotes = null;\n } else {\n noNotes = line;\n }\n\n if (noNotes !== null) {\n if (noNotes.replace(/ /g, '') === '') return { text: null, inBlock };\n return { text: noNotes, inBlock };\n }\n return { text: null, inBlock };\n}\n\n/** Python file-iteration semantics: each yielded line plus whether it carried a trailing newline. */\nfunction pythonLines(source: string): Array<{ text: string; hasNewline: boolean }> {\n if (source === '') return [];\n const parts = source.split('\\n');\n const result: Array<{ text: string; hasNewline: boolean }> = [];\n for (let index = 0; index < parts.length; index += 1) {\n result.push({ text: parts[index]!, hasNewline: index < parts.length - 1 });\n }\n if (result[result.length - 1]!.text === '' && !result[result.length - 1]!.hasNewline) result.pop();\n return result;\n}\n\n/** Delete Dart comments from a whole source file. */\nexport function deleteDartComments(source: string): string {\n const out: string[] = [];\n let inBlock = false;\n for (const { text, hasNewline } of pythonLines(source)) {\n const result = deleteNotesInLine(text, inBlock);\n inBlock = result.inBlock;\n if (result.text !== null && result.text.length > 0) out.push(result.text + (hasNewline ? '\\n' : ''));\n }\n return out.join('');\n}\n\n// ---------------------------------------------------------------------------\n// Resource names and references\n// ---------------------------------------------------------------------------\n\nconst FLUTTER_IMAGE_EXTENSIONS = new Set(['jpg', 'jpeg', 'png', 'webp', 'gif']);\nconst FLUTTER_AUDIO_EXTENSIONS = new Set(['pcm', 'wav', 'mp3', 'amr', 'aac', 'caf']);\nconst FLUTTER_VIDEO_EXTENSIONS = new Set(['mp4', 'mkv', 'avi', 'wmv', 'iso', 'rmvb']);\n\nfunction fileExtension(relative: string): string {\n const base = relative.slice(relative.lastIndexOf('/') + 1);\n const dot = base.lastIndexOf('.');\n return dot < 1 ? '' : base.slice(dot + 1).toLowerCase();\n}\n\nfunction basename(relative: string): string {\n return relative.slice(relative.lastIndexOf('/') + 1);\n}\n\n/** True for image files (extension paths only). */\nexport function isFlutterImage(relative: string): boolean {\n return FLUTTER_IMAGE_EXTENSIONS.has(fileExtension(relative));\n}\n\n/** True for audio files (by extension). */\nexport function isFlutterAudio(relative: string): boolean {\n return FLUTTER_AUDIO_EXTENSIONS.has(fileExtension(relative));\n}\n\n/** True for video files (by extension). */\nexport function isFlutterVideo(relative: string): boolean {\n return FLUTTER_VIDEO_EXTENSIONS.has(fileExtension(relative));\n}\n\nconst IGNORE_IMAGE_PATHS = ['/build/', '/ios/Runner/', '/.', '/android/app/'];\n\n/** True for image paths that should be ignored. */\nexport function isIgnoreImgPath(relative: string): boolean {\n return IGNORE_IMAGE_PATHS.some(item => relative.includes(item));\n}\n\nconst MUST_IGNORE_PATHS = ['/.git/', '/Pods/', '/README.md', '/Podfile.lock', '.json', '/.DS_Store', '/.svn/'];\n\n/** True for project-relative paths that must be ignored. */\nexport function mustIgnorePath(relative: string): boolean {\n const withSlash = `/${relative}`;\n return MUST_IGNORE_PATHS.some(item => withSlash.includes(item) || relative.includes(item));\n}\n\nconst DART_RESOURCE_PATTERNS = (name: string): string[] => [\n `/${name}.`,\n `'${name}.`,\n `\"${name}.`,\n ` ${name}.`,\n `'${name}.',`,\n `\"${name}.\",`,\n];\n\nconst YAML_RESOURCE_PATTERNS = (name: string): string[] => [`/${name}.`, `-${name}.`, ` ${name}.`];\n\n/** Rewrite resource references in a Dart source file. */\nexport function rewriteDartResourceReferences(source: string, map: ReadonlyMap<string, string>): string {\n return source.split('\\n').map(line => {\n let result = line;\n for (const [name, obscured] of map) {\n for (const pattern of DART_RESOURCE_PATTERNS(name)) {\n if (result.includes(pattern)) {\n result = result.split(pattern).join(pattern.replace(name, obscured));\n break;\n }\n }\n }\n return result;\n }).join('\\n');\n}\n\n/** Rewrite resource references in a YAML file. */\nexport function rewriteYamlResourceReferences(source: string, map: ReadonlyMap<string, string>): string {\n return source.split('\\n').map(line => {\n let result = line;\n for (const [name, obscured] of map) {\n for (const pattern of YAML_RESOURCE_PATTERNS(name)) {\n if (result.includes(pattern)) {\n result = result.split(pattern).join(pattern.replace(name, obscured));\n break;\n }\n }\n }\n return result;\n }).join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Resource hash perturbation\n// ---------------------------------------------------------------------------\n\nconst HASH_PAD_CHARS = '#&';\n\n/** First hash-pad character: always '#'. */\nexport function firstRandomCode(): string {\n return '#';\n}\n\n/** Hash-pad string: '#' + (length + 1) chars from '#&'. */\nexport function randomCodeString(length: number, rng: Rng): string {\n let final = HASH_PAD_CHARS[Math.floor(rng() * 2)]!;\n for (let index = 0; index < length; index += 1) final += HASH_PAD_CHARS[Math.floor(rng() * 2)]!;\n return firstRandomCode() + final;\n}\n\n/** Deterministic `#&` suffix appended to a resource payload to change its md5. */\nexport function perturbResourceHash(buffer: Buffer, seed: string, salt: string): Buffer {\n const rng = seededRandom(deriveHash(seed, 'flutter-resource-hash', salt));\n return Buffer.concat([buffer, Buffer.from(randomCodeString(4, rng), 'latin1')]);\n}\n\n// ---------------------------------------------------------------------------\n// project.pbxproj UUID remapping\n// ---------------------------------------------------------------------------\n\n/** True for a 24-char uppercase Xcode UUID with no `/* =\"._{}`. */\nexport function isXcodeUuid(token: string): boolean {\n if (token.length !== 24) return false;\n if (!/[A-Z]/.test(token) || token !== token.toUpperCase()) return false;\n return !/[\\/\\* =\"._{}]/.test(token);\n}\n\n/** Remap project.pbxproj UUIDs, pure over a source string. */\nexport function remapPbxprojUuids(source: string, seed: string): string {\n const map = new Map<string, string>();\n for (const line of source.split('\\n')) {\n let token = line.replace(/\\s+/g, '');\n if (token.length >= 24) token = token.slice(0, 24);\n if (isXcodeUuid(token) && !map.has(token)) map.set(token, deriveUuid(seed, token));\n }\n if (map.size === 0) return source;\n let result = source;\n for (const [oldUuid, newUuid] of map) result = result.split(oldUuid).join(newUuid);\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Internal orchestration helpers\n// ---------------------------------------------------------------------------\n\nfunction dartFiles(files: WalkEntry[]): WalkEntry[] {\n return files.filter(entry => entry.relative.endsWith('.dart') && !mustIgnorePath(entry.relative));\n}\n\nfunction splitLines(source: string): string[] {\n return source.split('\\n');\n}\n\n/**\n * Discovery + whole-word rewrite for one symbol kind over all dart files. Mirrors the\n * original `save_*_name` collision handling: generate once, and regenerate exactly once\n * when the result was already used; ignored/whitelisted names return unchanged and do not\n * advance the random stream.\n */\nfunction runSymbolPass(\n files: WalkEntry[],\n rng: Rng,\n analyze: (line: string) => string[],\n generate: (name: string, rng: Rng) => string,\n rewrite: (line: string, map: Map<string, string>) => string,\n changedPaths: Set<string>,\n): number {\n const entries = dartFiles(files);\n const map = new Map<string, string>();\n const used: string[] = [];\n\n for (const entry of entries) {\n const source = readFileSync(entry.absolute, 'utf8');\n for (const line of splitLines(source)) {\n for (const name of analyze(line)) {\n if (map.has(name)) continue;\n let obscured = generate(name, rng);\n if (obscured === name) continue;\n if (used.includes(obscured)) obscured = generate(name, rng);\n used.push(obscured);\n map.set(name, obscured);\n }\n }\n }\n\n if (map.size === 0) return 0;\n let changed = 0;\n for (const entry of entries) {\n const before = readFileSync(entry.absolute, 'utf8');\n const after = splitLines(before).map(line => rewrite(line, map)).join('\\n');\n if (after !== before && writeIfChanged(entry, after)) {\n changed += 1;\n changedPaths.add(entry.relative);\n }\n }\n return changed;\n}\n\n// ---------------------------------------------------------------------------\n// Batch entry point\n// ---------------------------------------------------------------------------\n\n/**\n * In-place Flutter obfuscation over an already-walked project, following the original\n * `flutter_obscure_main` order: variable -> class -> method -> resource hash -> resource\n * name -> delete notes -> uuid. Each symbol pass discovers declarations across all dart\n * files first (deterministically, sorted by relative path) and then rewrites every\n * occurrence using the original whole-word rules.\n */\nexport function renameFlutterSymbols(files: WalkEntry[], options: FlutterOptions, seed: string): TransformOutcome {\n const opts = normalizeFlutterOptions(options);\n const rng = seededRandom(deriveHash(seed, 'flutter'));\n const sorted = [...files].sort((a, b) => (a.relative < b.relative ? -1 : a.relative > b.relative ? 1 : 0));\n const changedPaths = new Set<string>();\n let unsupported = 0;\n\n // variable\n if (opts.features.variable) {\n runSymbolPass(sorted, rng,\n line => {\n const match = analyzeDartVariableLine(line);\n if (!match) return [];\n return match.kind === 'constructor' ? match.names : [match.name];\n },\n (name, r) => generateVariableName(name, opts.prefixWord, r, opts),\n (line, map) => {\n let result = line;\n for (const [name, obscured] of map) result = replaceVariableNameInLine(result, name, obscured);\n return result;\n },\n changedPaths);\n }\n\n // class\n if (opts.features.className) {\n runSymbolPass(sorted, rng,\n line => {\n const match = analyzeDartClassLine(line);\n return match ? [match.name] : [];\n },\n (name, r) => generateClassName(name, opts.prefixWord, r, opts),\n (line, map) => {\n let result = line;\n for (const [name, obscured] of map) result = replaceClassNameInLine(result, name, obscured);\n return result;\n },\n changedPaths);\n }\n\n // method\n if (opts.features.method) {\n runSymbolPass(sorted, rng,\n line => {\n const match = analyzeDartMethodLine(line);\n return match ? [match.name] : [];\n },\n (name, r) => generateMethodName(name, opts.prefixWord, r, opts),\n (line, map) => {\n let result = line;\n for (const [name, obscured] of map) result = replaceMethodNameInLine(result, name, obscured);\n return result;\n },\n changedPaths);\n }\n\n // resource hash (append a deterministic '#&' pad to image/audio/video payloads)\n if (opts.features.resourceHash) {\n for (const entry of sorted) {\n if (!isFlutterImage(entry.relative) && !isFlutterAudio(entry.relative) && !isFlutterVideo(entry.relative)) continue;\n if (mustIgnorePath(entry.relative)) continue;\n const before = readFileSync(entry.absolute);\n const after = perturbResourceHash(before, seed, entry.relative);\n if (after.equals(before)) continue;\n writeFileSync(entry.absolute, after);\n changedPaths.add(entry.relative);\n }\n }\n\n // resource name: discover image stems (non-numeric, not ignored), rewrite dart/yaml references, rename files\n if (opts.features.resourceName) {\n const nameMap = new Map<string, string>();\n const used: string[] = [];\n const renames = new Map<string, string>();\n for (const entry of sorted) {\n if (!isFlutterImage(entry.relative) || isIgnoreImgPath(entry.relative)) continue;\n const base = basename(entry.relative);\n const dot = base.indexOf('.');\n const resourceName = dot < 0 ? base : base.slice(0, dot);\n const resourceType = dot < 0 ? '' : base.slice(base.lastIndexOf('.') + 1);\n if (isNumberString(resourceName)) continue;\n if (!nameMap.has(resourceName)) {\n let obscured = generateResourceName(resourceName, opts.prefixWord, rng, opts);\n if (used.includes(obscured)) obscured = generateResourceName(resourceName, opts.prefixWord, rng, opts);\n used.push(obscured);\n nameMap.set(resourceName, obscured);\n }\n const obscured = nameMap.get(resourceName)!;\n const oldPath = entry.absolute;\n const newPath = oldPath.split(`${resourceName}.${resourceType}`).join(`${obscured}.${resourceType}`);\n if (newPath !== oldPath) renames.set(oldPath, newPath);\n }\n\n // rewrite references first, then move files (original traverses all directories here)\n for (const entry of sorted) {\n if (entry.relative.endsWith('.dart')) {\n if (entry.relative.includes('/.')) continue;\n const before = readFileSync(entry.absolute, 'utf8');\n const after = rewriteDartResourceReferences(before, nameMap);\n if (after !== before && writeIfChanged(entry, after)) changedPaths.add(entry.relative);\n } else if (entry.relative.endsWith('.yaml')) {\n const before = readFileSync(entry.absolute, 'utf8');\n const after = rewriteYamlResourceReferences(before, nameMap);\n if (after !== before && writeIfChanged(entry, after)) changedPaths.add(entry.relative);\n }\n }\n for (const [from, to] of renames) {\n try {\n renameSync(from, to);\n changedPaths.add(to);\n } catch {\n unsupported += 1;\n }\n }\n }\n\n // delete notes\n if (opts.features.deleteNotes) {\n for (const entry of dartFiles(sorted)) {\n const before = readFileSync(entry.absolute, 'utf8');\n const after = deleteDartComments(before);\n if (after !== before && writeIfChanged(entry, after)) changedPaths.add(entry.relative);\n }\n }\n\n // uuid\n if (opts.features.uuid) {\n for (const entry of sorted) {\n if (!entry.relative.endsWith('project.pbxproj')) continue;\n const before = readFileSync(entry.absolute, 'utf8');\n const after = remapPbxprojUuids(before, seed);\n if (after !== before && writeIfChanged(entry, after)) changedPaths.add(entry.relative);\n }\n }\n\n return { changed: changedPaths.size, changedPaths: [...changedPaths].sort(), unsupported };\n}\n"],"mappings":";;;;AAiDA,MAAM,eAA0C;CAC9C,UAAU;CAAM,WAAW;CAAM,QAAQ;CAAM,cAAc;CAC7D,cAAc;CAAM,aAAa;CAAM,MAAM;AAC/C;AAEA,SAAgB,wBAAwB,UAA0B,CAAC,GAA6B;CAC9F,OAAO;EACL,YAAY,QAAQ,cAAc;EAClC,mBAAmB,QAAQ,qBAAqB;EAChD,gBAAgB,QAAQ,kBAAkB,CAAC;EAC3C,iBAAiB,QAAQ,mBAAmB,CAAC;EAC7C,mBAAmB,QAAQ,qBAAqB,CAAC;EACjD,UAAU;GAAE,GAAG;GAAc,GAAI,QAAQ,YAAY,CAAC;EAAG;CAC3D;AACF;AAMA,MAAa,6BAAgD,CAAC,OAAO;AAErE,MAAa,yBAA4C;CACvD;CAAQ;CAAS;CAAa;CAAW;CAAmB;CAC5D;CAAY;CAAc;CAAY;CAAyB;AACjE;AAEA,MAAa,2BAA8C;CACzD;CAAS;CAAQ;CAAS;CAAU;CAAU;CAAK;CAAO;CAAW;CACrE;CAAQ;CAAU;CAAc;AAClC;AAEA,MAAa,4BAA+C;CAAC;CAAU;CAAS;CAAS;CAAO;AAAM;AAEtG,MAAa,2BAA8C;CACzD;CAAU;CAAO;CAAU;CAAO;CAAU;CAAW;CAAQ;CAAQ;CACvE;CAAU;CAAO;CAAQ;CAAS;AACpC;AAEA,MAAa,8BAAiD;CAC5D;CAAU;CAAe;CAAiB;CAAkB;CAC5D;CAAqB;CAAuB;CAAyB;CACrE;CAAgB;CAA2B;CAAY;CACvD;CAAmB;CAAa;CAAkB;CAAU;CAAe;CAC3E;CAAe;CAAgB;CAAY;CAAiB;CAAc;CAC1E;CAAyB;CAAqB;CAAwB;CACtE;CAAiB;CAAiB;CAAiB;CAAoB;CACvE;CAAY;CAAY;CAAa;CAAc;CAAe;CAClE;CAAY;CAAY;CAAsB;CAAY;CAAS;CAAS;CAC5E;CAAO;CAAU;CAAa;CAAU;CAAkB;CAAe;CACzE;CAAsB;CAAa;CAAc;CAAc;CAC/D;CAAmB;CAAoB;CAAY;CAAW;CAC9D;CAAmB;CAAS;CAAQ;CAAa;CAAY;CAC7D;CAAc;CAAgB;CAAc;CAAmB;CAC/D;CAAqB;CAAkB;CAAiB;CAAQ;CAAY;CAC5E;CAAiB;CAAU;CAAe;CAAmB;CAAU;CACvE;CAAoB;CAAc;CAAmB;CAAmB;CACxE;CAAa;CAAgB;CAAY;CAAe;CAAkB;CAC1E;CAAY;CAAiB;CAAU;CAAiB;CACxD;CAA4B;CAA2B;CAAuB;CAC9E;CAAwB;CAAoB;CAAmB;CAC/D;CAAkB;CAAiB;CAAa;CAAe;CAC/D;CAAkB;CAAc;CAAQ;CAAa;CAAiB;CACtE;CAAc;CAAa;CAAW;CAAY;CAAY;CAAa;CAC3E;CAAiB;CAAgB;CAA4B;CAC7D;CAAoC;CAAsB;CAC1D;CAAmB;CAAiB;CAAyB;CAC7D;CAAkB;CAA0B;CAAY;CAAgB;CACxE;CAAmB;CAAmB;CAAkB;CACxD;CAAsB;CAAyB;CAAmB;CAClE;CAAsB;CAAmB;CACzC;CAAgC;CAAmB;CACnD;CAAuB;CAAoB;CAAwB;CACnE;CAAyB;CAAc;CAAc;CACrD;CAAyB;CAAsB;CAAiB;CAAa;CAC7E;CAAc;CAAO;CAAW;CAAkB;CAAU;CAAW;CACvE;CAAc;CAAgB;CAAY;AAC5C;AAEA,MAAM,uBAAuB,IAAI,IAAI,0BAA0B;AAC/D,MAAM,oBAAoB,IAAI,IAAI,sBAAsB;AACxD,MAAM,sBAAsB,IAAI,IAAI,wBAAwB;AAC5D,MAAM,uBAAuB,IAAI,IAAI,yBAAyB;AAC9D,MAAM,iBAAiB,IAAI,IAAI,wBAAwB;AACvD,MAAM,oBAAoB,IAAI,IAAI,2BAA2B;AAE7D,MAAM,gDAAgC,IAAI,IAAI,mCAAmC;AACjF,MAAM,kBAAkB;AAMxB,MAAM,UAA6B;CACjC;CAAe;CAAgB;CAAc;CAAgB;CAAc;CAAgB;CAAe;CAAa;CAAc;CAAc;CAAY;CAC/J;CAAY;CAAY;CAAY;CAAgB;CAAiB;CAAY;CAAc;CAAc;CAAa;CAAY;CAAa;CACnJ;CAAY;CAAa;CAAW;CAAY;CAAY;CAAY;CAAQ;CAAU;CAAS;CAAS;CAAY;CACxH;CAAS;CAAa;CAAS;CAAW;CAAU;CAAY;CAAU;CAAW;CAAU;CAAS;CAAS;CACjH;CAAW;CAAU;CAAQ;CAAY;CAAa;CAAQ;CAAU;CAAO;CAAQ;CAAS;CAAa;CAC7G;CAAa;CAAW;CAAc;CAAY;CAAe;CAAa;CAAgB;CAAe;CAAS;CAAkB;CAAiB;CACzJ;CAAU;CAAS;CAAU;CAAW;CAAe;CAAW;CAAiB;CAAe;CAAiB;CAAiB;CAAQ;CAC5I;CAAY;CAAa;CAAa;CAAa;CAAa;CAAa;CAAY;CAAa;CAAc;CAAW;CAAW;CAC1I;CAAa;CAAY;CAAiB;CAAa;CAAU;CAAU;CAAU;CAAe;CAAc;CAAgB;CAAgB;CAClJ;CAAe;CAAiB;CAAiB;CAAiB;CAAiB;CAAa;CAAW;CAAW;CAAY;CAAW;CAAU;CACvJ;CAAW;CAAa;CAAa;CAAa;CAAa;CAAW;CAAY;CAAc;CAAS;CAAU;CAAU;CACjI;CAAQ;CAAQ;CAAS;CAAQ;CAAU;CAAa;CAAU;CAAU;CAAgB;CAAY;CAAS;CACjH;CAAY;CAAS;CAAQ;CAAQ;CAAW;CAAY;CAAU;CAAc;CAAY;CAAW;CAAW;CACtH;CAAc;CAAU;CAAY;CAAa;CAAW;CAAgB;CAAY;CAAc;CAAkB;CAAY;CAAa;CACjJ;CAAY;CAAW;CAAmB;CAAW;CAAY;CAAa;CAAiB;CAAY;CAAa;CAAY;CAAW;CAC/I;CAAQ;CAAa;CAAU;CAAc;CAAa;CAAY;CAAW;CAAa;CAAc;CAAY;CAAY;CACpI;CAAQ;CAAY;CAAU;CAAU;CAAY;CAAW;CAAe;CAAa;CAAgB;CAAS;CAAQ;CAC5H;CAAY;CAAW;CAAQ;CAAa;CAAS;CAAY;CAAW;CAAW;CAAY;CAAS;CAAU;CACtH;CAAY;CAAU;CAAc;CAAgB;CAAe;CAAc;CAAa;CAAc;CAAY;CAAW;CAAe;CAClJ;CAAe;CAAe;CAAc;CAAc;CAAc;CAAW;CAAa;CAAY;CAAiB;CAAa;CAAe;CACzJ;CAAgB;CAAQ;CAAS;CAAY;CAAS;CAAY;CAAQ;CAAc;CAAU;CAAW;CAAc;CAC3H;CAAU;CAAc;CAAY;CAAW;CAAW;CAAS;CAAU;CAAY;CAAY;CAAc;CAAY;CAC/H;CAAc;CAAU;CAAU;CAAQ;CAAU;CAAa;CAAU;CAAe;CAAU;CAAiB;CAAgB;CACrI;CAAa;CAAW;CAAmB;CAAc;CAAe;CAAc;CAAkB;CAAY;CAAY;CAAY;CAAc;CAC1J;CAAU;CAAU;CAAS;CAAa;CAAa;CAAc;CAAY;CAAY;CAAW;CAAY;CAAc;CAClI;CAAa;CAAa;CAAY;CAAgB;CAAgB;CAAkB;CAAO;CAAQ;CAAW;CAAS;CAAU;CACrI;CAAS;CAAgB;CAAW;CAAY;CAAY;CAAc;CAAU;CAAS;CAAW;CAAa;CAAa;CAClI;CAAY;CAAY;CAAY;CAAU;CAAe;CAAQ;CAAY;CAAc;CAAS;CAAU;CAAY;CAC9H;CAAY;CAAQ;CAAa;CAAe;CAAc;CAAS;CAAU;CAAc;CAAW;CAAU;CAAc;CAClI;CAAc;CAAe;CAAW;CAAa;CAAc;CAAU;CAAY;CAAa;CAAY;CAAe;CAAe;CAChJ;CAAc;CAAe;CAAgB;CAAa;CAAW;CAAa;CAAa;CAAS;CAAY;CAAY;CAAU;CAC1I;CAAY;CAAc;CAAa;CAAa;CAAiB;CAAe;CAAW;CAAQ;CAAY;CAAW;CAAU;CACxI;CAAY;CAAY;CAAW;CAAW;CAAa;CAAU;CAAU;CAAa;CAAU;CAAc;CAAY;CAChI;CAAW;CAAe;CAAc;CAAa;CAAY;CAAa;CAAc;CAAW;CAAY;CAAW;CAAS;CACvI;CAAc;CAAW;CAAU;CAAa;CAAU;CAAW;CAAa;CAAc;CAAW;CAAa;CAAW;CACnI;CAAa;CAAY;CAAc;CAAU;CAAQ;CAAU;CAAS;CAAU;CAAgB;CAAa;CAAY;CAC/H;CAAa;CAAY;CAAY;CAAgB;CAAgB;CAAgB;CAAiB;CAAU;CAAc;CAAU;CAAO;CAC/I;CAAY;CAAW;CAAU;CAAU;CAAQ;CAAS;CAAS;CAAU;CAAY;CAAS;CAAW;CAC/G;CAAY;CAAU;CAAW;CAAW;CAAU;CAAU;CAAW;CAAS;CAAU;CAAY;CAAa;CACvH;CAAS;CAAY;CAAU;CAAU;CAAa;CAAc;CAAgB;CAAa;CAAS;CAAU;CAAU;CAC9H;CAAc;CAAY;CAAW;CAAc;CAAW;CAAY;CAAW;CAAa;CAAY;CAAO;CAAS;CAC9H;CAAQ;CAAe;CAAW;CAAQ;CAAY;CAAa;CAAc;CAAc;CAAa;CAAU;CAAW;CACjI;CAAW;CAAU;CAAU;CAAW;CAAY;CAAU;CAAW;CAAY;CAAa;CAAU;CAAS;CACvH;CAAa;CAAa;CAAY;CAAO;CAAQ;CAAW;CAAS;CAAS;CAAO;CAAU;CAAS;CAC5G;CAAW;CAAY;CAAY;CAAiB;CAAY;CAAS;CAAW;CAAa;CAAa;CAAe;CAAS;CACtI;CAAY;CAAW;CAAS;CAAa;CAAW;CAAS;CAAQ;CAAY;CAAS;CAAS;CAAU;CACjH;CAAQ;CAAW;CAAU;CAAW;CAAQ;CAAQ;CAAa;CAAW;CAAO;CAAO;CAAa;CAC3G;CAAa;CAAQ;CAAS;CAAe;CAAc;CAAe;CAAa;CAAU;CAAW;CAAU;CAAW;CACjI;CAAQ;CAAa;CAAQ;CAAW;CAAa;CAAS;CAAW;CAAc;CAAW;CAAS;CAAa;CACxH;CAAiB;CAAY;CAAe;CAAgB;CAAa;CAAW;CAAS;CAAW;CAAc;CAAQ;CAAS;CACvI;CAAW;CAAW;CAAa;CAAe;CAAc;CAAc;CAAY;CAAU;CAAQ;CAAU;CAAc;CACpI;CAAa;CAAW;CAAS;CAAQ;CAAY;CAAY;CAAU;CAAa;CAAU;CAAO;CAAY;CACrH;CAAc;CAAa;CAAa;CAAa;CAAa;CAAU;CAAU;CAAa;CAAc;CAAS;CAAQ;CAClI;CAAW;CAAU;CAAU;CAAa;CAAS;CAAS;CAAS;CAAW;CAAU;CAAa;CAAU;CACnH;CAAS;CAAW;CAAW;CAAY;CAAc;CAAY;CAAU;CAAQ;CAAa;CAAc;CAAW;CAC7H;CAAS;CAAa;CAAS;CAAY;CAAU;CAAQ;CAAa;CAAU;CAAa;CAAY;CAAW;CACxH;CAAS;CAAW;CAAc;CAAc;CAAU;CAAe;CAAS;CAAa;CAAY;CAAa;CAAQ;CAChI;CAAY;CAAa;CAAW;CAAW;CAAc;CAAU;CAAS;CAAY;CAAc;CAAS;CAAW;CAC9H;CAAY;CAAc;CAAS;CAAQ;CAAS;CAAW;CAAY;CAAW;CAAS;CAAU;CAAU;CACnH;CAAW;CAAgB;CAAS;CAAY;CAAU;CAAS;CAAW;CAAU;CAAW;CAAS;CAAc;CAC1H;CAAe;CAAS;CAAW;CAAS;CAAY;CAAgB;CAAa;CAAc;CAAS;CAAY;CAAc;CACtI;CAAW;CAAgB;CAAO;CAAY;CAAa;CAAU;CAAY;CAAW;CAAS;CAAS;CAAU;CACxH;CAAW;CAAc;CAAU;CAAW;CAAa;CAAc;CAAW;CAAY;CAAW;CAAU;CAAU;CAC/H;CAAW;CAAY;CAAY;CAAW;CAAW;CAAa;CAAW;CAAY;CAAa;CAAc;CAAe;CACvI;CAAc;CAAa;CAAW;CAAW;CAAY;CAAY;CAAU;CAAc;CAAO;CAAQ;CAAW;CAC3H;CAAY;CAAa;CAAS;CAAY;CAAW;CAAW;CAAW;CAAS;CAAQ;CAAY;CAAU;CACtH;CAAS;CAAY;CAAS;CAAa;CAAS;CAAU;CAAQ;CAAW;CAAQ;CAAc;CAAc;CACrH;CAAe;CAAa;CAAc;CAAgB;CAAS;CAAa;CAAa;CAAU;CAAS;CAAS;CAAkB;CAC3I;CAAgB;CAAgB;CAAa;CAAa;CAAQ;CAAW;CAAY;CAAe;CAAa;CAAY;CAAW;CAC5I;CAAa;CAAS;CAAY;CAAQ;CAAU;CAAS;CAAU;CAAW;CAAW;CAAW;CAAW;CACnH;CAAc;CAAS;CAAa;CAAkB;CAAgB;CAAQ;CAAW;CAAS;CAAe;CAAgB;CAAe;CAChJ;CAAW;CAAU;CAAU;CAAa;CAAa;CAAa;CAAW;CAAa;CAAW;CAAW;CAAc;CAClI;CAAa;CAAY;CAAa;CAAa;CAAc;CAAc;CAAgB;CAAQ;CAAQ;CAAU;CAAU;CACnI;CAAQ;CAAY;CAAU;CAAgB;CAAe;CAAS;CAAW;CAAS;CAAa;CAAW;CAAY;CAC9H;CAAc;CAAY;CAAa;CAAe;CAAgB;CAAa;CAAU;CAAc;CAAS;CAAU;CAAU;CACxI;CAAY;CAAc;CAAa;CAAU;CAAa;CAAW;CAAW;CAAc;CAAa;CAAa;CAAS;CACrI;CAAU;CAAe;CAAQ;CAAQ;CAAW;CAAQ;CAAS;CAAa;CAAU;CAAS;CAAW;CAChH;CAAW;CAAa;CAAa;CAAa;CAAQ;CAAW;CAAS;CAAY;CAAW;CAAU;CAAa;CAC5H;CAAY;CAAc;CAAS;CAAQ;CAAS;CAAa;CAAa;CAAY;CAAU;CAAW;CAAY;CAC3H;CAAe;CAAU;CAAS;CAAS;CAAa;CAAW;CAAY;CAAa;CAAa;CAAS;CAAc;CAChI;CAAa;CAAU;CAAQ;CAAY;CAAa;CAAY;CAAY;CAAY;CAAY;CAAY;CAAW;CAC/H;CAAY;CAAU;CAAY;CAAa;CAAY;CAAY;CAAY;CAAa;CAAa;CAAc;CAAS;CACpI;CAAY;CAAW;CAAQ;CAAW;CAAY;CAAU;CAAa;CAAS;CAAS;CAAQ;CAAW;CAClH;CAAQ;CAAQ;CAAU;CAAa;CAAW;CAAY;CAAS;CAAS;CAAS;CAAS;CAAQ;CAC1G;CAAa;CAAa;CAAW;CAAU;CAAc;CAAY;CAAY;CAAS;CAAS;CAAU;CAAY;CAC7H;CAAS;CAAY;CAAc;CAAgB;CAAY;CAAU;CAAa;CAAW;CAAU;CAAW;CAAU;CAChI;CAAU;CAAW;CAAY;CAAa;CAAY;CAAY;CAAa;CAAQ;CAAY;CAAU;CAAa;CAC9H;CAAW;CAAU;CAAY;CAAa;CAAY;CAAU;CAAY;CAAS;CAAO;CAAQ;CAAW;CACnH;CAAY;CAAU;CAAc;CAAU;CAAQ;CAAQ;CAAY;CAAY;CAAY;CAAc;CAAW;CAC3H;CAAY;CAAU;CAAa;CAAS;CAAQ;CAAW;CAAgB;CAAe;CAAc;CAAY;CAAa;CACrI;CAAW;CAAY;CAAY;CAAW;CAAY;CAAU;CAAS;CAAS;CAAa;CAAS;CAAQ;CACpH;CAAS;CAAU;CAAY;CAAS;CAAU;CAAQ;CAAY;CAAY;CAAO;CAAO;CAAY;CAC5G;CAAS;CAAS;CAAW;CAAa;CAAa;CAAY;CAAa;CAAS;CAAY;CAAY;CAAgB;CACjI;CAAgB;CAAY;CAAc;CAAa;CAAY;CAAa;CAAc;CAAc;CAAU;CAAS;CAAU;CACzI;CAAY;CAAU;CAAW;CAAc;CAAc;CAAS;CAAU;CAAc;CAAW;CAAa;CAAW;CACjI;CAAa;CAAU;CAAS;CAAW;CAAW;CAAa;CAAY;CAAW;CAAW;CAAc;CAAY;CAC/H;CAAO;CAAO;CAAQ;CAAS;CAAa;CAAU;CAAU;CAAU;CAAS;CAAY;CAAW;CAC1G;CAAU;CAAS;CAAW;CAAY;CAAY;CAAc;CAAQ;CAAO;CAAO;CAAS;CAAW;CAC9G;CAAa;CAAgB;CAAS;CAAa;CAAU;CAAW;CAAa;CAAY;CAAU;CAAS;CAAU;CAC9H;CAAU;CAAS;CAAS;CAAc;CAAc;CAAe;CAAY;CAAe;CAAY;CAAe;CAAa;CAC1I;CAAW;CAAU;CAAS;CAAY;CAAQ;CAAa;CAAU;CAAW;CAAY;CAAa;CAAS;CACtH;CAAa;CAAY;CAAe;CAAc;CAAa;CAAc;CAAY;CAAc;CAAW;CAAc;CAAc;CAClJ;CAAW;CAAW;CAAS;CAAS;CAAW;CAAY;CAAS;CAAQ;CAAU;CAAW;CAAU;CAC/G;CAAY;CAAY;CAAe;CAAY;CAAY;CAAc;CAAW;CAAe;CAAa;CAAS;CAAW;CACxI;CAAY;CAAU;CAAY;CAAU;CAAQ;CAAS;CAAU;CAAY;CAAc;CAAU;CAAQ;CACnH;CAAY;CAAa;CAAY;CAAQ;CAAU;CAAY;CAAc;CAAU;CAAU;CAAY;CAAY;CAC7H;CAAY;CAAe;CAAa;CAAW;CAAS;CAAQ;CAAW;CAAgB;CAAkB;CAAU;CAAS;CACpI;CAAa;CAAa;CAAS;CAAa;CAAa;CAAY;CAAa;CAAa;CAAY;CAAa;CAAc;CAC1I;CAAa;CAAc;CAAa;CAAU;CAAW;CAAS;CAAgB;CAAQ;CAAY;CAAY;CAAc;CACpI;CAAc;CAAW;CAAY;CAAU;CAAa;CAAS;CAAS;CAAS;CAAW;CAAc;CAAU;CAC1H;CAAU;CAAc;CAAW;CAAS;CAAU;CAAQ;CAAU;CAAQ;CAAQ;CAAS;CAAS;CAC1G;CAAY;CAAc;CAAY;CAAU;CAAQ;CAAS;CAAY;CAAc;CAAU;CAAU;CAAa;CAC5H;CAAW;CAAU;CAAS;CAAa;CAAQ;CAAS;CAAW;CAAe;CAAW;CAAS;CAAa;CACvH;CAAa;CAAW;CAAY;CAAW;CAAU;CAAS;CAAW;CAAU;CAAQ;CAAW;CAAQ;CAClH;CAAa;CAAe;CAAU;CAAe;CAAU;CAAY;CAAkB;CAAW;CAAY;CAAY;CAAU;CAC1I;CAAU;CAAU;CAAY;CAAa;CAAQ;CAAQ;CAAY;CAAY;CAAgB;CAAY;CAAU;CAC3H;CAAY;CAAU;CAAa;CAAS;CAAW;CAAQ;CAAgB;CAAS;CAAS;CAAW;CAAS;CACrH;CAAgB;CAAY;CAAU;CAAS;CAAY;CAAU;CAAU;CAAU;CAAa;CAAS;CAAU;CACzH;CAAW;CAAU;CAAQ;CAAY;CAAU;CAAc;CAAS;CAAW;CAAQ;CAAY;CAAY;CACrH;CAAa;CAAY;CAAa;CAAa;CAAa;CAAa;CAAY;CAAW;CAAc;CAAW;CAAW;CACxI;CAAa;CAAW;CAAa;CAAY;CAAY;CAAa;CAAa;CAAY;CAAa;CAAc;CAAW;CACzI;CAAc;CAAgB;CAAY;CAAY;CAAa;CAAY;CAAY;CAAa;CAAY;CAAa;CAAY;CAC7I;CAAa;CAAS;CAAO;CAAQ;CAAW;CAAc;CAAU;CAAS;CAAS;CAAY;CAAgB;CACtH;CAAW;CAAY;CAAW;CAAa;CAAa;CAAU;CAAQ;CAAY;CAAY;CAAY;CAAW;CAC7H;CAAY;CAAW;CAAQ;CAAQ;CAAW;CAAU;CAAU;CAAY;CAAa;CAAW;CAAa;CACvH;CAAW;CAAU;CAAc;CAAe;CAAY;CAAa;CAAY;CAAY;CAAS;CAAQ;CAAY;CAChI;CAAW;CAAS;CAAc;CAAO;CAAW;CAAS;CAAU;CAAS;CAAY;CAAY;CAAY;CACpH;CAAe;CAAc;CAAY;CAAY;CAAa;CAAU;CAAW;CAAU;CAAS;CAAe;CAAY;CACrI;CAAU;CAAa;CAAa;CAAa;CAAe;CAAmB;CAAa;CAAa;CAAiB;CAAa;CAAc;CACzJ;CAAY;CAAW;CAAY;CAAe;CAAgB;CAAgB;CAAiB;CAAc;CAAiB;CAAgB;CAAiB;CACnK;CAAc;CAAe;CAAa;CAAa;CAAc;CAAa;CAAoB;CAAe;CAAgB;CAAkB;CAAe;CACtK;CAAe;CAAe;CAAa;CAAc;CAAa;CAAe;CAAkB;CAAkB;CAAe;CAAsB;CAAU;CACxK;CAAe;CAAU;CAAY;CAAU;CAAW;CAAS;CAAS;CAAU;CAAW;CAAY;CAAa;CAC1H;CAAO;CAAQ;CAAY;CAAY;CAAY;CAAY;CAAS;CAAU;CAAW;CAAS;CAAS;CAC/G;CAAS;CAAY;CAAY;CAAY;CAAU;CAAW;CAAQ;CAAY;CAAU;CAAY;CAAa;CACzH;CAAU;CAAO;CAAQ;CAAS;CAAU;CAAS;CAAQ;CAAY;CAAY;CAAY;CAAa;CAC9G;CAAU;CAAa;CAAa;CAAY;CAAc;CAAe;CAAW;CAAY;CAAU;CAAY;CAAa;CACvI;CAAS;CAAS;CAAS;CAAQ;CAAU;CAAW;CAAQ;CAAW;CAAa;CAAY;CAAS;CAC7G;CAAQ;CAAW;CAAa;CAAQ;CAAW;CAAS;CAAW;CAAO;CAAU;CAAa;CAAW;CAChH;CAAe;CAAY;CAAY;CAAU;CAAW;CAAS;CAAW;CAAe;CAAW;CAAY;CAAY;CAClI;CAAgB;CAAY;CAAe;CAAU;CAAW;CAAY;CAAQ;CAAU;CAAc;CAAU;CAAiB;CACvI;CAAS;CAAW;CAAe;CAAa;CAAe;CAAY;CAAS;CAAQ;CAAW;CAAY;CAAY;CAC/H;CAAY;CAAa;CAAU;CAAU;CAAa;CAAa;CAAa;CAAiB;CAAa;CAAY;CAAc;CAC5I;CAAc;CAAa;CAAe;CAAY;CAAa;CAAa;CAAU;CAAa;CAAW;CAAa;CAAU;CACzI;CAAW;CAAc;CAAgB;CAAa;CAAiB;CAAc;CAAgB;CAAc;CAAkB;CAAS;CAAY;CAC1J;CAAc;CAAc;CAAc;CAAY;CAAU;CAAkB;CAAY;CAAY;CAAW;CAAa;CAAiB;CACnJ;CAAc;CAAiB;CAAe;CAAgB;CAAe;CAAc;CAAe;CAAe;CAAe;CAAa;CAAY;CACjK;CAAW;CAAa;CAAa;CAAc;CAAY;CAAY;CAAkB;CAAY;CAAY;CAAa;CAAe;CACjJ;CAAe;CAAQ;CAAQ;CAAY;CAAW;CAAa;CAAS;CAAa;CAAY;CAAY;CAAc;CAC/H;CAAc;CAAc;CAAkB;CAAc;CAAe;CAAW;CAAW;CAAS;CAAU;CAAe;CAAa;CAChJ;CAAe;CAAY;CAAW;CAAS;CAAY;CAAW;CAAW;CAAc;CAAY;CAAQ;CAAS;CAC5H;CAAc;CAAa;CAAa;CAAe;CAAW;CAAgB;CAAc;CAAc;CAAiB;CAAe;CAAiB;CAC/J;CAAe;CAAe;CAAgB;CAAiB;CAAiB;CAAgB;CAAiB;CAAe;CAAe;CAAiB;CAAe;CAC/K;CAAiB;CAAgB;CAAc;CAAU;CAAY;CAAU;CAAY;CAAY;CAAQ;CAAY;CAAW;CACtI;CAAW;CAAW;CAAa;CAAc;CAAY;CAAiB;CAAc;CAAe;CAAY;CAAa;CAAY;CAChJ;CAAa;CAAW;CAAY;CAAY;CAAa;CAAa;CAAe;CAAW;CAAY;CAAU;CAAa;CACvI;CAAgB;CAAe;CAAgB;CAAgB;CAAc;CAAe;CAAgB;CAAgB;CAAW;CAAgB;CAAe;CACtK;CAAiB;CAAgB;CAAgB;CAAgB;CAAc;CAAgB;CAAc;CAAc;CAAa;CAAU;CAAS;CAC3J;CAAW;CAAY;CAAa;CAAS;CAAW;CAAU;CAAa;CAAS;CAAY;CAAU;CAAY;CAC1H;CAAW;CAAe;CAAkB;CAAQ;CAAS;CAAQ;CAAY;CAAY;CAAa;CAAY;CAAW;CACjI;CAAW;CAAY;CAAW;CAAY;CAAW;CAAa;CAAY;CAAc;CAAS;CAAY;CAAc;CACnI;CAAW;CAAc;CAAY;CAAW;CAAW;CAAS;CAAU;CAAa;CAAa;CAAa;CAAS;CAC9H;CAAgB;CAAiB;CAAe;CAAW;CAAa;CAAc;CAAoB;CAAY;CAAa;CAAY;CAAa;CAC5J;CAAa;CAAY;CAAgB;CAAY;CAAY;CAAc;CAAgB;CAAW;CAAW;CAAU;CAAS;CACxI;CAAQ;CAAS;CAAY;CAAW;CAAY;CAAS;CAAU;CAAU;CAAQ;CAAQ;CAAQ;CACzG;CAAY;CAAS;CAAU;CAAW;CAAY;CAAc;CAAW;CAAY;CAAc;CAAe;CAAW;CACnI;CAAY;CAAS;CAAO;CAAc;CAAa;CAAS;CAAQ;CAAS;CAAU;CAAW;CAAW;CACjH;CAAa;CAAe;CAAgB;CAAiB;CAAkB;CAAiB;CAAa;CAAc;CAAa;CAAc;CAAgB;CACtK;CAAU;CAAS;CAAgB;CAAa;CAAY;CAAY;CAAS;CAAU;CAAW;CAAS;CAAW;CAC1H;CAAa;CAAW;CAAW;CAAQ;CAAQ;CAAgB;CAAW;CAAW;CAAY;CAAS;CAAU;CACxH;CAAc;CAAW;CAAY;CAAa;CAAa;CAAW;CAAc;CAAU;CAAY;CAAQ;CAAY;CAClI;CAAc;CAAY;CAAY;CAAS;CAAU;CAAY;CAAU;CAAW;CAAS;CAAQ;CAAW;CACtH;CAAW;CAAe;CAAW;CAAY;CAAY;CAAc;CAAY;CAAY;CAAgB;CAAW;CAAY;CAC1I;CAAW;CAAa;CAAU;CAAa;CAAe;CAAS;CAAQ;CAAS;CAAY;CAAa;CAAU;CAC3H;CAAU;CAAa;CAAW;CAAa;CAAS;CAAO;CAAa;CAAO;CAAY;CAAe;CAAW;CACzH;CAAU;CAAU;CAAS;CAAQ;CAAU;CAAW;CAAO;CAAU;CAAW;CAAc;CAAa;CACjH;CAAU;CAAY;CAAU;CAAa;CAAW;CAAS;CAAU;CAAQ;CAAW;CAAY;CAAS;CACnH;CAAW;CAAW;CAAY;CAAY;CAAa;CAAe;CAAW;CAAa;CAAc;CAAY;CAAc;CAC1I;CAAW;CAAW;CAAa;CAAS;CAAQ;CAAY;CAAc;CAAa;CAAY;CAAa;CAAW;CAC/H;CAAU;CAAY;CAAY;CAAW;CAAc;CAAS;CAAW;CAAU;CAAY;CAAW;CAAU;CAC1H;CAAU;CAAc;CAAS;CAAc;CAAe;CAAc;CAAa;CAAa;CAAe;CAAiB;CAAgB;CACtJ;CAAiB;CAAkB;CAAW;CAAa;CAAY;CAAc;CAAmB;CAAc;CAAgB;CAAgB;CAAY;CAClK;CAAa;CAAY;CAAY;CAAa;CAAe;CAAc;CAAa;CAAe;CAAiB;CAAgB;CAAoB;CAChK;CAAkB;CAAa;CAAY;CAAY;CAAa;CAAa;CAAO;CAAa;CAAe;CAAU;CAAa;CAC3I;CAAa;CAAiB;CAAa;CAAiB;CAAe;CAAW;CAAc;CAAY;CAAU;CAAY;CAAO;CAC7I;CAAY;CAAY;CAAU;CAAU;CAAU;CAAS;CAAU;CAAQ;CAAY;CAAO;CAAQ;CAC5G;CAAW;CAAW;CAAS;CAAW;CAAO;CAAS;CAAc;CAAa;CAAY;CAAc;CAAc;CAC7H;CAAa;CAAa;CAAY;CAAa;CAAc;CAAa;CAAU;CAAa;CAAiB;CAAa;CAAa;CAChJ;CAAc;CAAe;CAAW;CAAW;CAAY;CAAc;CAAa;CAAW;CAAY;CAAS;CAAa;CACvI;CAAY;CAAa;CAAW;CAAY;CAAa;CAAY;CAAW;CAAU;CAAS;CAAQ;CAAW;CAC1H;CAAY;CAAQ;CAAY;CAAa;CAAe;CAAY;CAAU;CAAS;CAAS;CAAU;CAAS;CACvH;CAAW;CAAS;CAAc;CAAY;CAAQ;CAAa;CAAW;CAAY;CAAY;CAAU;CAAS;CACzH;CAAa;CAAY;CAAW;CAAW;CAAS;CAAW;CAAY;CAAY;CAAW;CAAW;CAAY;CAC7H;CAAY;CAAY;CAAQ;CAAY;CAAY;CAAS;CAAW;CAAa;CAAY;CAAe;CAAa;CACjI;CAAU;CAAW;CAAa;CAAS;CAAY;CAAW;CAAY;CAAa;CAAY;CAAa;CAAe;CACnI;CAAc;CAAY;CAAW;CAAgB;CAAU;CAAU;CAAY;CAAc;CAAY;CAAU;CAAc;CACvI;CAAW;CAAc;CAAc;CAAa;CAAS;CAAW;CAAa;CAAe;CAAiB;CAAc;CAAc;CACjJ;CAAe;CAAe;CAAe;CAAgB;CAAW;CAAQ;CAAc;CAAS;CAAW;CAAU;CAAW;CACvI;CAAc;CAAW;CAAc;CAAgB;CAAoB;CAAkB;CAAW;CAAW;CAAe;CAAe;CAAe;CAChK;CAAa;CAAe;CAAW;CAAU;CAAY;CAAS;CAAU;CAAQ;CAAQ;CAAO;CAAQ;AACjH;;AAOA,SAAgB,WAAW,OAAuB;CAChD,OAAO,MAAM,WAAW,IAAI,QAAQ,MAAM,EAAE,CAAE,YAAY,IAAI,MAAM,MAAM,CAAC,CAAC,CAAC,YAAY;AAC3F;;AAGA,SAAS,YAAY,MAAuB;CAC1C,OAAO,QAAQ,OAAO,QAAQ;AAChC;;AAGA,SAAgB,WAAW,MAAwB;CACjD,OAAO,KAAK,QAAQ,WAAU,OAAM,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG;AACzD;;AAGA,SAAgB,aAAa,QAAgB,KAAkB;CAC7D,IAAI,MAAM;CACV,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS,GAC3C,OAAO,gBAAgB,KAAK,MAAM,IAAI,IAAI,EAAsB;CAElE,OAAO;AACT;;AAGA,SAAgB,eAAe,OAAwB;CACrD,OAAO,QAAQ,KAAK,KAAK;AAC3B;;AAGA,SAAgB,iBAAiB,OAAwB;CACvD,KAAK,MAAM,QAAQ,OAAO,IAAI,8BAA8B,IAAI,IAAI,GAAG,OAAO;CAC9E,OAAO;AACT;;AAGA,SAAgB,OAAO,OAAuB;CAC5C,OAAO,WAAW,KAAK,CAAC,CAAC,OAAO,OAAO,MAAM,CAAC,CAAC,OAAO,KAAK;AAC7D;;AAGA,SAAgB,gBAAgB,QAAwB;CACtD,OAAO,WAAW,KAAK,CAAC,CAAC,OAAO,OAAO,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,KAAK;AACxE;;AAGA,SAAgB,YAAY,KAAkB;CAC5C,MAAM,QAAQ,KAAK,IAAI,QAAQ,SAAS,GAAG,KAAK,MAAM,IAAI,IAAI,QAAQ,MAAM,CAAC;CAC7E,IAAI,OAAO,QAAQ,UAAU;CAC7B,IAAI,SAAS,WAAW,OAAO;CAC/B,OAAO,SAAS,KAAK,SAAS;AAChC;AAEA,SAAS,UAAU,KAAU,KAAa,KAAqB;CAC7D,OAAO,MAAM,KAAK,MAAM,IAAI,KAAK,MAAM,MAAM,EAAE;AACjD;;AAGA,SAAS,YAAY,MAAc,MAAc,UAA0B;CACzE,IAAI,CAAC,MAAM,OAAO;CAClB,OAAO,KAAK,QAAQ,IAAI,OAAO,MAAM,aAAa,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ;AACpF;;AAOA,SAAgB,yBAAyB,MAAc,aAAqB,KAAkB;CAC5F,IAAI,QAAQ,WAAW,IAAI;CAC3B,MAAM,eAAe,WAAW,YAAY,GAAG,CAAC;CAChD,IAAI;CACJ,IAAI,MAAM,SAAS,KAAK,MAAM,EAAE,CAAE,WAAW,GAC3C,OAAO,MAAM,SAAS,KAAK,MAAM,EAAE,CAAE,WAAW,GAAG,QAAQ,MAAM,MAAM,CAAC;CAE1E,IAAI,MAAM,SAAS,GACjB,cAAc,WAAW,MAAM,MAAM,SAAS,EAAG;MAEjD,cAAc,WAAW,YAAY,GAAG,CAAC;CAE3C,MAAM,MAAgB,CAAC,YAAY;CACnC,IAAI,WAAW,MAAM,SAAS;CAC9B,IAAI,YAAY,GAAG,WAAW;CAC9B,KAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,UAAU,KAAK,GAAG,CAAC,GAAG,SAAS,GACpE,IAAI,KAAK,WAAW,YAAY,GAAG,CAAC,CAAC;CAEvC,IAAI,KAAK,WAAW;CACpB,IAAI,SAAS,IAAI,KAAK,EAAE;CACxB,IAAI,KAAK,WAAW,GAAG,GAAG,SAAS,IAAI;CACvC,OAAO;AACT;;AAGA,SAAgB,0BAA0B,MAAc,YAAoB,KAAkB;CAC5F,MAAM,QAAQ,WAAW,IAAI;CAC7B,IAAI,eAAe,YAAY,GAAG;CAClC,IAAI,WAAW,SAAS,KAAK,CAAC,WAAW,SAAS,GAAG,GACnD,eAAe,WAAW,YAAY;MACjC,IAAI,KAAK,WAAW,GAAG,GAC5B,WAAgB,YAAY,GAAG,CAAC;CAElC,MAAM,OAAO,MAAM,QAAO,SAAQ,KAAK,SAAS,CAAC;CACjD,IAAI;CACJ,IAAI,KAAK,SAAS,GAChB,cAAc,KAAK,KAAK,SAAS;MAEjC,cAAc,WAAW,YAAY,GAAG,CAAC;CAE3C,IAAI,SAAS,eAAe,WAAW,YAAY,GAAG,CAAC,IAAI,WAAW,WAAW;CACjF,IAAI,KAAK,WAAW,GAAG,GAAG,SAAS,IAAI;CACvC,OAAO;AACT;;AAGA,SAAgB,4BAA4B,MAAc,YAAoB,KAAkB;CAC9F,MAAM,QAAQ,WAAW,IAAI;CAC7B,IAAI,eAAe,YAAY,GAAG;CAClC,IAAI,WAAW,SAAS,KAAK,CAAC,WAAW,SAAS,GAAG,GACnD,eAAe,WAAW,YAAY;MACjC,IAAI,KAAK,WAAW,GAAG,GAC5B,WAAgB,YAAY,GAAG,CAAC;CAElC,IAAI;CACJ,IAAI,MAAM,SAAS,GACjB,cAAc,WAAW,MAAM,MAAM,SAAS,EAAG;MAEjD,cAAc,WAAW,YAAY,GAAG,CAAC;CAE3C,IAAI,SAAS,eAAe;CAC5B,IAAI,KAAK,WAAW,GAAG,GAAG,SAAS,IAAI;CACvC,OAAO;AACT;;AAGA,SAAgB,4BAA4B,MAAc,aAAqB,KAAkB;CAC/F,IAAI,QAAQ,WAAW,IAAI;CAC3B,MAAM,eAAe,YAAY,GAAG;CACpC,IAAI;CACJ,IAAI,MAAM,SAAS,KAAK,MAAM,EAAE,CAAE,WAAW,GAC3C,OAAO,MAAM,SAAS,KAAK,MAAM,EAAE,CAAE,WAAW,GAAG,QAAQ,MAAM,MAAM,CAAC;CAE1E,IAAI,MAAM,SAAS,GACjB,cAAc,WAAW,MAAM,MAAM,SAAS,EAAG;MAEjD,cAAc,WAAW,YAAY,GAAG,CAAC;CAE3C,MAAM,MAAgB,CAAC,YAAY;CACnC,IAAI,WAAW,MAAM,SAAS;CAC9B,IAAI,YAAY,GAAG,WAAW;CAC9B,KAAK,IAAI,QAAQ,GAAG,QAAQ,UAAU,SAAS,GAAG,IAAI,KAAK,WAAW,YAAY,GAAG,CAAC,CAAC;CACvF,IAAI,KAAK,WAAW;CACpB,IAAI,SAAS,IAAI,KAAK,EAAE;CACxB,IAAI,KAAK,WAAW,GAAG,GAAG,SAAS,IAAI;CACvC,OAAO;AACT;AAMA,SAAS,iBAAiB,QAAgB,MAAkC;CAC1E,IAAI,OAAO,SAAS,GAAG,GAAG,QAAQ,OAAO,MAAM,GAAG,CAAC,CAAC,MAAM,MAAM;AAElE;AAEA,SAAS,gBAAgB,QAAgB,MAAc,UAA0B;CAC/E,IAAI,OAAO,SAAS,KAAK,KAAK,SAAS,GAAG,GAAG;EAC3C,IAAI,OAAO,SAAS,GAAG,KAAK,KAAK,WAAW,GAAG,GAAG,QAAQ,OAAO,MAAM,GAAG,CAAC,CAAC,MAAM,MAAM;EACxF,OAAO,SAAS;CAClB;CACA,MAAM,QAAQ,SAAS,MAAM;CAC7B,MAAM,OAAO,SAAS,MAAM,CAAC;CAE7B,OAAO,UADU,YAAY,KAAK,MAAM,EAAE,IAAI,MAAM,YAAY,IAAI,MAAM,YAAY,KAC3D;AAC7B;;AAGA,SAAgB,kBAAkB,MAAc,YAAoB,KAAU,SAA2C;CACvH,IAAI,qBAAqB,IAAI,IAAI,KAAK,QAAQ,eAAe,SAAS,IAAI,GAAG,OAAO;CACpF,MAAM,SAAS,iBAAiB,YAAY,IAAI;CAChD,IAAI,WAAW,KAAA,GAAW,OAAO;CAIjC,OAAO,gBAAgB,YAAY,MAHlB,QAAQ,sBAAsB,IAC3C,aAAa,KAAK,SAAS,GAAG,GAAG,IACjC,yBAAyB,MAAM,YAAY,GAAG,CACD;AACnD;;AAGA,SAAgB,mBAAmB,MAAc,YAAoB,KAAU,SAA2C;CACxH,IAAI,kBAAkB,IAAI,IAAI,KAAK,QAAQ,gBAAgB,SAAS,IAAI,GAAG,OAAO;CAClF,MAAM,SAAS,iBAAiB,YAAY,IAAI;CAChD,IAAI,WAAW,KAAA,GAAW,OAAO;CAIjC,OAAO,gBAAgB,YAAY,MAHlB,QAAQ,sBAAsB,IAC3C,aAAa,KAAK,SAAS,GAAG,GAAG,IACjC,0BAA0B,MAAM,YAAY,GAAG,CACF;AACnD;;AAGA,SAAgB,qBAAqB,MAAc,YAAoB,KAAU,SAA2C;CAC1H,IAAI,oBAAoB,IAAI,IAAI,KAAK,QAAQ,kBAAkB,SAAS,IAAI,GAAG,OAAO;CACtF,MAAM,SAAS,iBAAiB,YAAY,IAAI;CAChD,IAAI,WAAW,KAAA,GAAW,OAAO;CAIjC,OAAO,gBAAgB,YAAY,MAHlB,QAAQ,sBAAsB,IAC3C,aAAa,KAAK,SAAS,GAAG,GAAG,IACjC,4BAA4B,MAAM,YAAY,GAAG,CACJ;AACnD;;AAGA,SAAgB,qBAAqB,MAAc,YAAoB,KAAU,SAA2C;CAC1H,MAAM,SAAS,iBAAiB,YAAY,IAAI;CAChD,IAAI,WAAW,KAAA,GAAW,OAAO;CAIjC,OAAO,gBAAgB,YAAY,MAHlB,QAAQ,sBAAsB,IAC3C,aAAa,KAAK,SAAS,GAAG,GAAG,IACjC,4BAA4B,MAAM,YAAY,GAAG,CACJ;AACnD;;AAWA,SAAgB,qBAAqB,MAA0C;CAC7E,IAAI,CAAC,KAAK,WAAW,QAAQ,GAAG,OAAO,KAAA;CAEvC,MAAM,OADS,KAAK,MAAM,KAAK,CAAC,CAAC,OAAO,OACtB,CAAC,CAAC;CACpB,OAAO,OAAO,EAAE,KAAK,IAAI,KAAA;AAC3B;;AAGA,SAAgB,sBAAsB,MAA2C;CAC/E,MAAM,SAAS,KAAK,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;CACtD,IAAI,OAAO,UAAU,GAAG,OAAO,KAAA;CAC/B,MAAM,aAAa,OAAO;CAC1B,IAAI,CAAC,eAAe,IAAI,UAAU,KAAK,CAAC,kBAAkB,IAAI,UAAU,GAAG,OAAO,KAAA;CAClF,IAAI,KAAK,MAAM,GAAG,CAAC,CAAC,SAAS,MAAM,KAAK,KAAK,MAAM,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,OAAO,KAAA;CACjF,IAAI,KAAK,SAAS,GAAG,GAAG,OAAO,KAAA;CAC/B,MAAM,OAAO,KAAK,QAAQ,GAAG;CAC7B,IAAI,OAAO,GAAG,OAAO,KAAA;CAErB,MAAM,eADe,KAAK,MAAM,GAAG,IACH,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;CAC7D,MAAM,OAAO,aAAa,aAAa,SAAS;CAChD,IAAI,CAAC,QAAQ,iBAAiB,IAAI,GAAG,OAAO,KAAA;CAC5C,IAAI,kBAAkB,IAAI,IAAI,GAAG,OAAO,KAAA;CACxC,IAAI,KAAK,WAAW,KAAK,KAAK,KAAK,SAAS,OAAO,GAAG,OAAO,KAAA;CAC7D,OAAO,EAAE,KAAK;AAChB;;AAGA,SAAgB,wBAAwB,MAA6C;CACnF,IAAI,KAAK,WAAW,IAAI,GAAG,OAAO,KAAA;CAClC,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,QAAQ,WAAW,GAAG,OAAO,KAAA;CAEjC,IAAI,QAAQ,WAAW,QAAQ,KAAK,QAAQ,SAAS,IAAI,GAAG;EAC1D,MAAM,QAAQ,CAAC,GAAG,QAAQ,SAAS,cAAc,CAAC,CAAC,CAAC,KAAI,UAAS,MAAM,EAAG;EAC1E,OAAO,MAAM,SAAS,IAAI;GAAE,MAAM;GAAe;EAAM,IAAI,KAAA;CAC7D;CAEA,IAAI,CAAC,KAAK,WAAW,GAAG,GAAG,OAAO,KAAA;CAClC,IAAI,CAAC,KAAK,SAAS,GAAG,GAAG,OAAO,KAAA;CAEhC,MAAM,SAAS,QAAQ,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;CAClD,IAAI;CAGJ,IADgB,CAAC,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,GACnE;EACX,IAAI,OAAO,SAAS,KAAK,OAAO,SAAS,GAAG,OAAO,KAAA;EACnD,MAAM,QAAQ,OAAO;EACrB,IAAI,CAAC,qBAAqB,IAAI,KAAK,KAAK,CAAC,eAAe,IAAI,KAAK,KAAK,CAAC,kBAAkB,IAAI,KAAK,GAAG,OAAO,KAAA;EAC5G,OAAO,OAAO,OAAO,SAAS;EAC9B,IAAI,SAAS,KAAA,KAAa,KAAK,SAAS,GAAG,GAAG,OAAO,KAAK,MAAM,GAAG,KAAK,QAAQ,GAAG,CAAC;EACpF,IAAI,SAAS,KAAA,MAAc,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,GAAG,IAAI,OAAO,KAAA;EAC9E,IAAI,SAAS,KAAA,MAAc,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,GAAG,IAAI,OAAO,KAAA;CAChF,OAAO;EACL,IAAI,CAAC,KAAK,SAAS,GAAG,GAAG,OAAO,KAAA;EAChC,MAAM,KAAK,KAAK,QAAQ,GAAG;EAC3B,IAAI,KAAK,KAAK,OAAO,OAAO,KAAK,KAAK,OAAO,KAAK,OAAO,KAAA;EAEzD,MAAM,YADM,QAAQ,MAAM,GAAG,CAAC,CAAC,EAAE,CAAE,KACf,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;EACjD,IAAI,UAAU,UAAU,GAAG,OAAO,KAAA;EAClC,OAAO,UAAU,UAAU,SAAS;CACtC;CAEA,IAAI,CAAC,MAAM,OAAO,KAAA;CAClB,OAAO;EAAE,MAAM;EAAe;CAAK;AACrC;;AAOA,SAAgB,uBAAuB,MAAc,MAAc,UAA0B;CAC3F,OAAO,YAAY,MAAM,MAAM,QAAQ;AACzC;;AAGA,SAAgB,wBAAwB,MAAc,MAAc,UAA0B;CAC5F,MAAM,OAAO;CACb,IAAI,OAAO;CACX,IAAI,KAAK,SAAS,IAAI,KAAK,EAAE,GAAG,OAAO,KAAK,MAAM,IAAI,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI;CACxE,IAAI,SAAS,YAAY,MAAM,MAAM,QAAQ;CAC7C,IAAI,OAAO,SAAS,IAAI,GAAG,SAAS,OAAO,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,EAAE;CACvE,OAAO;AACT;;AAGA,SAAgB,0BAA0B,MAAc,MAAc,UAA0B;CAC9F,IAAI,KAAK,WAAW,QAAQ,GAAG,OAAO;CACtC,MAAM,OAAO;CACb,MAAM,SAAS,IAAI,KAAK;CACxB,MAAM,OAAO,GAAG,KAAK;CACrB,MAAM,QAAQ,IAAI,KAAK;CACvB,IAAI,OAAO;CACX,MAAM,YAAY,KAAK,SAAS,IAAI,KAAK,EAAE;CAC3C,MAAM,YAAY,KAAK,SAAS,MAAM;CACtC,MAAM,UAAU,KAAK,SAAS,IAAI;CAClC,MAAM,WAAW,KAAK,SAAS,KAAK;CACpC,IAAI,WAAW,OAAO,KAAK,MAAM,IAAI,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI;CACvD,IAAI,WAAW,OAAO,KAAK,MAAM,MAAM,CAAC,CAAC,KAAK,OAAO,MAAM,CAAC;CAC5D,IAAI,SAAS,OAAO,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC;CACtD,IAAI,UAAU,OAAO,KAAK,MAAM,KAAK,CAAC,CAAC,KAAK,OAAO,KAAK,CAAC;CACzD,IAAI,SAAS,YAAY,MAAM,MAAM,QAAQ;CAC7C,IAAI,OAAO,SAAS,IAAI,GAAG,SAAS,OAAO,MAAM,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,EAAE;CACvE,IAAI,WAAW,SAAS,OAAO,MAAM,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM;CAChE,IAAI,SAAS,SAAS,OAAO,MAAM,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;CAC1D,IAAI,UAAU,SAAS,OAAO,MAAM,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK;CAC7D,OAAO;AACT;;AASA,SAAgB,kBAAkB,MAAc,SAAyC;CACvF,IAAI,UAAyB;CAC7B,MAAM,WAAW,KAAK,KAAK;CAC3B,IAAI,SAAS,SAAS,IAAI,GAAG;EAC3B,MAAM,KAAK,KAAK,QAAQ,IAAI;EAC5B,IAAI,KAAK,SAAS,IAAG,KAAM,KAAK,MAAM,IAAG,CAAC,CAAC,SAAS,MAAO,GAAG;GAC5D,MAAM,QAAQ,KAAK,QAAQ,IAAG;GAE9B,UAAU,KADE,KAAK,QAAQ,MAAK,QAAQ,CACrB,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;EAC3C,OAAO,IAAI,KAAK,SAAS,GAAG,KAAM,KAAK,MAAM,GAAG,CAAC,CAAC,SAAS,MAAO,GAAG;GACnE,MAAM,QAAQ,KAAK,QAAQ,GAAG;GAE9B,UAAU,KADE,KAAK,QAAQ,KAAK,QAAQ,CACrB,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;EAC3C,OACE,UAAU,KAAK,MAAM,GAAG,EAAE;CAE9B,OAAO,IAAI,SAAS,SAAS,IAAI,KAAK,CAAC,SAAS,SAAS,IAAI,GAAG;EAC9D,UAAU,KAAK,MAAM,GAAG,KAAK,QAAQ,IAAI,CAAC;EAC1C,UAAU;CACZ,OAAO,IAAI,CAAC,SAAS,SAAS,IAAI,KAAK,SAAS,SAAS,IAAI,GAAG;EAC9D,UAAU,KAAK,MAAM,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC3C,UAAU;CACZ,OAAO,IAAI,SAAS,SAAS,IAAI,KAAK,SAAS,SAAS,IAAI,GAAG;EAC7D,MAAM,QAAQ,KAAK,QAAQ,IAAI;EAC/B,MAAM,MAAM,KAAK,QAAQ,IAAI,IAAI;EACjC,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG;EAClC,UAAU,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,EAAE;CACpC,OAAO,IAAI,WAAW,CAAC,SAAS,SAAS,IAAI,KAAK,CAAC,SAAS,SAAS,IAAI,GACvE,UAAU;MAEV,UAAU;CAGZ,IAAI,YAAY,MAAM;EACpB,IAAI,QAAQ,QAAQ,MAAM,EAAE,MAAM,IAAI,OAAO;GAAE,MAAM;GAAM;EAAQ;EACnE,OAAO;GAAE,MAAM;GAAS;EAAQ;CAClC;CACA,OAAO;EAAE,MAAM;EAAM;CAAQ;AAC/B;;AAGA,SAAS,YAAY,QAA8D;CACjF,IAAI,WAAW,IAAI,OAAO,CAAC;CAC3B,MAAM,QAAQ,OAAO,MAAM,IAAI;CAC/B,MAAM,SAAuD,CAAC;CAC9D,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GACjD,OAAO,KAAK;EAAE,MAAM,MAAM;EAAS,YAAY,QAAQ,MAAM,SAAS;CAAE,CAAC;CAE3E,IAAI,OAAO,OAAO,SAAS,EAAE,CAAE,SAAS,MAAM,CAAC,OAAO,OAAO,SAAS,EAAE,CAAE,YAAY,OAAO,IAAI;CACjG,OAAO;AACT;;AAGA,SAAgB,mBAAmB,QAAwB;CACzD,MAAM,MAAgB,CAAC;CACvB,IAAI,UAAU;CACd,KAAK,MAAM,EAAE,MAAM,gBAAgB,YAAY,MAAM,GAAG;EACtD,MAAM,SAAS,kBAAkB,MAAM,OAAO;EAC9C,UAAU,OAAO;EACjB,IAAI,OAAO,SAAS,QAAQ,OAAO,KAAK,SAAS,GAAG,IAAI,KAAK,OAAO,QAAQ,aAAa,OAAO,GAAG;CACrG;CACA,OAAO,IAAI,KAAK,EAAE;AACpB;AAMA,MAAM,2CAA2B,IAAI,IAAI;CAAC;CAAO;CAAQ;CAAO;CAAQ;AAAK,CAAC;AAC9E,MAAM,2CAA2B,IAAI,IAAI;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAK,CAAC;AACnF,MAAM,2CAA2B,IAAI,IAAI;CAAC;CAAO;CAAO;CAAO;CAAO;CAAO;AAAM,CAAC;AAEpF,SAAS,cAAc,UAA0B;CAC/C,MAAM,OAAO,SAAS,MAAM,SAAS,YAAY,GAAG,IAAI,CAAC;CACzD,MAAM,MAAM,KAAK,YAAY,GAAG;CAChC,OAAO,MAAM,IAAI,KAAK,KAAK,MAAM,MAAM,CAAC,CAAC,CAAC,YAAY;AACxD;AAEA,SAAS,SAAS,UAA0B;CAC1C,OAAO,SAAS,MAAM,SAAS,YAAY,GAAG,IAAI,CAAC;AACrD;;AAGA,SAAgB,eAAe,UAA2B;CACxD,OAAO,yBAAyB,IAAI,cAAc,QAAQ,CAAC;AAC7D;;AAGA,SAAgB,eAAe,UAA2B;CACxD,OAAO,yBAAyB,IAAI,cAAc,QAAQ,CAAC;AAC7D;;AAGA,SAAgB,eAAe,UAA2B;CACxD,OAAO,yBAAyB,IAAI,cAAc,QAAQ,CAAC;AAC7D;AAEA,MAAM,qBAAqB;CAAC;CAAW;CAAgB;CAAM;AAAe;;AAG5E,SAAgB,gBAAgB,UAA2B;CACzD,OAAO,mBAAmB,MAAK,SAAQ,SAAS,SAAS,IAAI,CAAC;AAChE;AAEA,MAAM,oBAAoB;CAAC;CAAU;CAAU;CAAc;CAAiB;CAAS;CAAc;AAAQ;;AAG7G,SAAgB,eAAe,UAA2B;CACxD,MAAM,YAAY,IAAI;CACtB,OAAO,kBAAkB,MAAK,SAAQ,UAAU,SAAS,IAAI,KAAK,SAAS,SAAS,IAAI,CAAC;AAC3F;AAEA,MAAM,0BAA0B,SAA2B;CACzD,IAAI,KAAK;CACT,IAAI,KAAK;CACT,IAAI,KAAK;CACT,IAAI,KAAK;CACT,IAAI,KAAK;CACT,IAAI,KAAK;AACX;AAEA,MAAM,0BAA0B,SAA2B;CAAC,IAAI,KAAK;CAAI,IAAI,KAAK;CAAI,IAAI,KAAK;AAAE;;AAGjG,SAAgB,8BAA8B,QAAgB,KAA0C;CACtG,OAAO,OAAO,MAAM,IAAI,CAAC,CAAC,KAAI,SAAQ;EACpC,IAAI,SAAS;EACb,KAAK,MAAM,CAAC,MAAM,aAAa,KAC7B,KAAK,MAAM,WAAW,uBAAuB,IAAI,GAC/C,IAAI,OAAO,SAAS,OAAO,GAAG;GAC5B,SAAS,OAAO,MAAM,OAAO,CAAC,CAAC,KAAK,QAAQ,QAAQ,MAAM,QAAQ,CAAC;GACnE;EACF;EAGJ,OAAO;CACT,CAAC,CAAC,CAAC,KAAK,IAAI;AACd;;AAGA,SAAgB,8BAA8B,QAAgB,KAA0C;CACtG,OAAO,OAAO,MAAM,IAAI,CAAC,CAAC,KAAI,SAAQ;EACpC,IAAI,SAAS;EACb,KAAK,MAAM,CAAC,MAAM,aAAa,KAC7B,KAAK,MAAM,WAAW,uBAAuB,IAAI,GAC/C,IAAI,OAAO,SAAS,OAAO,GAAG;GAC5B,SAAS,OAAO,MAAM,OAAO,CAAC,CAAC,KAAK,QAAQ,QAAQ,MAAM,QAAQ,CAAC;GACnE;EACF;EAGJ,OAAO;CACT,CAAC,CAAC,CAAC,KAAK,IAAI;AACd;AAMA,MAAM,iBAAiB;;AAGvB,SAAgB,kBAA0B;CACxC,OAAO;AACT;;AAGA,SAAgB,iBAAiB,QAAgB,KAAkB;CACjE,IAAI,QAAQ,eAAe,KAAK,MAAM,IAAI,IAAI,CAAC;CAC/C,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS,GAAG,SAAS,eAAe,KAAK,MAAM,IAAI,IAAI,CAAC;CAC5F,OAAO,gBAAgB,IAAI;AAC7B;;AAGA,SAAgB,oBAAoB,QAAgB,MAAc,MAAsB;CACtF,MAAM,MAAM,aAAa,WAAW,MAAM,yBAAyB,IAAI,CAAC;CACxE,OAAO,OAAO,OAAO,CAAC,QAAQ,OAAO,KAAK,iBAAiB,GAAG,GAAG,GAAG,QAAQ,CAAC,CAAC;AAChF;;AAOA,SAAgB,YAAY,OAAwB;CAClD,IAAI,MAAM,WAAW,IAAI,OAAO;CAChC,IAAI,CAAC,QAAQ,KAAK,KAAK,KAAK,UAAU,MAAM,YAAY,GAAG,OAAO;CAClE,OAAO,CAAC,gBAAgB,KAAK,KAAK;AACpC;;AAGA,SAAgB,kBAAkB,QAAgB,MAAsB;CACtE,MAAM,sBAAM,IAAI,IAAoB;CACpC,KAAK,MAAM,QAAQ,OAAO,MAAM,IAAI,GAAG;EACrC,IAAI,QAAQ,KAAK,QAAQ,QAAQ,EAAE;EACnC,IAAI,MAAM,UAAU,IAAI,QAAQ,MAAM,MAAM,GAAG,EAAE;EACjD,IAAI,YAAY,KAAK,KAAK,CAAC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,OAAO,WAAW,MAAM,KAAK,CAAC;CACnF;CACA,IAAI,IAAI,SAAS,GAAG,OAAO;CAC3B,IAAI,SAAS;CACb,KAAK,MAAM,CAAC,SAAS,YAAY,KAAK,SAAS,OAAO,MAAM,OAAO,CAAC,CAAC,KAAK,OAAO;CACjF,OAAO;AACT;AAMA,SAAS,UAAU,OAAiC;CAClD,OAAO,MAAM,QAAO,UAAS,MAAM,SAAS,SAAS,OAAO,KAAK,CAAC,eAAe,MAAM,QAAQ,CAAC;AAClG;AAEA,SAAS,WAAW,QAA0B;CAC5C,OAAO,OAAO,MAAM,IAAI;AAC1B;;;;;;;AAQA,SAAS,cACP,OACA,KACA,SACA,UACA,SACA,cACQ;CACR,MAAM,UAAU,UAAU,KAAK;CAC/B,MAAM,sBAAM,IAAI,IAAoB;CACpC,MAAM,OAAiB,CAAC;CAExB,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,SAAS,aAAa,MAAM,UAAU,MAAM;EAClD,KAAK,MAAM,QAAQ,WAAW,MAAM,GAClC,KAAK,MAAM,QAAQ,QAAQ,IAAI,GAAG;GAChC,IAAI,IAAI,IAAI,IAAI,GAAG;GACnB,IAAI,WAAW,SAAS,MAAM,GAAG;GACjC,IAAI,aAAa,MAAM;GACvB,IAAI,KAAK,SAAS,QAAQ,GAAG,WAAW,SAAS,MAAM,GAAG;GAC1D,KAAK,KAAK,QAAQ;GAClB,IAAI,IAAI,MAAM,QAAQ;EACxB;CAEJ;CAEA,IAAI,IAAI,SAAS,GAAG,OAAO;CAC3B,IAAI,UAAU;CACd,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,SAAS,aAAa,MAAM,UAAU,MAAM;EAClD,MAAM,QAAQ,WAAW,MAAM,CAAC,CAAC,KAAI,SAAQ,QAAQ,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI;EAC1E,IAAI,UAAU,UAAU,eAAe,OAAO,KAAK,GAAG;GACpD,WAAW;GACX,aAAa,IAAI,MAAM,QAAQ;EACjC;CACF;CACA,OAAO;AACT;;;;;;;;AAaA,SAAgB,qBAAqB,OAAoB,SAAyB,MAAgC;CAChH,MAAM,OAAO,wBAAwB,OAAO;CAC5C,MAAM,MAAM,aAAa,WAAW,MAAM,SAAS,CAAC;CACpD,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,GAAG,MAAO,EAAE,WAAW,EAAE,WAAW,KAAK,EAAE,WAAW,EAAE,WAAW,IAAI,CAAE;CACzG,MAAM,+BAAe,IAAI,IAAY;CACrC,IAAI,cAAc;CAGlB,IAAI,KAAK,SAAS,UAChB,cAAc,QAAQ,MACpB,SAAQ;EACN,MAAM,QAAQ,wBAAwB,IAAI;EAC1C,IAAI,CAAC,OAAO,OAAO,CAAC;EACpB,OAAO,MAAM,SAAS,gBAAgB,MAAM,QAAQ,CAAC,MAAM,IAAI;CACjE,IACC,MAAM,MAAM,qBAAqB,MAAM,KAAK,YAAY,GAAG,IAAI,IAC/D,MAAM,QAAQ;EACb,IAAI,SAAS;EACb,KAAK,MAAM,CAAC,MAAM,aAAa,KAAK,SAAS,0BAA0B,QAAQ,MAAM,QAAQ;EAC7F,OAAO;CACT,GACA,YAAY;CAIhB,IAAI,KAAK,SAAS,WAChB,cAAc,QAAQ,MACpB,SAAQ;EACN,MAAM,QAAQ,qBAAqB,IAAI;EACvC,OAAO,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC;CACjC,IACC,MAAM,MAAM,kBAAkB,MAAM,KAAK,YAAY,GAAG,IAAI,IAC5D,MAAM,QAAQ;EACb,IAAI,SAAS;EACb,KAAK,MAAM,CAAC,MAAM,aAAa,KAAK,SAAS,uBAAuB,QAAQ,MAAM,QAAQ;EAC1F,OAAO;CACT,GACA,YAAY;CAIhB,IAAI,KAAK,SAAS,QAChB,cAAc,QAAQ,MACpB,SAAQ;EACN,MAAM,QAAQ,sBAAsB,IAAI;EACxC,OAAO,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC;CACjC,IACC,MAAM,MAAM,mBAAmB,MAAM,KAAK,YAAY,GAAG,IAAI,IAC7D,MAAM,QAAQ;EACb,IAAI,SAAS;EACb,KAAK,MAAM,CAAC,MAAM,aAAa,KAAK,SAAS,wBAAwB,QAAQ,MAAM,QAAQ;EAC3F,OAAO;CACT,GACA,YAAY;CAIhB,IAAI,KAAK,SAAS,cAChB,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,CAAC,eAAe,MAAM,QAAQ,KAAK,CAAC,eAAe,MAAM,QAAQ,KAAK,CAAC,eAAe,MAAM,QAAQ,GAAG;EAC3G,IAAI,eAAe,MAAM,QAAQ,GAAG;EACpC,MAAM,SAAS,aAAa,MAAM,QAAQ;EAC1C,MAAM,QAAQ,oBAAoB,QAAQ,MAAM,MAAM,QAAQ;EAC9D,IAAI,MAAM,OAAO,MAAM,GAAG;EAC1B,cAAc,MAAM,UAAU,KAAK;EACnC,aAAa,IAAI,MAAM,QAAQ;CACjC;CAIF,IAAI,KAAK,SAAS,cAAc;EAC9B,MAAM,0BAAU,IAAI,IAAoB;EACxC,MAAM,OAAiB,CAAC;EACxB,MAAM,0BAAU,IAAI,IAAoB;EACxC,KAAK,MAAM,SAAS,QAAQ;GAC1B,IAAI,CAAC,eAAe,MAAM,QAAQ,KAAK,gBAAgB,MAAM,QAAQ,GAAG;GACxE,MAAM,OAAO,SAAS,MAAM,QAAQ;GACpC,MAAM,MAAM,KAAK,QAAQ,GAAG;GAC5B,MAAM,eAAe,MAAM,IAAI,OAAO,KAAK,MAAM,GAAG,GAAG;GACvD,MAAM,eAAe,MAAM,IAAI,KAAK,KAAK,MAAM,KAAK,YAAY,GAAG,IAAI,CAAC;GACxE,IAAI,eAAe,YAAY,GAAG;GAClC,IAAI,CAAC,QAAQ,IAAI,YAAY,GAAG;IAC9B,IAAI,WAAW,qBAAqB,cAAc,KAAK,YAAY,KAAK,IAAI;IAC5E,IAAI,KAAK,SAAS,QAAQ,GAAG,WAAW,qBAAqB,cAAc,KAAK,YAAY,KAAK,IAAI;IACrG,KAAK,KAAK,QAAQ;IAClB,QAAQ,IAAI,cAAc,QAAQ;GACpC;GACA,MAAM,WAAW,QAAQ,IAAI,YAAY;GACzC,MAAM,UAAU,MAAM;GACtB,MAAM,UAAU,QAAQ,MAAM,GAAG,aAAa,GAAG,cAAc,CAAC,CAAC,KAAK,GAAG,SAAS,GAAG,cAAc;GACnG,IAAI,YAAY,SAAS,QAAQ,IAAI,SAAS,OAAO;EACvD;EAGA,KAAK,MAAM,SAAS,QAClB,IAAI,MAAM,SAAS,SAAS,OAAO,GAAG;GACpC,IAAI,MAAM,SAAS,SAAS,IAAI,GAAG;GACnC,MAAM,SAAS,aAAa,MAAM,UAAU,MAAM;GAClD,MAAM,QAAQ,8BAA8B,QAAQ,OAAO;GAC3D,IAAI,UAAU,UAAU,eAAe,OAAO,KAAK,GAAG,aAAa,IAAI,MAAM,QAAQ;EACvF,OAAO,IAAI,MAAM,SAAS,SAAS,OAAO,GAAG;GAC3C,MAAM,SAAS,aAAa,MAAM,UAAU,MAAM;GAClD,MAAM,QAAQ,8BAA8B,QAAQ,OAAO;GAC3D,IAAI,UAAU,UAAU,eAAe,OAAO,KAAK,GAAG,aAAa,IAAI,MAAM,QAAQ;EACvF;EAEF,KAAK,MAAM,CAAC,MAAM,OAAO,SACvB,IAAI;GACF,WAAW,MAAM,EAAE;GACnB,aAAa,IAAI,EAAE;EACrB,QAAQ;GACN,eAAe;EACjB;CAEJ;CAGA,IAAI,KAAK,SAAS,aAChB,KAAK,MAAM,SAAS,UAAU,MAAM,GAAG;EACrC,MAAM,SAAS,aAAa,MAAM,UAAU,MAAM;EAClD,MAAM,QAAQ,mBAAmB,MAAM;EACvC,IAAI,UAAU,UAAU,eAAe,OAAO,KAAK,GAAG,aAAa,IAAI,MAAM,QAAQ;CACvF;CAIF,IAAI,KAAK,SAAS,MAChB,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,CAAC,MAAM,SAAS,SAAS,iBAAiB,GAAG;EACjD,MAAM,SAAS,aAAa,MAAM,UAAU,MAAM;EAClD,MAAM,QAAQ,kBAAkB,QAAQ,IAAI;EAC5C,IAAI,UAAU,UAAU,eAAe,OAAO,KAAK,GAAG,aAAa,IAAI,MAAM,QAAQ;CACvF;CAGF,OAAO;EAAE,SAAS,aAAa;EAAM,cAAc,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK;EAAG;CAAY;AAC3F"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { extension, isImageFile } from "./common.js";
|
|
2
|
+
import { encodePNG, parsePNG } from "./png.js";
|
|
3
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
// src/image-utils.ts
|
|
5
|
+
/** Parse a `#RGB`/`#RRGGBB` hex color into an RGB triple. Throws on malformed input. */
|
|
6
|
+
function hexToRgb(hex) {
|
|
7
|
+
let value = hex.trim();
|
|
8
|
+
if (value.startsWith("#")) value = value.slice(1);
|
|
9
|
+
if (value.length === 3) value = `${value[0]}${value[0]}${value[1]}${value[1]}${value[2]}${value[2]}`;
|
|
10
|
+
if (!/^[0-9a-f]{6}$/i.test(value)) throw new Error(`Invalid hex color: ${hex}`);
|
|
11
|
+
return [
|
|
12
|
+
parseInt(value.slice(0, 2), 16),
|
|
13
|
+
parseInt(value.slice(2, 4), 16),
|
|
14
|
+
parseInt(value.slice(4, 6), 16)
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The original `colour_distance`: redmean-weighted RGB distance.
|
|
19
|
+
* value = sqrt((2 + rmean/256)*R^2 + 4*G^2 + (2 + (255 - rmean)/256)*B^2).
|
|
20
|
+
*/
|
|
21
|
+
function colourDistance(rgb1, rgb2) {
|
|
22
|
+
const rmean = (rgb1[0] + rgb2[0]) / 2;
|
|
23
|
+
const r = rgb1[0] - rgb2[0];
|
|
24
|
+
const g = rgb1[1] - rgb2[1];
|
|
25
|
+
const b = rgb1[2] - rgb2[2];
|
|
26
|
+
return Math.sqrt((2 + rmean / 256) * r * r + 4 * g * g + (2 + (255 - rmean) / 256) * b * b);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The original `color_acquaintance_compare`: true when every channel of `pixel`
|
|
30
|
+
* is within `tolerance` absolute distance of the corresponding `target` channel.
|
|
31
|
+
*/
|
|
32
|
+
function colorAcquaintanceCompare(target, pixel, tolerance) {
|
|
33
|
+
for (let index = 0; index < 3; index += 1) if (Math.abs(target[index] - pixel[index]) > tolerance) return false;
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/** Parse a hex color map (target -> replacement) preserving insertion order. */
|
|
37
|
+
function parseColorMap(colorMap) {
|
|
38
|
+
const rules = [];
|
|
39
|
+
for (const [target, replace] of Object.entries(colorMap)) rules.push({
|
|
40
|
+
from: hexToRgb(target),
|
|
41
|
+
to: hexToRgb(replace)
|
|
42
|
+
});
|
|
43
|
+
return rules;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Faithful port of the `exchange_image_colors` inner loop: for a single pixel,
|
|
47
|
+
* apply every rule whose `from` matches within `tolerance`; the last matching rule
|
|
48
|
+
* (in map insertion order) wins. Returns the replacement RGB, or undefined.
|
|
49
|
+
*/
|
|
50
|
+
function pickReplacement(r, g, b, map, tolerance) {
|
|
51
|
+
const pixel = [
|
|
52
|
+
r,
|
|
53
|
+
g,
|
|
54
|
+
b
|
|
55
|
+
];
|
|
56
|
+
let chosen;
|
|
57
|
+
for (const [target, replace] of Object.entries(map)) if (colorAcquaintanceCompare(hexToRgb(target), pixel, tolerance)) chosen = hexToRgb(replace);
|
|
58
|
+
return chosen;
|
|
59
|
+
}
|
|
60
|
+
/** Recolor pixels in place using parsed rules; transparent pixels are skipped. Returns whether anything changed. */
|
|
61
|
+
function applyRules(pixels, rules, tolerance) {
|
|
62
|
+
let modified = false;
|
|
63
|
+
for (let index = 0; index < pixels.length; index += 4) {
|
|
64
|
+
if (pixels[index + 3] === 0) continue;
|
|
65
|
+
const pixel = [
|
|
66
|
+
pixels[index],
|
|
67
|
+
pixels[index + 1],
|
|
68
|
+
pixels[index + 2]
|
|
69
|
+
];
|
|
70
|
+
let chosen;
|
|
71
|
+
for (const rule of rules) if (colorAcquaintanceCompare(rule.from, pixel, tolerance)) chosen = rule.to;
|
|
72
|
+
if (!chosen) continue;
|
|
73
|
+
if (chosen[0] !== pixels[index] || chosen[1] !== pixels[index + 1] || chosen[2] !== pixels[index + 2]) modified = true;
|
|
74
|
+
pixels[index] = chosen[0];
|
|
75
|
+
pixels[index + 1] = chosen[1];
|
|
76
|
+
pixels[index + 2] = chosen[2];
|
|
77
|
+
}
|
|
78
|
+
return modified;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Recolor owned PNGs by a hex color map (`#target -> #replace`). Non-PNG images and
|
|
82
|
+
* undecodable PNGs are reported as unsupported, never corrupted. `seed` is reserved
|
|
83
|
+
* for parity with the other transform modules; the mapping itself is deterministic.
|
|
84
|
+
*/
|
|
85
|
+
function recolorImagesByMap(files, colorMap, tolerance = 20, seed = "") {
|
|
86
|
+
const rules = parseColorMap(colorMap);
|
|
87
|
+
const changedPaths = [];
|
|
88
|
+
let changed = 0;
|
|
89
|
+
let unsupported = 0;
|
|
90
|
+
for (const entry of files) {
|
|
91
|
+
if (!isImageFile(entry.relative)) continue;
|
|
92
|
+
if (extension(entry.relative) !== "png") {
|
|
93
|
+
unsupported += 1;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const before = readFileSync(entry.absolute);
|
|
97
|
+
const decoded = parsePNG(before);
|
|
98
|
+
if (!decoded) {
|
|
99
|
+
unsupported += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!applyRules(decoded.pixels, rules, tolerance)) continue;
|
|
103
|
+
const next = encodePNG(before, decoded);
|
|
104
|
+
if (!next || next.equals(before)) {
|
|
105
|
+
unsupported += 1;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
writeFileSync(entry.absolute, next);
|
|
109
|
+
changed += 1;
|
|
110
|
+
changedPaths.push(entry.relative);
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
changed,
|
|
114
|
+
changedPaths,
|
|
115
|
+
unsupported
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Overwrite every non-transparent pixel's RGB with `color` (same_color). Returns whether anything changed. */
|
|
119
|
+
function recolorSolidPixels(pixels, color) {
|
|
120
|
+
let modified = false;
|
|
121
|
+
for (let index = 0; index < pixels.length; index += 4) {
|
|
122
|
+
if (pixels[index + 3] === 0) continue;
|
|
123
|
+
if (pixels[index] !== color[0] || pixels[index + 1] !== color[1] || pixels[index + 2] !== color[2]) modified = true;
|
|
124
|
+
pixels[index] = color[0];
|
|
125
|
+
pixels[index + 1] = color[1];
|
|
126
|
+
pixels[index + 2] = color[2];
|
|
127
|
+
}
|
|
128
|
+
return modified;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Replace every non-transparent pixel of owned PNGs with one color
|
|
132
|
+
* (port of `exchange_image_colors_same_color`).
|
|
133
|
+
*/
|
|
134
|
+
function recolorImagesSolid(files, color, seed = "") {
|
|
135
|
+
const rgb = hexToRgb(color);
|
|
136
|
+
const changedPaths = [];
|
|
137
|
+
let changed = 0;
|
|
138
|
+
let unsupported = 0;
|
|
139
|
+
for (const entry of files) {
|
|
140
|
+
if (!isImageFile(entry.relative)) continue;
|
|
141
|
+
if (extension(entry.relative) !== "png") {
|
|
142
|
+
unsupported += 1;
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const before = readFileSync(entry.absolute);
|
|
146
|
+
const decoded = parsePNG(before);
|
|
147
|
+
if (!decoded) {
|
|
148
|
+
unsupported += 1;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (!recolorSolidPixels(decoded.pixels, rgb)) continue;
|
|
152
|
+
const next = encodePNG(before, decoded);
|
|
153
|
+
if (!next || next.equals(before)) {
|
|
154
|
+
unsupported += 1;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
writeFileSync(entry.absolute, next);
|
|
158
|
+
changed += 1;
|
|
159
|
+
changedPaths.push(entry.relative);
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
changed,
|
|
163
|
+
changedPaths,
|
|
164
|
+
unsupported
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Center-aligned bilinear (or nearest-neighbor) RGBA resampling. Bilinear is the
|
|
169
|
+
* default and mirrors PIL's `Image.BILINEAR`; it is per-channel and edge-clamped,
|
|
170
|
+
* not bit-identical to Pillow's triangle-kernel affine transform.
|
|
171
|
+
*/
|
|
172
|
+
function scalePixels(pixels, srcWidth, srcHeight, dstWidth, dstHeight, interpolation = "bilinear") {
|
|
173
|
+
if (srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) throw new Error("Image dimensions must be positive");
|
|
174
|
+
if (pixels.length !== srcWidth * srcHeight * 4) throw new Error(`Pixel buffer length ${pixels.length} does not match ${srcWidth}x${srcHeight} RGBA`);
|
|
175
|
+
const out = new Uint8Array(dstWidth * dstHeight * 4);
|
|
176
|
+
if (srcWidth === dstWidth && srcHeight === dstHeight) {
|
|
177
|
+
out.set(pixels);
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
const xRatio = srcWidth / dstWidth;
|
|
181
|
+
const yRatio = srcHeight / dstHeight;
|
|
182
|
+
for (let dy = 0; dy < dstHeight; dy += 1) for (let dx = 0; dx < dstWidth; dx += 1) {
|
|
183
|
+
const di = (dy * dstWidth + dx) * 4;
|
|
184
|
+
if (interpolation === "nearest") {
|
|
185
|
+
const sx = Math.min(srcWidth - 1, Math.floor(dx * xRatio));
|
|
186
|
+
const si = (Math.min(srcHeight - 1, Math.floor(dy * yRatio)) * srcWidth + sx) * 4;
|
|
187
|
+
out[di] = pixels[si];
|
|
188
|
+
out[di + 1] = pixels[si + 1];
|
|
189
|
+
out[di + 2] = pixels[si + 2];
|
|
190
|
+
out[di + 3] = pixels[si + 3];
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const cx = Math.min(srcWidth - 1, Math.max(0, (dx + .5) * xRatio - .5));
|
|
194
|
+
const cy = Math.min(srcHeight - 1, Math.max(0, (dy + .5) * yRatio - .5));
|
|
195
|
+
const sx0 = Math.floor(cx);
|
|
196
|
+
const sy0 = Math.floor(cy);
|
|
197
|
+
const sx1 = Math.min(srcWidth - 1, sx0 + 1);
|
|
198
|
+
const sy1 = Math.min(srcHeight - 1, sy0 + 1);
|
|
199
|
+
const u = cx - sx0;
|
|
200
|
+
const v = cy - sy0;
|
|
201
|
+
for (let channel = 0; channel < 4; channel += 1) {
|
|
202
|
+
const p00 = pixels[(sy0 * srcWidth + sx0) * 4 + channel];
|
|
203
|
+
const p10 = pixels[(sy0 * srcWidth + sx1) * 4 + channel];
|
|
204
|
+
const p01 = pixels[(sy1 * srcWidth + sx0) * 4 + channel];
|
|
205
|
+
const p11 = pixels[(sy1 * srcWidth + sx1) * 4 + channel];
|
|
206
|
+
const top = p00 * (1 - u) + p10 * u;
|
|
207
|
+
const bottom = p01 * (1 - u) + p11 * u;
|
|
208
|
+
out[di + channel] = Math.round(top * (1 - v) + bottom * v);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
213
|
+
/** Resolve the output size from `options`, clamping to at least 1px on each axis. */
|
|
214
|
+
function resolveScaleSize(srcWidth, srcHeight, options) {
|
|
215
|
+
let width = options.width;
|
|
216
|
+
let height = options.height;
|
|
217
|
+
if (width !== void 0 && height !== void 0) {} else if (options.scale !== void 0) {
|
|
218
|
+
if (options.scale <= 0) throw new Error("scale must be positive");
|
|
219
|
+
width = Math.round(srcWidth * options.scale);
|
|
220
|
+
height = Math.round(srcHeight * options.scale);
|
|
221
|
+
} else if (width !== void 0) height = Math.round(srcHeight * (width / srcWidth));
|
|
222
|
+
else if (height !== void 0) width = Math.round(srcWidth * (height / srcHeight));
|
|
223
|
+
else {
|
|
224
|
+
width = srcWidth;
|
|
225
|
+
height = srcHeight;
|
|
226
|
+
}
|
|
227
|
+
return {
|
|
228
|
+
width: Math.max(1, Math.round(width)),
|
|
229
|
+
height: Math.max(1, Math.round(height))
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Scale owned PNGs to a target size, ratio, or factor. Non-PNG images and
|
|
234
|
+
* undecodable PNGs are reported as unsupported.
|
|
235
|
+
*/
|
|
236
|
+
function scaleImages(files, options) {
|
|
237
|
+
const changedPaths = [];
|
|
238
|
+
let changed = 0;
|
|
239
|
+
let unsupported = 0;
|
|
240
|
+
for (const entry of files) {
|
|
241
|
+
if (!isImageFile(entry.relative)) continue;
|
|
242
|
+
if (extension(entry.relative) !== "png") {
|
|
243
|
+
unsupported += 1;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const before = readFileSync(entry.absolute);
|
|
247
|
+
const decoded = parsePNG(before);
|
|
248
|
+
if (!decoded) {
|
|
249
|
+
unsupported += 1;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
const { width, height } = resolveScaleSize(decoded.width, decoded.height, options);
|
|
253
|
+
if (width === decoded.width && height === decoded.height) continue;
|
|
254
|
+
const pixels = scalePixels(decoded.pixels, decoded.width, decoded.height, width, height, options.interpolation ?? "bilinear");
|
|
255
|
+
const next = encodePNG(before, {
|
|
256
|
+
width,
|
|
257
|
+
height,
|
|
258
|
+
pixels
|
|
259
|
+
});
|
|
260
|
+
if (!next || next.equals(before)) {
|
|
261
|
+
unsupported += 1;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
writeFileSync(entry.absolute, next);
|
|
265
|
+
changed += 1;
|
|
266
|
+
changedPaths.push(entry.relative);
|
|
267
|
+
}
|
|
268
|
+
return {
|
|
269
|
+
changed,
|
|
270
|
+
changedPaths,
|
|
271
|
+
unsupported
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Composite RGBA pixels onto a solid background (`remove_transparency`): each pixel
|
|
276
|
+
* becomes `src * (a/255) + bg * (1 - a/255)` and is set fully opaque. The alpha
|
|
277
|
+
* channel is retained as 255 because this package's PNG encoder emits color type 6
|
|
278
|
+
* (RGBA); the resulting image is visually identical to PIL's RGB output.
|
|
279
|
+
*/
|
|
280
|
+
function flattenPixels(pixels, bgColor) {
|
|
281
|
+
const out = new Uint8Array(pixels.length);
|
|
282
|
+
const [br, bg, bb] = bgColor;
|
|
283
|
+
for (let index = 0; index < pixels.length; index += 4) {
|
|
284
|
+
const alpha = pixels[index + 3] / 255;
|
|
285
|
+
out[index] = Math.round(pixels[index] * alpha + br * (1 - alpha));
|
|
286
|
+
out[index + 1] = Math.round(pixels[index + 1] * alpha + bg * (1 - alpha));
|
|
287
|
+
out[index + 2] = Math.round(pixels[index + 2] * alpha + bb * (1 - alpha));
|
|
288
|
+
out[index + 3] = 255;
|
|
289
|
+
}
|
|
290
|
+
return out;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Flatten owned PNGs' alpha onto a background color, removing transparency.
|
|
294
|
+
* Non-PNG images and undecodable PNGs are reported as unsupported.
|
|
295
|
+
*/
|
|
296
|
+
function flattenTransparency(files, bgColor = [
|
|
297
|
+
255,
|
|
298
|
+
255,
|
|
299
|
+
255
|
|
300
|
+
]) {
|
|
301
|
+
const changedPaths = [];
|
|
302
|
+
let changed = 0;
|
|
303
|
+
let unsupported = 0;
|
|
304
|
+
for (const entry of files) {
|
|
305
|
+
if (!isImageFile(entry.relative)) continue;
|
|
306
|
+
if (extension(entry.relative) !== "png") {
|
|
307
|
+
unsupported += 1;
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
const before = readFileSync(entry.absolute);
|
|
311
|
+
const decoded = parsePNG(before);
|
|
312
|
+
if (!decoded) {
|
|
313
|
+
unsupported += 1;
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const pixels = flattenPixels(decoded.pixels, bgColor);
|
|
317
|
+
const next = encodePNG(before, {
|
|
318
|
+
width: decoded.width,
|
|
319
|
+
height: decoded.height,
|
|
320
|
+
pixels
|
|
321
|
+
});
|
|
322
|
+
if (!next || next.equals(before)) continue;
|
|
323
|
+
writeFileSync(entry.absolute, next);
|
|
324
|
+
changed += 1;
|
|
325
|
+
changedPaths.push(entry.relative);
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
changed,
|
|
329
|
+
changedPaths,
|
|
330
|
+
unsupported
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
export { colorAcquaintanceCompare, colourDistance, flattenPixels, flattenTransparency, hexToRgb, parseColorMap, pickReplacement, recolorImagesByMap, recolorImagesSolid, recolorSolidPixels, resolveScaleSize, scaleImages, scalePixels };
|
|
334
|
+
|
|
335
|
+
//# sourceMappingURL=image-utils.js.map
|