/** * Randomly pop an element from the given array, and return it. Will modify the original array. * @param {*}arr The array * @returns {*}The popped element */ functionarrRandomPop(arr) { const index = Math.floor(Math.random() * arr.length); return arr.splice(index, 1)[0]; }
/** * Get specified count of random characters from the given list, excluding the characters in the except list * @param { string[] }charList The list of characters * @param { number }count The count of characters to get * @param { string[] }exceptList The list of characters to exclude * @returns { string } */ functiongetRandomCharsFromList(charList, count, exceptList = []) { const charSet = newSet(charList); const result = []; while (result.length < count) { const index = Math.floor(Math.random() * charSet.size); const randomChar = Array.from(charSet)[index]; if (exceptList.includes(randomChar)) { continue; } result.push(randomChar); charSet.delete(randomChar); } return result; }
/** * @typedef { Object }IObfuscatePlusParams * @property { string }originalText The original text that need to obfuscate * @property { 'low' | 'middle' | 'high' | 'all' }obfuscateLevel The level of obfuscation * @property { string }fontName The name of the font family * @property { string }fontFilename The name of the output font file */
/** * Obfuscate a font by replacing the paths of glyphs with the paths of other glyphs * * @param { IObfuscatePlusParams }params * @returns { Promise<{ obfuscatedText: string, fontFilePath: string, obfuscatedMap: { [key: string]: string }}> } */ functionobfuscateRandom(params) { const { originalText, obfuscateLevel, fontName, fontFilename } = params; const allCharsSet = newSet(originalText); const levelMap = { low: 0.3, middle: 0.5, high: 0.7, all: 1 }; const countOfLevel = Math.round(allCharsSet.size * levelMap[obfuscateLevel]); const count = Math.min(countOfLevel, frequentlyUsedCnChar.length);
const obfuscatedGlyphs = finalObfuscateList.map(item => { const { displayChar, obfuscatedChar } = item; // Get the glyph for the display character and the obfuscated character const displayGlyph = font.charToGlyph(displayChar); const obfuscatedGlyph = font.charToGlyph(obfuscatedChar); // Clone the obfuscated glyph and replace its path with the display glyph's path const cloneObfuscatedGlyph = Object.assign( Object.create(Object.getPrototypeOf(obfuscatedGlyph)), obfuscatedGlyph ); cloneObfuscatedGlyph.path = displayGlyph.path; cloneObfuscatedGlyph.name = displayChar; return cloneObfuscatedGlyph; });
// This .notdef glyph is required, it's used for characters that doesn't have a glyph in the font const notDefGlyph = new opentype.Glyph({ name: '.notdef', advanceWidth: 650, path: new opentype.Path(), });
// Create a new font object with the obfuscated glyphs const newFont = new opentype.Font({ familyName: fontName, styleName: 'Regular', unitsPerEm: font.unitsPerEm, ascender: font.ascender, descender: font.descender, glyphs: [notDefGlyph, ...obfuscatedGlyphs], });
// Save the new font to a file const outputFilePath = path.resolve(OUTPUT_PATH, `${fontFilename}.ttf`); const buffer = newFont.toArrayBuffer(); fs.writeFileSync(outputFilePath, Buffer.from(buffer)); resolve({ obfuscatedText, fontFilePath: outputFilePath, obfuscatedMap: finalMap, }); }); }); }
const PORT = process.env.PORT || 3007; app.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); console.log(`http://localhost:${PORT}`); console.log(`http://127.0.0.1:${PORT}`); });
const PORT = process.env.PORT || 3007; app.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); console.log(`http://localhost:${PORT}`); console.log(`http://127.0.0.1:${PORT}`); });
# You can use comments to explain the rules. Rules themselves follow the # following syntax: matcher:expression -> list of values # The list of values can be hardcoded or substituted values.
functionmakeRequest(method, path, options) { return fetch(method, path, options).catch(function(err) { Sentry.withScope(function(scope) { // group errors together based on their request and response scope.setFingerprint([method, path, String(err.statusCode)]); Sentry.captureException(err); }); }); }
type ColorSchemeName = 'light' | 'dark' | null | undefined;
exportnamespace Appearance { type AppearancePreferences = { colorScheme: ColorSchemeName; };
type AppearanceListener = (preferences: AppearancePreferences) =>void;
/** * Note: Although color scheme is available immediately, it may change at any * time. Any rendering logic or styles that depend on this should try to call * this function on every render, rather than caching the value (for example, * using inline styles rather than setting a value in a `StyleSheet`). * * Example: `const colorScheme = Appearance.getColorScheme();` */ exportfunctiongetColorScheme(): ColorSchemeName;
/** * Add an event handler that is fired when appearance preferences change. */ exportfunctionaddChangeListener(listener: AppearanceListener): EventSubscription;
/** * A new useColorScheme hook is provided as the preferred way of accessing * the user's preferred color scheme (aka Dark Mode). */ exportfunctionuseColorScheme(): ColorSchemeName;
通过Appearance模块,可以获得当前的系统颜色主题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
const colorScheme = Appearance.getColorScheme(); if (colorScheme === 'dark') { // dark mode } else { // light mode }
Appearance.addChangeListener((prefer: Appearance.AppearancePreferences) => { if (prefer.colorScheme === 'dark') { // dark mode } else { // light mode } });
Also make sure you do not have UIUserInterfaceStyle set in your Info.plist. I had it set to ‘light’ so Appearance.getColorScheme() was always returning ‘light’.
When using the factory parameter for an ES6 module with a default export, the __esModule: true property needs to be specified. This property is normally generated by Babel / TypeScript, but here it needs to be set manually. When importing a default export, it’s an instruction to import the property named default from the export object