Changelog
Each package versions on its own, so each keeps a changelog of its own. Pick a language in the sidebar to read it.
1.19.0 (2026-09-12)
Breaking changes
sortNumeric,sortByObjectKey: The order no longer depends on the machine or on the package. A string is cut into runs of digits and runs of everything else, and the runs are compared in three passes over the whole string: the letters, then the accents on them, then upper against lower case. Whitespace sorts before punctuation, punctuation before numbers and numbers before letters, and a run of digits is compared by length before value, so a number too long for a number type still sorts correctly. The three packages now return the same order for the same input, which they never did.Intl.Collatorused to decide it here, with an empty locale list, so the same array came back in a different order on a machine set to Swedish than on one set to English, and neither Dart nor Python matched either. Ordinary lists of file names and labels are unaffected, the ordering being identical to whatIntl.Collatorproduced for them; a string starting with punctuation is where the two part company. Sort withIntl.Collatoryourself if you need the collation of one named locale
Changes
durationParts: Added. Breaks a duration into its units and hands them back as{ value, unit }rather than a string, so a duration can be written in a language this package does not know.durationlabels the units in English and builds the plural by adding ans, which is a rule only English follows: Polish has three plural forms and Arabic six.Intl.DurationFormatturns the pieces into14 Tage, 6 Stunden, 56 Minuten und 7 Sekunden. It takes the options ofdurationthat decide which units are used, anddurationis now built on it, so the two cannot disagreefileSizeParts: Added. Splits a file size in bytes into the scaled number and the unit it belongs to, and hands both back rather than a string, so a size can be written in a language this package does not know.Intl.NumberFormatturns{ value: 1.177, exponent: 2 }into1,18 MBin German and1,18 Moin French, which no arrangement of the old return value could produce. The value is deliberately left unrounded, so the caller's own formatter rounds it once instead of rounding an already rounded numberfileSizeFormat: Two options were added as a fourth argument.standardpicks the divisor and the unit names:jedec(the default) divides by 1024 and writesKBas it always has,iecdivides by 1024 and writesKiB, andsidivides by 1000 and writeskB.unitDisplaywrites the unit as an abbreviation (1.18 MB) or as a whole word (1.18 Megabytes), taking the singular when the rounded number is one. Leaving both out returns exactly the string it returned before, which the tests now pinfileSizeFormat: A size past the largest unit no longer runs off the end of the unit table.fileSizeFormat(1024 ** 9)returned1 undefined, where the Dart and Python packages threw on the same input; the exponent is now held at the last unit, so it reads1024 YB
1.18.0 (2026-08-29)
- The package is now declared side-effect free, and the lookup tables that
deburr,hasBadWords,sortNumeric,sortByObjectKeyandnumberFormatused to build at import time are built on the first call that needs them instead. A bundler has to keep any module that runs code when it is loaded, soimport { arrUnique } from 'qsu'dragged twoIntl.Collatorinstances, anIntl.NumberFormatand thedeburrandhasBadWordstables along with it. Bundling a single function with esbuild now comes to 251 bytes rather than 2665, and importing the package in Node costs 22.7ms rather than 33.2ms. This changes no behavior and no API - Every category now has a subpath export of its own:
qsu/array,qsu/date,qsu/format,qsu/math,qsu/misc,qsu/object,qsu/string,qsu/verifyandqsu/web, plusqsu/node/crypto,qsu/node/file,qsu/node/misc,qsu/node/netandqsu/node/osunder the Node.js runtime. Only.,./typesand./nodewere reachable before, so anything not running a bundler had to load the whole root barrel (171 modules, 33.2ms in Node) to reach one function, whereqsu/arraycosts 7.4ms.qsu/package.jsonis exported as well, for tools that read it qsu/typesnow resolves. The subpath pointed at./dist/types/global.*while the build emits./dist/_types/global.*, so bothimport 'qsu/types'and the type-onlyimport type { SlugOptions } from 'qsu/types'failedtruncate,truncateExpect: The length is now counted in code points, aspadalready did, so a character outside the Basic Multilingual Plane counts as one in every language. A JavaScript string is indexed in UTF-16 units, sotruncate('a👋b', 2)used to cut between the two halves of the emoji and hand back a broken character, andtruncateExpectstopped at a different sentence than Python did on the same texttruncateExpect:endStringCharnow takes an array as well as a single string, and defaults to the full stop as each script writes it (.,。,.,。). Japanese and Chinese text used to come back untouched, because a text with no ASCII.in it split into one piece and the expected length was never reached.!and?are left out of the default on purpose, so that the same sentence is not split differently depending on the script it is written in. A longer ending character is matched before a shorter one, so.next to...no longer cuts...short
1.17.0 (2026-08-07)
unescapeHtml: Added. Turns the five entitiesescapeHtmlproduces back into their characters. The string is walked once rather than replaced five times in a row, so&lt;comes back as the literal text<instead of being unescaped twice, and only those five entities are recognised, so and'are left as they areescapeHtml: Added. Escapes&,<,>,"and'so a value can be dropped into a page as text rather than read as markup.'is written as'rather than', which HTML 4 never defined. It lives in thewebcategory, next togetSlug, and leavesescapeRegExpas the pattern-oriented oneobjClone: Added. Copies an object, deeply by default and top level only withdeep: false. Plain objects, arrays,MapandSetare rebuilt with their contents copied,DateandRegExpget a fresh copy, and a function or class instance is handed back as it is. A structure that points back at itself is rebuilt with the same shape rather than recursing until the stack runs outobjMerge: Added. Merges any number of objects into one new object, going down through nested objects, with the later source winning. Two plain objects under the same key are merged into a new object, so neither source is shared with the result or modified. Arrays are replaced whole rather than merged index by index as Lodash does, andnullNoneis returned when an argument is not an objectobjGet: Added. Reads a nested value out of an object by dot and/or bracket path (a.b.c,list[0],list[1].d), returning thefallbackwhen the path is not there. A bracket may carry a quoted key, so["a.b"]reads one key rather than walking two levels, and a storednullNonecounts as a value rather than a missing pathobjPick: Added. Returns a new object containing only the listed keys, accepting a single key or an array of keys. Only the top level is inspected, and a key the object does not have is skipped rather than carried over asundefinedpad: Added. Pads a string until it reaches the given length, with onepositionoption (start,endorboth) covering what Lodash splits acrosspad,padStartandpadEnd.bothis the default and gives the extra character to the end, a multi-charactercharis repeated and truncated, and the length is counted in code points so an emoji counts as one in every languagestrToConstantCase: Added. Converts a string toCONSTANT_CASE, uppercasing every word and joining them with an underscore. It splits withwords, soXMLHttpRequestbecomesXML_HTTP_REQUEST. JavaScript and Python apply the full Unicode case mapping where Dart applies the simple one, sostraßebecomesSTRASSEhere andSTRAßEin Dart, which the documentation states rather than papering overstrToPascalCase: Added. Converts a string toPascalCase, giving every word an uppercase first letter and a lowercase rest. It splits withwords, soXMLHttpRequestbecomesXmlHttpRequest.capitalizeEachWordsstays the one that keeps the original separatorsstrToKebabCase: Added. Converts a string tokebab-case, lowercasing every word and joining them with a hyphen. It splits withwords, soXMLHttpRequestbecomesxml-http-request.getSlugstays the URL-oriented onestrToSnakeCase: Added. Converts a string tosnake_case, lowercasing every word and joining them with an underscore. It splits withwords, soXMLHttpRequestbecomesxml_http_requestandabc12defbecomesabc_12_defstrToCamelCase: Added. Converts a string tocamelCase, lowercasing the first word and giving every word after it an uppercase first letter. It splits withwords, so an acronym stays whole (XMLHttpRequestbecomesxmlHttpRequest) and a run of digits is its own word (abc12defbecomesabc12Def)min: Added. Returns the smallest of the given numbers, accepting either n arguments or a single array exactly likesum. Values that are not numbers are skipped, and so isNaN, which would otherwise win by losing every comparison. An empty input returnsnullNonemax: Added. Returns the largest of the given numbers, accepting either n arguments or a single array exactly likesum. Values that are not numbers are skipped, and so isNaN, which would otherwise win by losing every comparison. An empty input returnsnullNonefloor: Added. Rounds a number down, to the given number of decimal places, a negative precision rounding down to tens, hundreds and so on. Rounding goes toward negative infinity, sofloor(-4.006)is-5. The value is shifted through its shortest string representation, sofloor(1.1, 1)is1.1ceil: Added. Rounds a number up, to the given number of decimal places, a negative precision rounding up to tens, hundreds and so on. Rounding goes toward positive infinity, soceil(-4.006)is-4. The value is shifted through its shortest string representation, soceil(1.1, 1)is1.1and not1.2round: Added. Rounds a number to the given number of decimal places, a negative precision rounding to tens, hundreds and so on. Ties go away from zero in every language, where the three disagree natively (0.5is1/1/0and-1.5is-1/-2/-2in JavaScript/Dart/Python) and where Lodash sends them toward positive infinity. The value is shifted through its shortest string representation rather than multiplied by a power of ten, soround(1.005, 2)is1.01and not1clamp: Added. Restricts a number to an inclusive range, returningminbelow it andmaxabove it. The upper bound is applied first, sominwins when the two are passed the wrong way round, matching Lodash rather than Dart'snum.clamp, which throws
1.16.0 (2026-08-04)
retry: Added. Runs the given function again on failure until it succeeds or the attempts run out, raising the last error if they all fail.timescounts total attempts (default3),delaywaits between them andbackoffmultiplies that wait after each failurethrottle: Added. Limits how often a function may run to at most once perwaitwindow, the counterpart ofdebounce.leadingandtrailing(bothtrueTrueby default) choose which edge of the window runsobjInvert: Added. Returns a new object with the keys and values swapped. Values are converted to text because keys are always strings, and the later entry wins when two share a valueobjMapKeys: Added. Returns a new object whose keys are the values returned by the callback, with the values carried over untouched. The callback receives(value, key), and the later key wins when two map onto the same nameobjPickBy: Added. Returns a new object containing only the entries for which the callback returnstrueTrue. The callback receives(value, key), and only the top level is inspecteduncapitalizeFirst: Added. Converts the first letter of the entire string to lowercase, the inverse ofcapitalizeFirst. Only the first character is touched, soTESTbecomestESTescapeRegExp: Added. Escapes every regular expression metacharacter (^ $ . * + ? ( ) [ ] { } |and\) so a value can be matched literally.-and#are left alone: they are special only inside a character class, and\-outside one is a syntax error in unicode modedeburr: Added. Replaces accented Latin letters with their unaccented equivalents (déjà vubecomesdeja vu), spelling outÆ,ß,Þ,ŒandIJ, and dropping combining marks. Covers the Latin-1 Supplement and Latin Extended-A blockswords: Added. Splits a string into the words it is made of. Anything that is neither a letter nor a digit separates words, and camelCase boundaries, runs of capitals (XMLHttpRequestisXML,Http,Request) and runs of digits are split as wellarrIntersection: Added. Returns the values that are present in every one of the given arrays. The result is unique and keeps the order of the first arrayarrDifference: Added. Returns the values of the first array that are not contained in any of the other arrays. Values are compared by value rather than by reference, so nested arrays and objects are matched as wellarrCompact: Added. Returns a new array with every falsy value removed (nullNone,undefined,falseFalse,0,'',NaN). Empty arrays and objects are truthy and are kept
1.15.0 (2026-08-02)
- BREAKING CHANGES:
isValidFileNamenow rejects an empty name and any name carrying a control character (U+0000-U+001ForU+007F).NULis the one that matters: it terminates the path in the system call underneath every filesystem, so a name carrying one was reported as valid and then silently truncated on the way to disk - BREAKING CHANGES:
isValidFileNamenow rejects a name ending in a dot or a space on the Windows path. Windows strips it instead of reporting an error, soreport.quietly becomesreportand overwrites it. Unix keeps them, so they stay valid withunixType - BREAKING CHANGES:
isValidFileNamenow measures its 255 limit in UTF-8 bytes rather than characters, which is what ext4, APFS and NTFS enforce.'가'.repeat(100)is 100 characters but 300 bytes and cannot be created. Counting characters also disagreed with the Python implementation, which counted code points where JavaScript counted UTF-16 units ('😀'.repeat(130)was invalid here and valid there) - BREAKING CHANGES:
createDirectorynow reports the error when a file already sits at the path. It asked only whether something was there and then answered that there was nothing to do, so no directory existed and nothing said so. Thestatbehind that check is gone as well, becausemkdirwithrecursiveis already a no-op for an existing directory - BREAKING CHANGES:
createFilenow creates any parent directory the path needs instead of failing withENOENT, matching the Dart implementation - BREAKING CHANGES:
createFile,deleteFileandmoveFilenow treat a path of nothing but whitespace as no path at all, matching the Dart implementation.createFile(' ')used to create a file literally named - BREAKING CHANGES:
getFileInfoandgetFileSizenow throw the original filesystem error instead of a newErrorcarrying only its message.code,errnoandpathwere dropped with it, so a caller could not tellENOENTfromEACCES, and the stack pointed at qsu rather than at the call. The unreachable fallback object both functions ended with has been removed - BREAKING CHANGES:
toValidFilePathnow resolves a leading..against the root, so'../../etc/passwd'returns/etc/passwdinstead of/../../etc/passwd isFileHidden: Runattribdirectly instead of handing a command line to a shell. A quote in a file name closed the quoting ofattrib "<path>"and the rest of the name ran as a command, so scanning a directory could execute whatever a file in it was named. Running the program directly also halves the processes each call startsisFileHidden: Read the attribute letters out of the columnattribprints them in. Removing the caller's path from the output failed whenever a relative path was given, becauseattribanswers with an absolute one, and anyHin a directory name then read as hiddentailFile: Read backwards from the end of the file a chunk at a time instead of walking it from the start, and stop shifting alength-sized array once per line. The old shape costlines × length: on a 108 MB log the last 20,000 lines took 57 seconds and now take 0.02, and the last single line went from 0.29 seconds to 0.001getCopyFileName: Accept aSetas well as an array, and read it as it is. Naming n files into one directory calls this n times, and rebuilding the set on every call made that loop quadratic — 16,000 names took 19 seconds through an array and 0.01 seconds through a reusedSetmoveFile: Fall back to a copy and a remove when the operating system reportsEXDEV.renamecannot cross a filesystem boundary, so moving out of the temporary directory, into a mounted volume or onto another drive failed outrightdeleteAllFileFromDirectory: Delete up to 32 entries at a time instead of awaiting each one in turngetFileHashFromPath: Read throughpipelinewith a 1 MB buffer instead of collectingdataevents at the 64 KB stream defaulthasBadWords: Catch a banned word broken up by digits (ad1min,사1과,사123과), a common way of hiding a word in Korean. A digit that opens or closes a word is still read as a letter, so a number in front of a word (2시 발표) is not read away- Import every Node.js built-in through the
node:prefix (node:crypto,node:fs,node:fs/promises,node:path,node:os,node:child_process,node:stream/promises). A bare specifier likecrypto,pathorosalso names a real package on npm, so a bundler could resolve it to that package instead of the built-in, and webpack 4 and other older bundlers silently substituted a browser polyfill for it. The prefix marks these as built-ins unambiguously, so a bundler targeting the browser reports them rather than replacing them. The hash functions were also importing fromcryptoandnode:cryptoin the same file. This changes no behavior and no API: the browser-safeqsuroot entry point never imported a built-in, and everything underqsu/nodeis imported from that subpath as before
1.14.0 (2026-07-28)
- BREAKING CHANGES:
logBoxnow requires a Node.js runtime and is imported from theqsu/nodesubpath. It usesnode:utilandprocess, so exporting it from the browser-safe root entry point could break bundlers - BREAKING CHANGES:
objDeleteKeyByValue,objUpdate,objMergeNewKey,arrShuffle,arrMove,sortNumericandsortByObjectKeyno longer modify the argument they are given. They all return a new object or array, matching the Dart implementations.Object.assign(obj, {})returnsobjitself andArray.prototype.sortreorders in place, so the caller's data used to change underneath it - BREAKING CHANGES:
numUniquenow returns a millisecond timestamp combined with a per-millisecond sequence (16 digits) instead of a timestamp combined with a random number (18 digits). The old value exceededNumber.MAX_SAFE_INTEGER, so digits were rounded away and different draws collapsed onto the same number — 100 calls within one millisecond produced only 98 distinct values. Repeated calls in a process are now always unique and strictly increasing - BREAKING CHANGES:
arrShufflenow returns an array when given a single element, instead of returning that element itself - BREAKING CHANGES:
sortNumericandsortByObjectKeynow applydescendingthrough the comparator instead of reversing the sorted result, so equal elements keep their relative order - BREAKING CHANGES:
generateLicensenow normalizes thetypeoption correctly, so'Apache 2.0','apache-2.0'and'BSD 3'return the license they name instead of silently falling back to MIT (a missing character class in the normalizing regular expression made it a no-op) - BREAKING CHANGES:
isEqualandisEqualStrictnow compare objects instead of mistaking them for an argument list. Previously any two objects compared as equal (isEqual({a: 1}, {a: 2})returnedtrueTrue). Passing the operands as an array still works - BREAKING CHANGES:
safeParseIntnow returnsfallbackwhen parsing fails (parseIntreports failure withNaNrather than throwing, sosafeParseInt('abc', 99)returnedNaN), and treats0as a valid input instead of a missing one - BREAKING CHANGES:
numberFormatnow groups the integer part as a string, so values beyondNumber.MAX_SAFE_INTEGERkeep every digit ('123456789012345678901'no longer becomes'123,456,789,012,345,680,000') - BREAKING CHANGES:
encryptnow stores the authentication tag for AEAD algorithms (GCM, CCM, OCB, ChaCha20-Poly1305) asiv:authTag:encrypted. Ciphertext produced by these algorithms was previously impossible to decrypt. Theiv:encryptedformat for CBC and other non-AEAD algorithms is unchanged - BREAKING CHANGES:
arrTo1dArrayno longer throws onnullNoneor plain objects (typeof null === 'object'made it spread a non-iterable); they are now kept as-is, matching the Dart and Python implementations decrypt: Support AEAD algorithms by reading the authentication tag, and throw a clear error when the input is not in the formatencryptreturnsdebounce: Pass the caller's arguments through to the debounced function (func.apply(args)passed them asthisArg, so the function always received none), and stop a pending timer from keeping a Node process alivecapitalizeEverySentence: Fix sentences containing characters outside the BMP (emoji) overwriting the wrong character, because a code point array was indexed with UTF-16 offsetsstrRandom: Stop appending the string'undefined'to the candidate characters whenadditionalCharactersis omitted, which madeu,n,d,e,fanditwo to three times more likelyreplaceBetween: Escape both delimiters correctly. A retainedlastIndexon a/gregular expression leftendCharunescaped, soreplaceBetween('a(b)c', '(', ')')threw a syntax errorarrUnique: Stop throwing on arrays containingundefinedor functions, which have no JSON representationarrRepeat,arrTo1dArray: Stop overflowing the call stack on large arrays by pushing in a loop instead of spreadingfetchData: FixbodyType: 'form-data'requests by leavingContent-Typeunset, sofetchcan supply theboundaryparameter that multipart bodies requireis2dArray: Return on the first nested array instead of walking the whole array and allocating a new oneobjToArray,objTo1d,objUpdate,objDeleteKeyByValue: Build the key list once per object instead of on every iteration, which made these O(n^2) (an object with 4,000 keys took over a second inobjUpdate)numberFormat,sortNumeric,sortByObjectKey: Reuse a singleIntl.NumberFormat/Intl.Collatorinstance instead of constructing one per callnumUnique: Stop building an 89,999 element array on every call to pick a single number- Remove
lib/verify/isUnique.ts, an empty file that was never exported but still emittedisUnique.jsandisUnique.d.tsinto the published build
1.13.2 (2026-07-26)
hasBadWords: ImprovehasBadWordsmethod
1.13.1 (2026-07-26)
hasBadWords: AddhasBadWordsmethod
1.13.0 (2026-07-26)
- BREAKING CHANGES:
durationnow hides milliseconds by default (enable withwithMilliSeconds) and uses grammatically correct plurals (e.g.0 Hours,1 Hour) - BREAKING CHANGES:
getFilePathLevelno longer counts a trailing separator as an extra level (/home/user/now returns the same level as/home/user) - BREAKING CHANGES:
getCopyFileNamenow preserves the original file extension casing (e.g.Report.PDFcopies toReport (1).PDFinstead ofReport (1).pdf) - BREAKING CHANGES:
isValidFileNamenow validates the whole name including its extension (sohello.:txtis invalid) and rejects Windows device names (CON,NUL,COM1-COM9,LPT1-LPT9, etc.) - BREAKING CHANGES:
createFileWithDummynow creates an empty file for a size of0instead of throwing, and throws a clearer error for a negative size - BREAKING CHANGES:
getParentFilePathnow returns the root (/or\) for an empty or single-segment path instead of/. - BREAKING CHANGES:
toValidFilePathnow returns the root (/or\) for a path that collapses to nothing instead of/. isFileExists: Follow symlinks so a dangling link reports as missing on every platform (previously returnedtrueTruefor a dangling link on Windows), matching the Dart and Python implementationsduration: SupportMonth(30 days) andYear(365 days) units, and addwithMilliSeconds,maxUnitCount, andunit(single-unit) optionslogBox: AddlogBoxmethodgetParsedInfoFromAddress: AddgetParsedInfoFromAddressmethodgetSlug: AddgetSlugmethod
1.12.2 (2026-06-06)
arrPick: AddarrPickmethod
1.12.1 (2026-05-21)
capitalizeEachWords: If thenaturaloption is not enabled, characters that are already uppercase will not be converted to lowercase.
1.12.0 (2026-04-14)
- BREAKING CHANGES:
strToNumberHashhas renamed tonumberHash md5Hash,sha1Hash,sha256Hash: Add an encoding option for hash functionsfetchData: Minor improvementsgetUptime: AddgetUptimemethodsha512Hash: Addsha512Hashmethod
1.11.6 (2026-04-12)
fetchData: Minor improvements
1.11.5 (2026-03-27)
getCopyFileName: AddgetCopyFileNamemethod
1.11.4 (2026-03-27)
net.fetchData: AddfetchDatamethod
1.11.3 (2026-03-26)
numberFormat: Fix zero value
1.11.2 (2026-03-26)
- BREAKING CHANGES:
numRandomhas renamed tonumPick numUnique: AddnumUniquemethodgetCpu: AddgetCpumethodgetFileName: Fix incorrect directory name with include dot characternumberFormat: Fix where negative numbers were not handled properly, and now return an empty string instead of 0 when the value is null
1.11.1 (2026-01-18)
getGroupKeys: AddgetGroupKeysmethod
1.11.0 (2026-01-09)
- BREAKING CHANGES: The
isWindowsargument is no longer used ingetFileExtension. getFileExtension: Performance improvements and cleanupsgetFileName: Performance improvements and cleanupstoValidFilePath: Performance improvements and cleanupsgetParentFilePath: Performance improvements and cleanupsjoinFilePath: Performance improvements and cleanups
1.10.4 (2025-11-25)
getFileSize: AddgetFileSizemethodgetRamSize: AddgetRamSizemethodheadFile,tailFile: Use better head/tail logicfileSizeFormat: Addceilargument to thefileSizeFormatmethod
1.10.3 (2025-11-04)
- BREAKING CHANGES:
getFileSizehas renamed tofileSizeFormat
1.10.2 (2025-10-15)
getHostname: AddgetHostnamemethodgetStrBytes: AddgetStrBytesmethod
1.10.1 (2025-06-08)
isEmail: AddonlyLowerCaseparametergetFileHash: This function has been renamed togetFileHashFromPath. Also,getFileHashFromStreamhas been added, which can take a ReadableStream and hash it.
1.10.0 (2025-03-12)
- The
machinipackages have now been merged into theqsupackage
1.9.3 (2025-03-08)
generateLicense: Add bsd3 license
1.9.2 (2025-03-06)
- Update
README.md
1.9.1 (2025-03-01)
- Fix import issue
1.9.0 (2025-03-01)
- BREAKING CHANGES: The utility functions related to
file,cryptothat use Node.js modules have been separated out and should useimport * from 'qsu/node'instead ofimport * from 'qsu'to use them. These modules do not need to be installed separately. - Rename export name
servertonode
1.8.3 (2025-03-01) - DEPRECATED
- Fix import issue
1.8.2 (2025-03-01) - DEPRECATED
- Fix import issue
1.8.1 (2025-03-01) - DEPRECATED
- Fix import issue
1.8.0 (2025-03-01) - DEPRECATED
- BREAKING CHANGES: The utility functions related to
file,cryptothat use Node.js modules have been separated out and should useimport * from 'qsu/server'instead ofimport * from 'qsu'to use them. These modules do not need to be installed separately.
1.7.2 (2025-03-01)
numberFormat: Fix decimal point formattailFile,headFile: Correct line-break detection in Windows OS- Clarify node module descriptions
1.7.1 (2025-02-28)
- Update documentations
1.7.0 (2025-02-27)
- BREAKING CHANGES: The
qsu-fsandqsu-webpackages have now been merged into theqsupackage, and all functions in the family package can now be used by installing onlyqsu. For more information, please refer to the documentation. - BREAKING CHANGES:
fileExt,fileName, andfileSizehave been moved to the file category and renamed togetFileExtension,getFileName, andgetFileSize, respectively. - Separate files by function to strengthen tree shaking
1.6.5 (2025-02-23)
numberFormat: Need to handle decimal pointstruncateExpect: Fix incorrect characters being added when all strings are displayed
1.6.4 (2024-12-20)
isTrueMinimumNumberOfTimes: Use any type (fix build)
1.6.3 (2024-12-20)
objMergeNewKey: Added options to customize behavior for arrays
1.6.2 (2024-12-08)
- Fix import crypto module
1.6.1 (2024-12-07)
- Fix import of type declaration files
- Fix critical import issue
1.6.0 (2024-12-06)
NOTE: This version is broken. Please use 1.6.1 or later.
- BREAKING CHANGES: The
qsupackage no longer uses classes, so if you want to import the entire module at once, you must use something likeimport * as _ from 'qsu'. (_->* as _) - BREAKING CHANGES: The
objectTo1dmethod have been renamed toobjTo1d - Separate files for each module purpose. Improved tree-shaking.
1.5.0 (2024-10-24)
- BREAKING CHANGES: The
md5,sha1, andsha256methods have been renamed tomd5Hash,sha1Hash, andsha256Hash. objMergeNewKey: AddobjMergeNewKeymethod
1.4.2 (2024-06-25)
isObject: use more accurate detect logic
1.4.1 (2024-05-05)
safeJSONParse: AddsafeJSONParsemethodsafeParseInt: AddsafeParseIntmethod
1.4.0 (2024-04-14)
- BREAKING CHANGES: Removed the
msToTimeandsecToTimemethods, which are unstable and have been replaced with thedurationmethod to provide a more stable utility. duration: Adddurationmethod
1.3.8 (2024-04-12)
objectTo1d: AddobjectTo1dmethod- Strictly check object types on some methods
1.3.7 (2024-04-07)
trim: handle error when value isnullNone
1.3.6 (2024-04-07)
- BREAKING CHANGES: The
trim, Now there is no second argument, and the default behavior is to remove leading and trailing spaces, and change spaces in more than two letters to spaces in the sentence - BREAKING CHANGES: The
getPlatformmethod has been deleted
1.3.5 (2024-03-31)
numberFormat: allow string type parameterisTrueMinimumNumberOfTimes: AddisTrueMinimumNumberOfTimesmethod
1.3.4 (2024-03-19)
objDeleteKeyByValue: AddobjDeleteKeyByValuemethodobjUpdate: AddobjUpdatemethodarrGroupByMaxCount: AddarrGroupByMaxCountmethod
1.3.3 (2024-03-05)
objFindItemRecursiveByKey: AddobjFindItemRecursiveByKeymethodurlJoin: AddurlJoinmethodobjToArray: AddobjToArraymethod
1.3.2 (2023-12-28)
strToNumberHash: AddstrToNumberHashmethodobjToQueryString: AddobjToQueryStringmethodobjToPrettyStr: AddobjToPrettyStrmethod
1.3.1 (2023-11-08)
encrypt,decrypt: Add toBase64 params for result string encodingcreateDateListFromRange: Use regex instead of string checkgetPlatform: Android is not linux os (This method has now been removed in version 1.3.6)
1.3.0 (2023-09-27)
objectId: AddobjectIdmethodsortByObjectKey: AddsortByObjectKeymethodsortNumeric: AddsortNumericmethod- Documentation improvements
1.2.3 (2023-09-15)
truncateExpect: do not add a closing character to the last character for sentences without a closing character
1.2.2 (2023-08-15)
replaceBetween: AddreplaceBetweenmethod
1.2.1 (2023-08-07)
capitalizeEverySentence: AddcapitalizeEverySentencemethodarrUnique: Use fast algorithm for 2d array uniquedebounce: Adddebouncemethod
1.2.0 (2023-06-29)
BREAKING CHANGES: The isBotAgent, license methods were separated from qsu to the qsu-web package. These methods are no longer available after version 1.2.0.
- Explore the
qsu-webpackage: %DEPRECATED% - Also, I've split the documentation page into the following sites: https://qsu.cdget.com
1.1.8 (2023-05-13)
strToAscii: AddstrToAsciimethodtruncateExpect: AddtruncateExpectmethod
1.1.7 (2023-03-17)
- Node.js 12 version deprecation
removeSpecialChar: UsingexceptionCharactersinstead ofwithoutSpace
1.1.6 (2023-02-28)
isValidDate: Only theyyyy-mm-ddformat can be verifieddateToYYYYMMDD: AdddateToYYYYMMDDmethodcreateDateListFromRange: AddcreateDateListFromRangemethodarrCount: AddarrCountmethod
1.1.5 (2023-02-07)
isEmail: AddisEmailmethodsub: Addsubmethoddiv: Adddivmethod
1.1.4 (2022-12-22)
arrTo1dArray: AddarrTo1dArraymethodisObject: AddisObjectmethodarrRepeat: AddarrRepeatmethodisValidDate: RenameisRealDatetoisValidDate
1.1.3 (2022-10-23)
funcTimes: AddfuncTimesmethodgetPlatform: AddgetPlatformmethod (This method has now been removed in version 1.3.6)sum,mul,split: Fix type errorarrUnique,capitalizeEachWords,strBlindRandom: Fix correct use static method- Support named import
- Change test script to TypeScript
1.1.2 (2022-10-20)
trim: Add new trim methodfileSize: When byte is null, returns 0 bytesstrCount: Use indexOf instead of regular expression to use better performancestrNumberOf: Rename method name to strCount- Add prettier and reformat all codes
- Change require nodejs version to >= 12
- Remove unused ts-node package
- Upgrade package dependencies
1.1.1 (2022-10-08)
- Upgrade package dependencies
1.1.0 (2022-09-03)
- Reduced bundle size due to minify executable code
isBotAgent: Remove duplicate string
1.0.9 (2022-08-15)
str: Handling of null str values
1.0.8 (2022-08-15)
- Add GitHub workflows
truncate: Return empty string when str is nullfileName: Resolves Windows's path regardless of system environment
1.0.7 (2022-07-24)
- Add
CHANGELOG.mdto.npmignore
1.0.6 (2022-07-24)
isBotAgent: Addchrome-lighthousein bot listssplit: Fix incorrect return typeisEqual: Add new isEqual methodisEqualStrict: Add new isEqualStrict method- Import only the methods needed in the path and crypto module
1.0.5 (2022-06-23)
contains: When the length of the str parameter value of a string type is 0, no error is thrown and false is returned
1.0.4 (2022-06-16)
BREAKING CHANGES: convertDate is no longer supported due to the removal of moment as a dependent module.
The today method has changed its usage. We no longer support custom date formats.
split: Add new split methodtoday: Remove dependent modules, change parameters to use pure codeconvertDate: Remove methodencrypt,decrypt: Add basic validation check (more fix)
1.0.3 (2022-05-24)
encrypt,decrypt: Add basic validation check
1.0.2 (2022-05-23)
encryptdecrypt: Add basic validation checkstrBlindRandom: Override the deprecated substr method
1.0.1 (2022-05-12)
- Minimize bundle size and clean up code
1.0.0 (2022-05-09)
- First version release
0.0.1 ~ 0.5.5 (2021-03-16 ~ 2022-04-09)
- This is for the Alpha release and is not recommended for use
1.7.0 (2026-09-12)
Breaking changes
sortNumeric: The order no longer depends on the package. A string is cut into runs of digits and runs of everything else, and the runs are compared in three passes over the whole string: the letters, then the accents on them, then upper against lower case. Whitespace sorts before punctuation, punctuation before numbers and numbers before letters, and a run of digits is compared by length before value, so a number too long for a number type still sorts correctly. The three packages now return the same order for the same input, which they never did.compareNaturalfrompackage:collectionused to decide it, which compared code points, soApple,BananaandZebraall came beforeapple, andFile-3.txtcame beforefile-1.txt
Changes
package:collectionis no longer a dependency.compareNaturalwas the only thing this package used it for, andsortNumericno longer calls it, so the package now rests onpath,cryptoandunorm_dartalonedurationParts: Added. Breaks a duration into its units and hands them back as aList<DurationPart>rather than a string, so a duration can be written in a language this package does not know.durationlabels the units in English and builds the plural by adding ans, which is a rule only English follows: Polish has three plural forms and Arabic six. It takes the named parameters ofdurationthat decide which units are used, anddurationis now built on it, so the two cannot disagreefileSizeParts: Added. Splits a file size in bytes into the scaled number and the unit it belongs to, returning aFileSizePartsrather than a string, so a size can be written in a language this package does not know. Handvalueto aNumberFormatfromintland take the unit name fromexponent; the value is deliberately left unrounded, so that formatter rounds it once instead of rounding an already rounded numberfileSizeFormat: Two named parameters were added.standardpicks the divisor and the unit names:jedec(the default) divides by 1024 and writesKBas it always has,iecdivides by 1024 and writesKiB, andsidivides by 1000 and writeskB.unitDisplaywrites the unit as an abbreviation (1.18 MB) or as a whole word (1.18 Megabytes), taking the singular when the rounded number is one. Leaving both out returns exactly the string it returned before, which the tests now pinfileSizeFormat: A size past the largest unit no longer throws aRangeErrorby indexing past the end of the unit table. The exponent is held at the last unit instead, matching what the JavaScript and Python packages now do
1.6.0 (2026-08-29)
truncate,truncateExpect: The length is now counted in code points, aspadalready did, so a character outside the Basic Multilingual Plane counts as one in every language. A Dart string is indexed in UTF-16 units, sotruncate('a👋b', 2)used to cut between the two halves of the emoji and hand back a broken character, andtruncateExpectstopped at a different sentence than Python did on the same texttruncateExpect:endStringCharnow takes aList<String>as well as a singleString, and defaults to the full stop as each script writes it (.,。,.,。). Japanese and Chinese text used to come back untouched, because a text with no ASCII.in it split into one piece and the expected length was never reached.!and?are left out of the default on purpose, so that the same sentence is not split differently depending on the script it is written in. A longer ending character is matched before a shorter one, so.next to...no longer cuts...short
1.5.0 (2026-08-07)
unescapeHtml: Added. Turns the five entitiesescapeHtmlproduces back into their characters. The string is walked once rather than replaced five times in a row, so&lt;comes back as the literal text<instead of being unescaped twice, and only those five entities are recognised, so and'are left as they areescapeHtml: Added. Escapes&,<,>,"and'so a value can be dropped into a page as text rather than read as markup.'is written as'rather than', which HTML 4 never defined. It lives in thewebcategory, next togetSlug, and leavesescapeRegExpas the pattern-oriented oneobjClone: Added. Copies an object, deeply by default and top level only withdeep: false. AMap,ListandSetare rebuilt with their contents copied, while aDateTime(immutable) or a class instance is handed back as it is. A structure that points back at itself is rebuilt with the same shape rather than recursing until the stack runs outobjMerge: Added. Merges any number of objects into one new object, going down through nested maps, with the later source winning. Two maps under the same key are merged into a new map, so neither source is shared with the result or modified. Lists are replaced whole rather than merged index by index as Lodash does, andnullNoneis returned when an entry is not a mapobjGet: Added. Reads a nested value out of an object by dot and/or bracket path (a.b.c,list[0],list[1].d), returning thefallbackwhen the path is not there. A bracket may carry a quoted key, so["a.b"]reads one key rather than walking two levels, and a storednullNonecounts as a value rather than a missing pathobjPick: Added. Returns a new object containing only the listed keys, accepting a single key or a list of keys. Only the top level is inspected, and a key the map does not have is skipped rather than carried over asnullNonepad: Added. Pads a string until it reaches the given length, with onepositionnamed parameter (start,endorboth) covering what Lodash splits acrosspad,padStartandpadEnd.bothis the default and gives the extra character to the end, a multi-charactercharis repeated and truncated, and the length is counted in code points so an emoji counts as one in every languagestrToConstantCase: Added. Converts a string toCONSTANT_CASE, uppercasing every word and joining them with an underscore. It splits withwords, soXMLHttpRequestbecomesXML_HTTP_REQUEST. Dart applies the simple Unicode case mapping where JavaScript and Python apply the full one, sostraßebecomesSTRAßEhere andSTRASSEthere, which the documentation states rather than papering overstrToPascalCase: Added. Converts a string toPascalCase, giving every word an uppercase first letter and a lowercase rest. It splits withwords, soXMLHttpRequestbecomesXmlHttpRequest.capitalizeEachWordsstays the one that keeps the original separatorsstrToKebabCase: Added. Converts a string tokebab-case, lowercasing every word and joining them with a hyphen. It splits withwords, soXMLHttpRequestbecomesxml-http-request.getSlugstays the URL-oriented onestrToSnakeCase: Added. Converts a string tosnake_case, lowercasing every word and joining them with an underscore. It splits withwords, soXMLHttpRequestbecomesxml_http_requestandabc12defbecomesabc_12_defstrToCamelCase: Added. Converts a string tocamelCase, lowercasing the first word and giving every word after it an uppercase first letter. It splits withwords, so an acronym stays whole (XMLHttpRequestbecomesxmlHttpRequest) and a run of digits is its own word (abc12defbecomesabc12Def)min: Added. Returns the smallest of the given numbers, taking a single array exactly likesum.NaNis skipped, because it loses every comparison and would otherwise win by being seen first, and an empty list returnsnullNone. It shadowsminfromdart:math, so a file that needs both has to import one of them with a prefixmax: Added. Returns the largest of the given numbers, taking a single array exactly likesum.NaNis skipped, because it loses every comparison and would otherwise win by being seen first, and an empty list returnsnullNone. It shadowsmaxfromdart:math, so a file that needs both has to import one of them with a prefixfloor: Added. Rounds a number down, to the given number of decimal places, a negative precision rounding down to tens, hundreds and so on. Rounding goes toward negative infinity, sofloor(-4.006)is-5. The value is shifted through its shortest string representation, sofloor(1.1, 1)is1.1, and a whole result is handed back as anintceil: Added. Rounds a number up, to the given number of decimal places, a negative precision rounding up to tens, hundreds and so on. Rounding goes toward positive infinity, soceil(-4.006)is-4. The value is shifted through its shortest string representation, soceil(1.1, 1)is1.1and not1.2, and a whole result is handed back as anintround: Added. Rounds a number to the given number of decimal places, a negative precision rounding to tens, hundreds and so on. Ties go away from zero, which is whatnum.roundalready does but not what JavaScript'sMath.roundor Lodash do. The value is shifted through its shortest string representation rather than multiplied by a power of ten, soround(1.005, 2)is1.01and not1, and a whole result is handed back as anintsoround(1234, -2)is1200rather than1200.0clamp: Added. Restricts a number to an inclusive range, returningminbelow it andmaxabove it. The upper bound is applied first, sominwins when the two are passed the wrong way round, where the built-innum.clampthrows on an inverted range insteadretry: Added. Runs the given function again on failure until it succeeds or the attempts run out, rethrowing the last error with its original stack trace if they all fail.timescounts total attempts (default3),delaywaits between them andbackoffmultiplies that wait after each failurethrottle: Added. Limits how often a function may run to at most once perwaitwindow, the counterpart ofdebounce.leadingandtrailing(bothtrueTrueby default) choose which edge of the window runsobjInvert: Added. Returns a new object with the keys and values swapped. Values are converted to text because keys are always strings, a wholedoublelosing its fractional part so the result matches the JavaScript implementation, and the later entry wins when two share a valueobjMapKeys: Added. Returns a new object whose keys are the values returned by the callback, with the values carried over untouched. The callback receives(value, key), and the later key wins when two map onto the same nameobjPickBy: Added. Returns a new object containing only the entries for which the callback returnstrueTrue. The callback receives(value, key), and only the top level is inspecteduncapitalizeFirst: Added. Converts the first letter of the entire string to lowercase, the inverse ofcapitalizeFirst. Only the first character is touched, soTESTbecomestESTescapeRegExp: Added. Escapes every regular expression metacharacter (^ $ . * + ? ( ) [ ] { } |and\) so a value can be matched literally.-and#are left alone: they are special only inside a character class. The private helper behindremoveSpecialCharandreplaceBetween, which does also escape-and/because its result lands inside a character class, is now named_escapeRegExpInClassto keep the two apartdeburr: Added. Replaces accented Latin letters with their unaccented equivalents (déjà vubecomesdeja vu), spelling outÆ,ß,Þ,ŒandIJ, and dropping combining marks. Covers the Latin-1 Supplement and Latin Extended-A blockswords: Added. Splits a string into the words it is made of. Anything that is neither a letter nor a digit separates words, and camelCase boundaries, runs of capitals (XMLHttpRequestisXML,Http,Request) and runs of digits are split as wellarrIntersection: Added. Returns the values that are present in every one of the given arrays. The result is unique and keeps the order of the first arrayarrDifference: Added. Returns the values of the first array that are not contained in any of the other arrays. Values are compared by value rather than by identity, so nested lists and maps are matched as wellarrCompact: Added. Returns a new array with every falsy value removed (nullNone,falseFalse,0,'',NaN). An empty list and an empty map are kept, matching the JavaScript implementation
1.4.0 (2026-08-)
- BREAKING CHANGES:
isValidFileNamenow rejects an empty name and any name carrying a control character (U+0000-U+001ForU+007F).NULis the one that matters: it terminates the path in the system call underneath every filesystem, so a name carrying one was reported as valid and then silently truncated on the way to disk - BREAKING CHANGES:
isValidFileNamenow rejects a name ending in a dot or a space on the Windows path. Windows strips it instead of reporting an error, soreport.quietly becomesreportand overwrites it. Unix keeps them, so they stay valid withunixType - BREAKING CHANGES:
isValidFileNamenow measures its 255 limit in UTF-8 bytes rather than characters, which is what ext4, APFS and NTFS enforce.'가' * 100is 100 characters but 300 bytes and cannot be created - BREAKING CHANGES:
headFileandtailFilenow replace malformed UTF-8 withU+FFFDinstead of throwing aFormatException, matching the JavaScript and Python implementations. One bad byte in a log file no longer stops it from being read - BREAKING CHANGES:
headFileandtailFilenow keep a leading byte order mark. Dart's UTF-8 decoder drops it, which silently changed text that JavaScript and Python both return whole - BREAKING CHANGES:
moveFilenow moves a directory as well as a file, with everything inside it.File(path).renamereports an error on a directory, so the entity is opened as what it actually is - BREAKING CHANGES:
getFileInfoandgetFileSizenow throw theFileSystemExceptionas it is instead of wrapping it inException(err.toString()), which droppedosErrorandpathand left a caller unable to tell a missing file from a permission error.headFileandtailFileno longer wrap theirs either - BREAKING CHANGES:
toValidFilePathnow resolves a leading..against the root, so'../../etc/passwd'returns/etc/passwdinstead of/../../etc/passwd - BREAKING CHANGES:
getCopyFileNamenow takes anIterable<String>instead of aList<String>, and reads aSetas it is. Naming n files into one directory calls this n times, and rebuilding the set on every call made that loop quadratic — 16,000 names took 21 seconds through aListand 0.01 seconds through a reusedSet tailFile: Read backwards from the end of the file a chunk at a time instead of streaming it from the start. On a 108 MB log the last line took 0.73 seconds and now takes 0.002headFile: Read forwards a chunk at a time and stop as soon as enough lines are in hand, rather than running the whole file through a stream transformermoveFile: Fall back to a copy and a remove when the operating system reports a cross-device error.renamecannot cross a filesystem boundary, so moving out of the temporary directory, into a mounted volume or onto another drive failed outrightisFileExists: Answer with a singleFileSystemEntity.typecall rather than askingFile.existsand thenDirectory.exists, which cost two system calls for every directorycreateDirectory: Drop theexistscall that ran before everycreate.createis already a no-op for an existing directory and already reports a file in the waydeleteAllFileFromDirectory: Delete up to 32 entries at a time instead of awaiting each one in turnhasBadWords: Catch a banned word broken up by digits (ad1min,사1과,사123과), a common way of hiding a word in Korean. A digit that opens or closes a word is still read as a letter, so a number in front of a word (2시 발표) is not read away
1.3.0 (2026-07-28)
- BREAKING CHANGES:
numberHashnow returns the low 32 bits as a signed value, so it can be negative as documented and matches the JavaScript and Python implementations (numberHash('k10000')is-1184917978, not3110049318) - BREAKING CHANGES: The
base64urlhash encoding is now unpadded, andbinarynow returns the raw digest as latin-1 characters instead of a string of 0s and 1s, both matching the JavaScript and Python implementations - BREAKING CHANGES:
truncateExpectno longer inserts the literal textnullNoneinto the result whenendStringCharis omitted (truncateExpect('Hi. Bye.', 3)returned'Hinull') - BREAKING CHANGES:
numUniquenow returns a millisecond timestamp combined with a per-millisecond sequence (16 digits) instead of a timestamp combined with a random number (18 digits). Repeated calls within a process are now always unique and strictly increasing - BREAKING CHANGES:
isValidDatenow rejects years0100-1599, which the JavaScript and Python implementations also reject. Two-digit years16-99and four-digit years1600-9999remain valid - BREAKING CHANGES:
dayDiffnow returns the absolute difference, so swapping the arguments no longer flips the sign - BREAKING CHANGES:
arrMoveno longer modifies the list it is given; it returns a new one - BREAKING CHANGES:
strRandomreturns an empty string andfuncTimesreturns an empty list for a non-positive count, instead of throwing, matching the JavaScript and Python implementations - BREAKING CHANGES:
objTo1dnow rejects anullNoneseparator, which used to be interpolated into every nested key as the literal textnullNone - BREAKING CHANGES:
isMatchPathnamenow throws for an empty matcher list instead of quietly returningfalseFalse strUnique: Deduplicate by code point, so characters outside the BMP (emoji) are no longer broken apartcapitalizeFirst,capitalizeEachWords: Return an empty string instead of throwing aRangeErroron empty inputreplaceBetween: Escape the whole delimiter, so multi-character delimiters produce a valid pattern;replaceWithnow defaults to an empty string as documentedremoveSpecialChar,removeLocalePrefix: Escape the caller's characters before building the pattern, so values like']'orzh.CNare matched literally instead of being interpreted as a patternisMatchPathname,removeLocalePrefix: Accept any iterable, not onlyList<String>. AList<dynamic>(what JSON decoding produces) used to be stringified whole and never matchedmd5Hash,sha1Hash,sha256Hash,sha512Hash: Fall back to hex whenencodingis explicitlynullNoneinstead of throwingisBotAgent: Remove 84 of the 172 alternatives that were substrings of another one (botalready matchesnaverbot,bingbot, ...) and could never change the outcome — verified identical on 200,000 inputs. Roughly halves the matching costisBotAgent,isMobile,getSlug,removeSpecialChar,replaceBetween,trim,capitalizeEverySentence,getParsedInfoFromAddress: Compile regular expressions once instead of on every call —getSlugwas building three per characterobjectId,strShuffle,strRandom,numPick: Reuse a singleRandominstance instead of constructing one per draw- BREAKING CHANGES:
getParentFilePathnow handles relative paths (relative/path->/relative), UNC paths, and trailing separators correctly - BREAKING CHANGES:
toValidFilePathnow resolves.and..segments and preserves the UNC\\prefix - BREAKING CHANGES:
getFilePathLevelno longer counts a trailing separator as an extra level (/home/user/now returns the same level as/home/user) - BREAKING CHANGES:
getCopyFileNamenow preserves the original file extension casing (e.g.Report.PDFcopies toReport (1).PDFinstead ofReport (1).pdf) - BREAKING CHANGES:
isValidFileNamenow validates the whole name including its extension (sohello.:txtis invalid) and rejects Windows device names (CON,NUL,COM1-COM9,LPT1-LPT9, etc.) - BREAKING CHANGES:
createFileWithDummynow throws for a negative size instead of returningfalseFalse - BREAKING CHANGES:
createDirectory,moveFile, andcreateFilenow propagate filesystem errors instead of silently ignoring them duration: AdddurationmethodarrPick: AddarrPickmethodgetParsedInfoFromAddress: AddgetParsedInfoFromAddressmethodgetSlug: AddgetSlugmethodhasBadWords: AddhasBadWordsmethodcapitalizeEachWords: If thenaturaloption is not enabled, characters that are already uppercase will not be converted to lowercase
1.2.0 (2026-04-14)
- BREAKING CHANGES:
strToNumberHashhas renamed tonumberHash md5Hash,sha1Hash,sha256Hash: Add an encoding option for hash functions- Add
sortNumericmethod - Add
sha512Hashmethod
1.1.12 (2026-03-31)
- BREAKING CHANGES:
numRandomhas renamed tonumPick getFileName: Fix incorrect directory name with include dot character- Add
getCopyFileNamemethod - Add
divmethod - Add
mulmethod - Add
submethod - Add
summethod - Add
createDateListFromRangemethod - Add
dateToYYYYMMDDmethod - Add
dayDiffmethod - Add
isValidDatemethod - Add
todaymethod
1.1.11 (2025-12-10)
- Add
splitmethod - Add
isMobilemethod - Add
objDeleteKeyByValuemethod
1.1.10 (2025-11-25)
- Fix package dependencies
1.1.9 (2025-11-25)
- Add
getFileSizemethod - Add
normalizeFilemethod - Add
headFilemethod - Add
tailFilemethod - Add
removeLocalePrefixmethod - Add
isMatchPathnamemethod - Add
isBotAgentmethod - Add
ceilargument to thefileSizeFormatmethod
1.1.8 (2025-11-13)
- Add
createDirectorymethod - Add
getParentFilePathmethod - Add
deleteFilemethod - Add
createFilemethod - Add
deleteAllFileFromDirectorymethod - Add
moveFilemethod - Add
createFileWithDummymethod - Add
getFileInfomethod - Add
joinFilePathmethod - Add
getFileHashFromPathmethod
1.1.7 (2025-11-03)
- BREAKING CHANGES:
getFileSizehas renamed tofileSizeFormat - BREAKING CHANGES:
safeJSONParse: 'fallback' parameters has changed to named parameter - BREAKING CHANGES:
objToArray: 'recursive' parameters has changed to named parameter - Add
getFileNameandgetFileExtensionmethods - Add
isFileExistsmethod - Add
isValidFileNamemethod - Add
toPosixFilePathmethod - Add
getFilePathLevelmethod - Add
toValidFilePathmethod
1.1.6 (2025-10-15)
isEmail: addonlyLowerCaseparameter- Add
consolemethod - Add
getStrBytesmethod
1.1.5 (2025-03-06)
- Update
README.md
1.1.4 (2025-02-28)
- Update documentation
1.1.3 (2025-02-14)
- Fix
isUrlparameters
1.1.2 (2025-02-14)
- Add
debouncemethod - Add
isUrlmethod - Add
isObjectmethod - Add
isEqualmethod - Add
isEqualStrictmethod - Add
isEmptymethod
1.1.1 (2024-11-26)
- Fix
objTo1dparameters
1.1.0 (2024-11-26)
- Add
arrCountmethod - Add
betweenmethod - Add
arrGroupByMaxCountmethod - Add
numPickmethod - Add
lenmethod - Add
isTrueMinimumNumberOfTimesmethod - Add
objToQueryStringmethod - Add
objToArraymethod - Add
objTo1dmethod
1.0.0 (2024-10-19)
- Add
fileSizemethod - Add
fileExtmethod - Add
safeParseIntmethod - Add
isEmailmethod - Add
fileNamemethod - Add
safeJSONParsemethod - Add
md5Hashmethod - Add
sha1Hashmethod - Add
sha256Hashmethod - Add
encodeBase64method - Add
decodeBase64method - Add
strToNumberHashmethod - Add
objectIdmethod
0.0.4 (2024-10-02)
- Add
averagemethod - Add
arrMovemethod - Add
arrTo1dArraymethod - Add
arrRepeatmethod
0.0.3 (2024-10-02)
- Add
strShufflemethod - Add
strRandommethod - Add
truncateExpectmethod - Add
strUniquemethod - Add
strToAsciimethod - Add
urlJoinmethod - Add
arrWithDefaultmethod - Add
arrWithNumbermethod - Add
funcTimesmethod - Add
is2dArraymethod - Add
arrUniquemethod
0.0.2 (2024-09-10)
- Add
trimmethod - Add
replaceBetweenmethod - Add
removeNewLinemethod - Add
capitalizeEverySentencemethod - Add
containsmethod - Add
capitalizeEachWordsmethod - Add
strCountmethod - Add
sleepmethod - Add
arrShufflemethod - Add
removeSpecialCharmethod
0.0.1 (2024-09-02) - Not for Production
- Initial release
1.4.0 (2026-09-12)
Breaking changes
sortNumeric,sortByObjectKey: The order no longer depends on the machine or on the package. A string is cut into runs of digits and runs of everything else, and the runs are compared in three passes over the whole string: the letters, then the accents on them, then upper against lower case. Whitespace sorts before punctuation, punctuation before numbers and numbers before letters, and a run of digits is compared by length before value, so a number too long for a number type still sorts correctly. The three packages now return the same order for the same input, which they never did. The key used to compare code points, soApple,BananaandZebraall came beforeapple, andFile-3.txtcame beforefile-1.txt
Changes
durationParts: Added. Breaks a duration into its units and hands them back as a list of{'value', 'unit'}rather than a string, so a duration can be written in a language this package does not know.durationlabels the units in English and builds the plural by adding ans, which is a rule only English follows: Polish has three plural forms and Arabic six.babel'sformat_unitknows the plural rules for each language. It takes the options ofdurationthat decide which units are used, anddurationis now built on it, so the two cannot disagreefileSizeParts: Added. Splits a file size in bytes into the scaled number and the unit it belongs to, returning adictrather than a string, so a size can be written in a language this package does not know. Handvaluetobabel'sformat_decimaland take the unit name fromexponent; the value is deliberately left unrounded, so that formatter rounds it once instead of rounding an already rounded numberfileSizeFormat: Two keyword arguments were added.standardpicks the divisor and the unit names:jedec(the default) divides by 1024 and writesKBas it always has,iecdivides by 1024 and writesKiB, andsidivides by 1000 and writeskB.unitDisplaywrites the unit as an abbreviation (1.18 MB) or as a whole word (1.18 Megabytes), taking the singular when the rounded number is one. Leaving both out returns exactly the string it returned before, which the tests now pinfileSizeFormat: A size past the largest unit no longer raisesIndexErrorby indexing past the end of the unit table.fileSizeFormat(1024 ** 9)now reads1024 YB, matching what the JavaScript and Dart packages now do
1.3.0 (2026-08-29)
- The package now ships a
py.typedmarker, so a type checker reads the annotations every function already carried. Without it those annotations were ignored in an installed package (PEP 561), and because functions are imported on demand, a checker followingfrom qsu.array import arrUniquelanded on the module of that name rather than the function in it. Each category now spells its re-exports out underif TYPE_CHECKING, which costs nothing at runtime, soqsu.arrUnique,from qsu.array import arrUniqueandfrom qsu.array.arrUnique import arrUniqueall carry the real signature - Categories and functions are now imported on first access.
import qsuused to pull in all 170 function modules, and with themcryptography,subprocessandurllib, whatever the caller went on to use; reaching for a single function through its own module cost exactly the same, because importing a submodule runs the package__init__first. It now takes 1.6ms rather than 61ms and loads 18 modules rather than 286, and the first call into a category pays for that category alone.__all__and its order,from qsu import *,from qsu.array import arrUniqueanddir()all answer as before, and every name still resolves to one object whether it is read fromqsuor from its category truncateExpect:endStringCharnow takes a list as well as a single string, and defaults to the full stop as each script writes it (.,。,.,。). Japanese and Chinese text used to come back untouched, because a text with no ASCII.in it split into one piece and the expected length was never reached.!and?are left out of the default on purpose, so that the same sentence is not split differently depending on the script it is written in. A longer ending character is matched before a shorter one, so.next to...no longer cuts...short
1.2.0 (2026-08-07)
unescapeHtml: Added. Turns the five entitiesescapeHtmlproduces back into their characters. The string is walked once rather than replaced five times in a row, so&lt;comes back as the literal text<instead of being unescaped twice, and only those five entities are recognised, so and'are left as they areescapeHtml: Added. Escapes&,<,>,"and'so a value can be dropped into a page as text rather than read as markup.'is written as'where the built-inhtml.escapewrites', so this is not a wrapper around it. It lives in thewebcategory, next togetSlug, and leavesescapeRegExpas the pattern-oriented oneobjClone: Added. Copies an object, deeply by default and top level only withdeep: False. Adict,listandtupleare rebuilt with their contents copied and asetgets a fresh copy, while adatetime(immutable) or a class instance is handed back as it is. A structure that points back at itself is rebuilt with the same shape rather than recursing until the recursion limit is hitobjMerge: Added. Merges any number of objects into one new object, going down through nested dicts, with the later source winning. Two dicts under the same key are merged into a new dict, so neither source is shared with the result or modified. Lists are replaced whole rather than merged index by index as Lodash does, andNoneis returned when an argument is not a dictobjGet: Added. Reads a nested value out of an object by dot and/or bracket path (a.b.c,list[0],list[1].d), returning thefallbackwhen the path is not there. A bracket may carry a quoted key, so["a.b"]reads one key rather than walking two levels, and a storedNonecounts as a value rather than a missing pathobjPick: Added. Returns a new object containing only the listed keys, accepting a single key or a list of keys. Only the top level is inspected, and a key the dict does not have is skipped rather than carried over asNonepad: Added. Pads a string until it reaches the given length, with onepositionoption (start,endorboth) covering what Lodash splits acrosspad,padStartandpadEnd.bothis the default and gives the extra character to the end, a multi-charactercharis repeated and truncated, and the length is counted in code points so an emoji counts as one in every languagestrToConstantCase: Added. Converts a string toCONSTANT_CASE, uppercasing every word and joining them with an underscore. It splits withwords, soXMLHttpRequestbecomesXML_HTTP_REQUEST. Python and JavaScript apply the full Unicode case mapping where Dart applies the simple one, sostraßebecomesSTRASSEhere andSTRAßEin Dart, which the documentation states rather than papering overstrToPascalCase: Added. Converts a string toPascalCase, giving every word an uppercase first letter and a lowercase rest. It splits withwords, soXMLHttpRequestbecomesXmlHttpRequest.capitalizeEachWordsstays the one that keeps the original separatorsstrToKebabCase: Added. Converts a string tokebab-case, lowercasing every word and joining them with a hyphen. It splits withwords, soXMLHttpRequestbecomesxml-http-request.getSlugstays the URL-oriented onestrToSnakeCase: Added. Converts a string tosnake_case, lowercasing every word and joining them with an underscore. It splits withwords, soXMLHttpRequestbecomesxml_http_requestandabc12defbecomesabc_12_defstrToCamelCase: Added. Converts a string tocamelCase, lowercasing the first word and giving every word after it an uppercase first letter. It splits withwords, so an acronym stays whole (XMLHttpRequestbecomesxmlHttpRequest) and a run of digits is its own word (abc12defbecomesabc12Def)min: Added. Returns the smallest of the given numbers, accepting either n arguments or a single list exactly likesum. Values that are not numbers are skipped,boolamong them, and so isnan, which would otherwise win by losing every comparison. An empty input returnsNonemax: Added. Returns the largest of the given numbers, accepting either n arguments or a single list exactly likesum. Values that are not numbers are skipped,boolamong them, and so isnan, which would otherwise win by losing every comparison. An empty input returnsNonefloor: Added. Rounds a number down, to the given number of decimal places, a negative precision rounding down to tens, hundreds and so on. Rounding goes toward negative infinity, sofloor(-4.006)is-5. The value is read throughDecimal(str(value))and shifted by its exponent, sofloor(1.1, 1)is1.1ceil: Added. Rounds a number up, to the given number of decimal places, a negative precision rounding up to tens, hundreds and so on. Rounding goes toward positive infinity, soceil(-4.006)is-4. The value is read throughDecimal(str(value))and shifted by its exponent, soceil(1.1, 1)is1.1and not1.2round: Added. Rounds a number to the given number of decimal places, a negative precision rounding to tens, hundreds and so on. Ties go away from zero rather than to the nearest even number, so unlike the built-inroundit answers1for0.5and3for2.5, matching the JavaScript and Dart implementations. The value is read throughDecimal(str(value))and shifted by its exponent rather than multiplied by a power of ten, soround(1.005, 2)is1.01and not1clamp: Added. Restricts a number to an inclusive range, returningminbelow it andmaxabove it. The upper bound is applied first, sominwins when the two are passed the wrong way round, matching Lodash rather than Dart'snum.clamp, which throwsretry: Added. Runs the given function again on failure until it succeeds or the attempts run out, raising the last error if they all fail.timescounts total attempts (default3),delaywaits between them andbackoffmultiplies that wait after each failure. It is synchronous and waits withtime.sleep, assleepalready does.BaseExceptionis not caught, soKeyboardInterruptstill stops the loopthrottle: Added. Limits how often a function may run to at most once perwaitwindow, the counterpart ofdebounce.leadingandtrailing(bothTrueby default) choose which edge of the window runs. The trailing call is scheduled on a background thread, asdebouncealready doesobjInvert: Added. Returns a new object with the keys and values swapped. Values are converted to text because keys are always strings —NonebecomesnullNoneandTruebecomestrueTrue, and a wholefloatloses its fractional part, so the result matches the JavaScript implementation — and the later entry wins when two share a valueobjMapKeys: Added. Returns a new object whose keys are the values returned by the callback, with the values carried over untouched. The callback receives(value, key), and the later key wins when two map onto the same nameobjPickBy: Added. Returns a new object containing only the entries for which the callback returnstrueTrue. The callback receives(value, key), and only the top level is inspecteduncapitalizeFirst: Added. Converts the first letter of the entire string to lowercase, the inverse ofcapitalizeFirst. Only the first character is touched, soTESTbecomestESTescapeRegExp: Added. Escapes every regular expression metacharacter (^ $ . * + ? ( ) [ ] { } |and\) so a value can be matched literally. Unlikere.escapeit leaves-,#and whitespace alone, because those are special only inside a character class or in verbose mode, and escaping them would not match the JavaScript implementationdeburr: Added. Replaces accented Latin letters with their unaccented equivalents (déjà vubecomesdeja vu), spelling outÆ,ß,Þ,ŒandIJ, and dropping combining marks. Covers the Latin-1 Supplement and Latin Extended-A blockswords: Added. Splits a string into the words it is made of. Anything that is neither a letter nor a digit separates words, and camelCase boundaries, runs of capitals (XMLHttpRequestisXML,Http,Request) and runs of digits are split as wellarrIntersection: Added. Returns the values that are present in every one of the given arrays. The result is unique and keeps the order of the first arrayarrDifference: Added. Returns the values of the first array that are not contained in any of the other arrays. Values are compared by value rather than by identity, so nested lists and dicts are matched as wellarrCompact: Added. Returns a new array with every falsy value removed (None,False,0,'',nan). An empty list and an empty dict are kept, matching the JavaScript implementation
1.1.0 (2026-08-04)
- BREAKING CHANGES:
isValidFileNamenow rejects an empty name and any name carrying a control character (U+0000-U+001ForU+007F).NULis the one that matters: it terminates the path in the system call underneath every filesystem, so a name carrying one was reported as valid and then silently truncated on the way to disk - BREAKING CHANGES:
isValidFileNamenow rejects a name ending in a dot or a space on the Windows path. Windows strips it instead of reporting an error, soreport.quietly becomesreportand overwrites it. Unix keeps them, so they stay valid withunixType - BREAKING CHANGES:
isValidFileNamenow measures its 255 limit in UTF-8 bytes rather than characters, which is what ext4, APFS and NTFS enforce.'가' * 100is 100 characters but 300 bytes and cannot be created. Counting characters also disagreed with the JavaScript and Dart implementations, which count UTF-16 units where Python counted code points ('😀' * 130was valid here and invalid there) - BREAKING CHANGES:
headFileandtailFilenow replace malformed UTF-8 withU+FFFDinstead of raisingUnicodeDecodeError, matching the JavaScript and Dart implementations. One bad byte in a log file no longer stops it from being read - BREAKING CHANGES:
headFileandtailFilenow break a line on a lone\ras well as on\nand\r\n, matching Node's readline and Dart'sLineSplitter. A file written on a pre-OS X Mac used to come back as a single line - BREAKING CHANGES:
createDirectorynow reports the error when a file already sits at the path. It asked only whether something was there and then answered that there was nothing to do, so no directory existed and nothing said so - BREAKING CHANGES:
createFilenow creates any parent directory the path needs instead of raisingFileNotFoundError, matching the Dart implementation - BREAKING CHANGES:
createFile,deleteFileandmoveFilenow treat a path of nothing but whitespace as no path at all, matching the Dart implementation.createFile(' ')used to create a file literally named - BREAKING CHANGES:
getFileInfoandgetFileSizenow raise the originalOSErrorinstead of a plainExceptioncarrying only its text.errno,strerrorandfilenamewere dropped with it, so a caller could not tell a missing file from a permission error. The unreachablereturnboth functions ended with has been removed - BREAKING CHANGES:
getFileInfonow buildsdirnamewithos.path, which follows the host platform, instead of always splitting on/. A Windows path used to come back whole - BREAKING CHANGES:
toValidFilePathnow resolves a leading..against the root, so'../../etc/passwd'returns/etc/passwdinstead of/../../etc/passwd isFileHidden: Read the attribute letters out of the columnattribprints them in. Removing the caller's path from the output failed whenever a relative path was given, becauseattribanswers with an absolute one, and anyHin a directory name then read as hiddenheadFile: Read the file in chunks instead of pulling all of it into memory with a singleread(). Asking for the first line of a 108 MB log held 476 MB at once and now holds a chunktailFile: Read backwards from the end of the file a chunk at a time instead of walking it from the start, and stop popping the front of alength-sized list once per line. The old shape costlines × length: on a 108 MB log the last 20,000 lines took 6.8 seconds and now take 0.06, and the last single line went from 0.28 seconds to 0.001getCopyFileName: Accept asetas well as a list, and read it as it is. Naming n files into one directory calls this n times, and rebuilding the set on every call made that loop quadratic — 16,000 names took 11 seconds through a list and 0.03 seconds through a reusedsetmoveFile: Fall back to a copy and a remove when the operating system reportsEXDEV.os.renamecannot cross a filesystem boundary, so moving out of the temporary directory, into a mounted volume or onto another drive failed outrightisFileExists: Drop theos.accesscall whose result was thrown away, halving the system calls this makesgetFileInfo: Read the directory flag out of thestatresult already in hand instead of asking the filesystem a second time throughos.path.isdircreateDirectory: Drop theisFileExistscall that ran before everymakedirs.makedirswithexist_okis already a no-op for an existing directoryhasBadWords: Catch a banned word broken up by digits (ad1min,사1과,사123과), a common way of hiding a word in Korean. A digit that opens or closes a word is still read as a letter, so a number in front of a word (2시 발표) is not read away
1.0.0 (2026-07-28)
- BREAKING CHANGES:
encryptanddecryptnow honour thealgorithmargument. Every algorithm silently produced AES-CBC before, so a value such asaes-256-gcmwas accepted but ignored and the output did not match the JavaScript implementation. AEAD modes (GCM) now carry the authentication tag asiv:authTag:encrypted; theiv:encryptedformat for CBC is unchanged. The key length is validated against the algorithm, as it is in JavaScript - BREAKING CHANGES:
decryptnow validates PKCS7 padding, so decrypting with the wrong key raises instead of quietly returning an empty string - BREAKING CHANGES:
generateLicensenow normalizes thetypeargument correctly, so'Apache 2.0','apache-2.0'and'BSD 3'return the license they name instead of silently falling back to MIT (a missing character class in the normalizing regular expression made it a no-op) - BREAKING CHANGES:
numberHashandstrToAsciinow iterate UTF-16 code units, like the JavaScript and Dart implementations.ord()returns a code point, so characters outside the BMP produced different values ('😀'hashed to128512instead of1772899) - BREAKING CHANGES:
numUniquenow returns a millisecond timestamp combined with a per-millisecond sequence (16 digits) instead of a timestamp combined with a random number (18 digits). Repeated calls within a process are now always unique and strictly increasing - BREAKING CHANGES:
isEqualandisEqualStrictnow compare dicts instead of mistaking them for an argument list. Iterating a dict yielded its keys, so every dict comparison returnedFalse. Passing the operands as a list or tuple still works - BREAKING CHANGES:
objDeleteKeyByValue,objUpdate,arrShuffle,arrMove,sortNumericandsortByObjectKeyno longer modify the argument they are given; they all return a new dict or list - BREAKING CHANGES:
arrShufflenow returns a list when given a single element, instead of returning that element itself - BREAKING CHANGES:
sortNumericandsortByObjectKeynow applydescendingthrough the sort key instead of reversing the sorted result, so equal elements keep their relative order - BREAKING CHANGES:
safeParseIntnow treats0as a valid input instead of a missing one, sosafeParseInt(0, 99)returns0 - BREAKING CHANGES:
trimnow returnsNonefor any non-string input instead of raising anAttributeErroron truthy values such astrim(123) strBlindRandom: Keep the result the same length as the input. The character that was checked and the character that was masked were one position apart, and the index could land past the end of the string and append instead of maskgenerateLicense: Accept an optionsdictas the first positional argument, like the rest of the packageis2dArray: Return on the first nested list instead of building a filtered copy of the whole list (640ms to 0ms on a 100,000 element list)isBotAgent: Remove 84 of the 172 alternatives that were substrings of another one (botalready matchesnaverbot,bingbot, ...) and could never change the outcome — verified identical on 200,000 inputs. Roughly halves the matching costnumUnique: Stop building an 89,999 element list on every call to pick a single numbercapitalizeEachWords: Look the stop words up in afrozensetinstead of scanning a list throughcontains- BREAKING CHANGES:
durationnow hides milliseconds by default (enable withwithMilliSeconds) and uses grammatically correct plurals (e.g.0 Hours,1 Hour) - BREAKING CHANGES:
getFilePathLevelno longer counts a trailing separator as an extra level (/home/user/now returns the same level as/home/user) - BREAKING CHANGES:
getCopyFileNamenow preserves the original file extension casing (e.g.Report.PDFcopies toReport (1).PDFinstead ofReport (1).pdf) - BREAKING CHANGES:
isValidFileNamenow validates the whole name including its extension (sohello.:txtis invalid) and rejects Windows device names (CON,NUL,COM1-COM9,LPT1-LPT9, etc.) - BREAKING CHANGES:
createFileWithDummynow creates an empty file for a size of0instead of throwing, and throws a clearer error for a negative size - BREAKING CHANGES:
getParentFilePathnow returns the root (/or\) for an empty or single-segment path instead of/. - BREAKING CHANGES:
toValidFilePathnow returns the root (/or\) for a path that collapses to nothing instead of/. duration: SupportMonth(30 days) andYear(365 days) units, and addwithMilliSeconds,maxUnitCount, andunit(single-unit) optionsgetParsedInfoFromAddress: AddgetParsedInfoFromAddressmethodgetSlug: AddgetSlugmethodhasBadWords: AddhasBadWordsmethod
0.1.0 (2026-06-16)
- Initial release of the Python package
- Add
stringutilities:capitalizeEachWords,capitalizeEverySentence,capitalizeFirst,getGroupKeys,getStrBytes,removeNewLine,removeSpecialChar,replaceBetween,split,strBlindRandom,strCount,strRandom,strShuffle,strToAscii,strUnique,trim,truncate,truncateExpect,urlJoin - Add
arrayutilities:arrCount,arrGroupByMaxCount,arrMove,arrPick,arrRepeat,arrShuffle,arrTo1dArray,arrUnique,arrWithDefault,arrWithNumber,average,sortByObjectKey,sortNumeric - Add
objectutilities:objDeleteKeyByValue,objFindItemRecursiveByKey,objMergeNewKey,objTo1d,objToArray,objToPrettyStr,objToQueryString,objUpdate - Add
dateutilities:createDateListFromRange,dateToYYYYMMDD,dayDiff,isValidDate,today - Add
formatutilities:duration,fileSizeFormat,numberFormat,safeJSONParse,safeParseInt - Add
mathutilities:div,mul,numPick,numUnique,sub,sum - Add
verifyutilities:between,contains,is2dArray,isEmail,isEmpty,isEqual,isEqualStrict,isObject,isTrueMinimumNumberOfTimes,isUrl,len - Add
webutilities:generateLicense,isBotAgent,isMatchPathname,isMobile,removeLocalePrefix - Add
miscutilities:debounce,funcTimes,logBox,sleep(async functions are implemented synchronously) - Add
cryptoutilities:decodeBase64,decrypt,encodeBase64,encrypt,md5Hash,numberHash,objectId,sha1Hash,sha256Hash,sha512Hash(encrypt/decryptuse thecryptographypackage) - Add
fileutilities:createDirectory,createFile,createFileWithDummy,deleteAllFileFromDirectory,deleteFile,getCopyFileName,getFileExtension,getFileHashFromPath,getFileHashFromStream,getFileInfo,getFileName,getFilePathLevel,getFileSize,getParentFilePath,headFile,isFileExists,isFileHidden,isValidFileName,joinFilePath,moveFile,normalizeFile,tailFile,toPosixFilePath,toValidFilePath - Add
osutilities:getCpu,getHostname,getMachineId,getRamSize,getSid,getUptime,runCommand - Add
netutility:fetchData
