JFIF  ` ` ;CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 85 C   !"$"$ C hh"       } !1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz      w !1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz   ? .(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((+QI3L( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( @y -#yIޚXP2$袊 ( ( ( ( ( ( ( ( ( ( ( ( ( ( 3FE a(dN^M4GӁMoO$dssYz4]4+HM9վ2#OL@ܟH O@}LYW=p3! 7'Z&;" zםg|Ij~DǶr^2sI🆒TS(2?y}xmux#sھ[Cqg0mr\ ҏĺҋ{d^Rrr#mOŬ]\>uKcq*?ɯL񆥥Ƕ[ĆlO b[2+'c9Yl{I`:R fڽ;g8jc}ZC)ʑX匌J@:(P Hzh@#֌6Y$ʹ -ڛhJۆqi7s^{|c)]zyۿP+𗈬MaH_?LfG/U ( ( ( ( ( ( ( ("iX1?.ቨ.a?6I"|O+<.2H]aizhV3G8v|t".RcR7t+d(E~0 zD$r2ۜ~oC+Qsvx~%8 ~_|@Nկ81\gNMI#x ÞƠ W Cidlu;$1G5xh\NM#oL Zv6u+fd$HbaKiܻN?ʥt0F۟+g ]Q+r{8"28S4.ofXɑ|֗ x&s_Мp{W.14h~RME;XVX`q֡|:֢oB1fSBP_ WI~Ծ<04%ar UΉ>cy ~1b5w|Iϊ1ٯ4D`A y{-+N SkڲVCXR)M^ѠSc^3! }b}VBَ'9ִ/j~!]/DY_'׿} UQDRBͲ>GLsSnJQ(W Cx`rbF }G:~çivZ1Q =V&,gߥI}kdsѻ4RVEPEPEPEPEPEPH)I1@ (;=7JkO8j_ ٛVr\Q0 "=_Z;-8*ᛯ[ino ZU>#/9]x0]> 3u&%S9/PQVҭtIbxP ==*9 jPX7uMr3<`Z\g:^qV \WKg.잹ȩZ]][Pi۬h=V'O2VK0 TI`z'_֚CH/G Է4V 5, up쇖?夿w5j9]APn<:cs[V57 ]vAl*բp֖Z Pu{ _N]6@ȫaՏ@6sX+W1q@ tX 鴫`I8h3D Gm vCċiҝzRzP!Ҕ`p:P }>5|4VR!-䝒I,O98(=e"|ۦuK *pl?B k@u=$ Mz%%Sr~SsW۴ͧ1;Lg99qw:)Ծ~Ǟ+|7s]Md 9)V5"ھ;/?p MLGN=ҾÈ67c&XL1#}0瞾o};^̠yJ}}ǡǾ%!<zbfEe}I]ֽ NzZ-T0I WiiehRin-lPN׉bgfIìh% $L vˆ*n.Kr{waҷRnGz<+d63G <M4Ҽ' m4H ǪՅ$qpxZZ)gڊ(((((( W|sZ|akmD:rJELr~wkMCX _v4E|!e u.W%1zu?θߎ b%#QB#ApN9^78R ᭭DdA&ӶJ:h9>ct`lҝQ+9 erGn"  0=*(((((&4u+`=cpoōj:-pwp~Q*%*nH/=6a#4׎cÚwyC޾W})ǚEEQ4w_JȨÔjf5>Ϟ[<t(c ~m1K#SI1S@ Z@5F)E0 ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( )8;qzj6:s3yv ӥ b|J ͭj'*"㔃Ty ėc^lb=$7 N4a. R#!{\ts '᳣xj ao% T9ڔ4|QwZ|Z20k G>xO^;]o..tn7h ֆ[\y5/glKv:xu^)-_ۏLwOY5y` 6gҴ/ɬi[X~77O_ x>}NU =?=6;XDa+XSHRlA Q<7ֺ8@ԊzSA7qB Z(AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP^WZ#GkM-] eRH-##0'TH( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ^cef6b88lr1ڀ< &[^dB>ץYYh#0JpP c4  QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE QE 'use strict' module.exports = exports = search const npm = require('./npm.js') const allPackageSearch = require('./search/all-package-search') const figgyPudding = require('figgy-pudding') const formatPackageStream = require('./search/format-package-stream.js') const libSearch = require('libnpm/search') const log = require('npmlog') const ms = require('mississippi') const npmConfig = require('./config/figgy-config.js') const output = require('./utils/output.js') const usage = require('./utils/usage') search.usage = usage( 'search', 'npm search [--long] [search terms ...]' ) search.completion = function (opts, cb) { cb(null, []) } const SearchOpts = figgyPudding({ description: {}, exclude: {}, include: {}, limit: {}, log: {}, staleness: {}, unicode: {} }) function search (args, cb) { const opts = SearchOpts(npmConfig()).concat({ description: npm.config.get('description'), exclude: prepareExcludes(npm.config.get('searchexclude')), include: prepareIncludes(args, npm.config.get('searchopts')), limit: npm.config.get('searchlimit') || 20, log: log, staleness: npm.config.get('searchstaleness'), unicode: npm.config.get('unicode') }) if (opts.include.length === 0) { return cb(new Error('search must be called with arguments')) } // Used later to figure out whether we had any packages go out let anyOutput = false const entriesStream = ms.through.obj() let esearchWritten = false libSearch.stream(opts.include, opts).on('data', pkg => { entriesStream.write(pkg) !esearchWritten && (esearchWritten = true) }).on('error', err => { if (esearchWritten) { // If esearch errored after already starting output, we can't fall back. return entriesStream.emit('error', err) } log.warn('search', 'fast search endpoint errored. Using old search.') allPackageSearch(opts) .on('data', pkg => entriesStream.write(pkg)) .on('error', err => entriesStream.emit('error', err)) .on('end', () => entriesStream.end()) }).on('end', () => entriesStream.end()) // Grab a configured output stream that will spit out packages in the // desired format. var outputStream = formatPackageStream({ args: args, // --searchinclude options are not highlighted long: npm.config.get('long'), description: npm.config.get('description'), json: npm.config.get('json'), parseable: npm.config.get('parseable'), color: npm.color }) outputStream.on('data', chunk => { if (!anyOutput) { anyOutput = true } output(chunk.toString('utf8')) }) log.silly('search', 'searching packages') ms.pipe(entriesStream, outputStream, err => { if (err) return cb(err) if (!anyOutput && !npm.config.get('json') && !npm.config.get('parseable')) { output('No matches found for ' + (args.map(JSON.stringify).join(' '))) } log.silly('search', 'search completed') log.clearProgress() cb(null, {}) }) } function prepareIncludes (args, searchopts) { if (typeof searchopts !== 'string') searchopts = '' return searchopts.split(/\s+/).concat(args).map(function (s) { return s.toLowerCase() }).filter(function (s) { return s }) } function prepareExcludes (searchexclude) { var exclude if (typeof searchexclude === 'string') { exclude = searchexclude.split(/\s+/) } else { exclude = [] } return exclude.map(function (s) { return s.toLowerCase() }) }