node-gulp-4.0.2+~cs38.20.35/000077500000000000000000000000001415667007300150405ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/.ci/000077500000000000000000000000001415667007300155115ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/.ci/.azure-pipelines-steps.yml000066400000000000000000000020661415667007300225660ustar00rootroot00000000000000steps: - script: npm i -g npm@$(npm_version) displayName: Use legacy npm version $(npm_version) condition: ne(variables['npm_version'], '') - task: NodeTool@0 inputs: versionSpec: '$(node_version)' displayName: Use Node $(node_version) - script: npm install displayName: npm install - script: npm test displayName: Run tests - script: npm run coveralls displayName: Run coveralls env: # Pretend to be AppVeyor for now APPVEYOR: true APPVEYOR_BUILD_NUMBER: $(Build.BuildNumber) APPVEYOR_BUILD_ID: $(Agent.OS)_$(node_version) APPVEYOR_REPO_COMMIT: $(Build.SourceVersion) APPVEYOR_REPO_BRANCH: $(Build.SourceBranchName) # Overwrite the AppVeyor Service Name COVERALLS_SERVICE_NAME: Azure Pipelines COVERALLS_REPO_TOKEN: $(COVERALLS_REPO_TOKEN_SECRET) COVERALLS_PARALLEL: true CI_PULL_REQUEST: $(System.PullRequest.PullRequestNumber) - script: npm run azure-pipelines displayName: Write tests to xml - task: PublishTestResults@2 inputs: testResultsFiles: '**/test.xunit' condition: succeededOrFailed() node-gulp-4.0.2+~cs38.20.35/.ci/.azure-pipelines.yml000066400000000000000000000040501415667007300214250ustar00rootroot00000000000000trigger: - master - releases/* jobs: - job: Test_Linux displayName: Run Tests on Linux pool: vmImage: "Ubuntu 16.04" strategy: matrix: Node_v12: node_version: 12 Node_v10: node_version: 10 Node_v8: node_version: 8 Node_v6: node_version: 6 Node_v4: node_version: 4 Node_v0_12: node_version: 0.12 Node_v0_10: node_version: 0.10 steps: - template: .azure-pipelines-steps.yml - job: Test_Windows displayName: Run Tests on Windows pool: vmImage: vs2017-win2016 strategy: matrix: Node_v12: node_version: 12 Node_v10: node_version: 10 Node_v8: node_version: 8 Node_v6: node_version: 6 Node_v4: node_version: 4 npm_version: 2 Node_v0_12: node_version: 0.12 npm_version: 2 Node_v0_10: node_version: 0.10 npm_version: 2 steps: - template: .azure-pipelines-steps.yml - job: Test_MacOS displayName: Run Tests on MacOS pool: vmImage: macos-10.13 strategy: matrix: Node_v12: node_version: 12 Node_v10: node_version: 10 Node_v8: node_version: 8 Node_v6: node_version: 6 Node_v4: node_version: 4 Node_v0_12: node_version: 0.12 Node_v0_10: node_version: 0.10 steps: - template: .azure-pipelines-steps.yml - job: Notify_Coveralls displayName: Notify Coveralls that the parallel report is done pool: vmImage: "Ubuntu 16.04" dependsOn: - Test_Linux - Test_Windows - Test_MacOS steps: - script: curl -k https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN -d "payload[build_num]=$BUILD_NAME&payload[status]=done" env: COVERALLS_REPO_TOKEN: $(COVERALLS_REPO_TOKEN_SECRET) BUILD_NAME: $(Build.BuildNumber) node-gulp-4.0.2+~cs38.20.35/.editorconfig000066400000000000000000000003271415667007300175170ustar00rootroot00000000000000# https://editorconfig.org root = true [*] indent_style = space indent_size = 2 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true end_of_line = lf [*.md] trim_trailing_whitespace = false node-gulp-4.0.2+~cs38.20.35/.eslintrc000066400000000000000000000000301415667007300166550ustar00rootroot00000000000000{ "extends": "gulp" } node-gulp-4.0.2+~cs38.20.35/.gitattributes000066400000000000000000000001561415667007300177350ustar00rootroot00000000000000* text eol=lf # Denote all files that are truly binary and should not be modified. *.png binary *.jpg binary node-gulp-4.0.2+~cs38.20.35/.github/000077500000000000000000000000001415667007300164005ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/.github/ISSUE_TEMPLATE.md000066400000000000000000000016701415667007300211110ustar00rootroot00000000000000This tracker is for bug reports only. Before opening an issue, please make sure you've checked the following: - For support requests, please use Stack Overflow (stackoverflow.com) or Gitter (see the README). - If the bug is in a plugin, open an issue on the plugin repository, not the gulp repository. - If you're getting a deprecated module warning, don't worry about it: we're aware of it and it's not an issue. To make it go away, update to Gulp 4.0. - If you're asking about the status of Gulp 4, please don't! You can see the remaining issues on the gulp4 label: https://github.com/gulpjs/gulp/issues?q=is%3Aissue+is%3Aopen+label%3Agulp4 ---- **What were you expecting to happen?** **What actually happened?** **Please post a sample of your gulpfile (preferably reduced to just the bit that's not working)** ```js gulp.task(function () {}); ``` **What version of gulp are you using?** **What versions of npm and node are you using?** node-gulp-4.0.2+~cs38.20.35/.github/support.yml000066400000000000000000000016051415667007300206410ustar00rootroot00000000000000# Configuration for support-requests - https://github.com/dessant/support-requests supportLabel: support supportComment: > Issues are reserved for bugs and features. Here are a few places to find answers to your question: * For community support, use the `gulp` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/gulp). * Participate in community chat on [Gitter](https://gitter.im/gulpjs/gulp). * To get paid support directly from the maintainers, sign up for [Tidelift](https://tidelift.com/subscription/pkg/npm-gulp?utm_source=npm-gulp&utm_medium=referral&utm_campaign=support). Subscribers should email support@tidelift.com, mention that it's a question for Gulp, and describe your question. Straightforward questions are answered as part of your subscription. Additional consulting hours are available for more complex help. close: true lock: false setLockReason: false node-gulp-4.0.2+~cs38.20.35/.tidelift.yml000066400000000000000000000007161415667007300174510ustar00rootroot00000000000000ci: platform: NPM: # We use an older version that doesn't use ES6+ features to support back to node 0.10 eslint: tests: outdated: skip # We use an older version that doesn't use ES6+ features to support back to node 0.10 expect: tests: outdated: skip # We use an older version that doesn't use ES6+ features to support back to node 0.10 mocha: tests: outdated: skip node-gulp-4.0.2+~cs38.20.35/.travis.yml000066400000000000000000000002131415667007300171450ustar00rootroot00000000000000sudo: false language: node_js node_js: - '12' - '10' - '8' - '6' - '4' - '0.12' - '0.10' after_script: - npm run coveralls node-gulp-4.0.2+~cs38.20.35/CHANGELOG.md000066400000000000000000000172341415667007300166600ustar00rootroot00000000000000# gulp changelog ## 4.0.0 ### Task system changes - replaced 3.x task system (orchestrator) with new task system (bach) - removed gulp.reset - removed 3 argument syntax for `gulp.task` - `gulp.task` should only be used when you will call the task with the CLI - added `gulp.series` and `gulp.parallel` methods for composing tasks. Everything must use these now. - added single argument syntax for `gulp.task` which allows a named function to be used as the name of the task and task function. - added `gulp.tree` method for retrieving the task tree. Pass `{ deep: true }` for an `archy` compatible node list. - added `gulp.registry` for setting custom registries. ### CLI changes - split CLI out into a module if you want to save bandwidth/disk space. you can install the gulp CLI using either `npm install gulp -g` or `npm install gulp-cli -g`, where gulp-cli is the smaller one (no module code included) - add `--tasks-json` flag to CLI to dump the whole tree out for other tools to consume - added `--verify` flag to check the dependencies in package.json against the plugin blacklist. ### vinyl/vinyl-fs changes - added `gulp.symlink` which functions exactly like `gulp.dest`, but symlinks instead. - added `dirMode` param to `gulp.dest` and `gulp.symlink` which allows better control over the mode of the destination folder that is created. - globs passed to `gulp.src` will be evaluated in order, which means this is possible `gulp.src(['*.js', '!b*.js', 'bad.js'])` (exclude every JS file that starts with a b except bad.js) - performance for gulp.src has improved massively - `gulp.src(['**/*', '!b.js'])` will no longer eat CPU since negations happen during walking now - added `since` option to `gulp.src` which lets you only match files that have been modified since a certain date (for incremental builds) - fixed `gulp.src` not following symlinks - added `overwrite` option to `gulp.dest` which allows you to enable or disable overwriting of existing files ## 3.9.1 - update interpret to 1.0.0 (support for babel-register) - fix to include manpages in published tarball - documentation/recipe updates ## 3.9.0 - add babel support - add transpiler fallback support - add support for some renamed transpilers: livescript, etc - add JSCS - update dependencies (liftoff, interpret) - documentation tweaks ## 3.8.11 - fix node 0.12/iojs problems - add node 0.12 and iojs to travis - update dependencies (liftoff, v8flags) - documentation tweaks ## 3.8.10 - add link to spanish docs - update dependencies (archy, semver, mocha, etc) - documentation tweaks ## 3.8.9 - fix local version undefined output - add completion for fish shell - fix powershell completion line splitting - add support for arbitrary node flags (oops, should have been a minor bump) - add v8flags dependency - update dependencies (liftoff) - documentation tweaks ## 3.8.8 - update dependencies (minimist, tildify) - documentation tweaks ## 3.8.7 - handle errors a bit better - update dependencies (gulp-util, semver, etc) - documentation tweaks ## 3.8.6 - remove executable flag from LICENSE - update dependencies (chalk, minimist, liftoff, etc) - documentation tweaks ## 3.8.5 - simplify --silent and --tasks-simple - fix bug in autocomplete where errors would come out ## 3.8.4 - CLI will use exit code 1 on exit when any task fails during the lifetime of the process ## 3.8.3 - Tweak error formatting to work better with PluginErrors and strings ## 3.8.2 - add manpage generation ## 3.8.1 - the CLI now adds process.env.INIT_CWD which is the original cwd it was launched from ## 3.8.0 - update vinyl-fs - gulp.src is now a writable passthrough, this means you can use it to add files to your pipeline at any point - gulp.dest can now take a function to determine the folder This is now possible! ```js gulp.src('lib/*.js') .pipe(uglify()) .pipe(gulp.src('styles/*.css')) .pipe(gulp.dest(function(file){ // I don't know, you can do something cool here return 'build/whatever'; })); ``` ## 3.7.0 - update vinyl-fs to remove BOM from UTF8 files - add --tasks-simple flag for plaintext task listings - updated autocomplete scripts to be simpler and use new --tasks-simple flag - added support for transpilers via liftoff 0.11 and interpret - just npm install your compiler (coffee-script for example) and it will work out of the box ## 3.5.5 - update deps - gulp.dest now support mode option, uses source file mode by default (file.stat.mode) - use chalk for colors in bin - update gulp.env deprecation msg to be more helpful ## 3.5.2 - add -V for version on CLI (unix standard) - -v is deprecated, use -V - add -T as an alias for --tasks - documentation ## 3.5 - added `gulp.watch(globs, tasksArray)` sugar - remove gulp.taskQueue - deprecate gulp.run - deprecate gulp.env - add engineStrict to prevent people with node < 0.9 from installing ## 3.4 - added `--tasks` that prints out the tree of tasks + deps - global cli + local install mismatch is no longer fatal - remove tests for fs stuff - switch core src, dest, and watch to vinyl-fs - internal cleaning ## 3.3.4 - `--base` is now `--cwd` ## 3.3.3 - support for `--base` CLI arg to change where the search for gulpfile/`--require`s starts - support for `--gulpfile` CLI arg to point to a gulpfile specifically ## 3.3.0 - file.contents streams are no longer paused coming out of src - dest now passes files through before they are empty to fix passing to multiple dests ## 3.2.4 - Bug fix - we didn't have any CLI tests ## 3.2.3 - Update dependencies for bug fixes - autocomplete stuff in the completion folder ## 3.2 - File object is now [vinyl](https://github.com/wearefractal/vinyl) - .watch() is now [glob-watcher](https://github.com/wearefractal/glob-watcher) - Fix CLI -v when no gulpfile found - gulp-util updated - Logging moved to CLI bin file - Will cause double logging if you update global CLI to 3.2 but not local - Will cause no logging if you update local to 3.1 but not global CLI - Drop support for < 0.9 ## 3.1.3 - Move isStream and isBuffer to gulp-util ## 3.1 - Move file class to gulp-util ## 3.0 - Ability to pass multiple globs and glob negations to glob-stream - Breaking change to the way glob-stream works - File object is now a class - file.shortened changed to file.relative - file.cwd added - Break out getStats to avoid nesting - Major code reorganization ## 2.7 - Breaking change to the way options are passed to glob-stream - Introduce new File object to ease pain of computing shortened names (now a getter) ## 2.4 - 2.6 - Moved stuff to gulp-util - Quit exposing createGlobStream (just use the glob-stream module) - More logging - Prettier time durations - Tons of documentation changes - gulp.trigger(tasks...) as a through stream ## 1.2-2.4 (11/12/13) - src buffer=false fixed for 0.8 and 0.9 (remember to .resume() on these versions before consuming) - CLI completely rewritten - Colorful logging - Uses local version of gulp to run tasks - Uses findup to locate gulpfile (so you can run it anywhere in your project) - chdir to gulpfile directory before loading it - Correct exit codes on errors - silent flag added to gulp to disable logging - Fixes to task orchestration (3rd party) - Better support for globbed directories (thanks @robrich) ## 1.2 (10/28/13) - Can specify buffer=false on src streams to make file.content a stream - Can specify read=false on src streams to disable file.content ## 1.1 (10/21/13) - Can specify run callback - Can specify task dependencies - Tasks can accept callback or return promise - `gulp.verbose` exposes run-time internals ## 1.0 (9/26/13) - Specify dependency versions - Updated docs ## 0.2 (8/6/13) - Rename .files() to .src() and .folder() to .dest() ## 0.1 (7/18/13) - Initial Release node-gulp-4.0.2+~cs38.20.35/CONTRIBUTING.md000066400000000000000000000123211415667007300172700ustar00rootroot00000000000000# Request for contributions Please contribute to this repository if any of the following is true: - You have expertise in community development, communication, or education - You want open source communities to be more collaborative and inclusive - You want to help lower the burden to first time contributors # How to contribute Prerequisites: - familiarity with [GitHub PRs](https://help.github.com/articles/using-pull-requests) (pull requests) and issues - knowledge of Markdown for editing `.md` documents In particular, this community seeks the following types of contributions: - ideas: participate in an Issues thread or start your own to have your voice heard - resources: submit a PR to add to [docs README.md](/docs/README.md) with links to related content - outline sections: help us ensure that this repository is comprehensive. If there is a topic that is overlooked, please add it, even if it is just a stub in the form of a header and single sentence. Initially, most things fall into this category - write: contribute your expertise in an area by helping us expand the included content - copy editing: fix typos, clarify language, and generally improve the quality of the content - formatting: help keep content easy to read with consistent formatting - code: Fix issues or contribute new features to this or any related projects # Project structure Gulp itself is tiny: index.js contains [very few lines of code](https://github.com/gulpjs/gulp/blob/4.0/index.js). It is powered by a few other libraries which each handle a few specific tasks each. You can view all issues with the "help wanted" label across all gulp projects here: https://github.com/issues?utf8=%E2%9C%93&q=is%3Aopen+is%3Aissue+user%3Agulpjs+label%3A%22help+wanted%22+ ## Undertaker: task management Undertaker handles task management in Gulp: the `gulp.task()`, `gulp.series()` and `gulp.parallel()` functions. `gulp.series()` and `gulp.parallel()` are in turn powered by Bach. - https://github.com/gulpjs/undertaker - https://github.com/gulpjs/bach ## vinyl-fs: file streams vinyl-fs powers the `gulp.src()` and `gulp.dest()` functions: they take files and globs specified by the user, turns them into a stream of file objects, and then puts them back into the filesystem when `gulp.dest()` is called. The file objects themselves are vinyl objects: that's another library (a simple one!) - https://github.com/gulpjs/vinyl-fs - https://github.com/gulpjs/vinyl ## chokidar: file watching `gulp.watch()` is using chokidar for file watching. It's actually wrapped in a small library on the gulp organization, glob-watcher. - https://github.com/paulmillr/chokidar - https://github.com/gulpjs/glob-watcher ## gulp-cli: running gulp Finally, we have gulp-cli. This uses liftoff to take what people run in the command line and run the correct tasks. It works with both gulp 4 and older versions of gulp. - https://github.com/gulpjs/gulp-cli - https://github.com/js-cli/js-liftoff # Conduct We are committed to providing a friendly, safe and welcoming environment for all, regardless of gender, sexual orientation, disability, ethnicity, religion, or similar personal characteristic. On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all. Please be kind and courteous. There's no need to be mean or rude. Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer, merely an optimal answer given a set of values and circumstances. Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works. We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups. Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [gulpjs](https://github.com/orgs/gulpjs/people) core team immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back. Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome. # Communication There is an IRC channel on irc.freenode.net, channel `#gulpjs`. You're welcome to drop in and ask questions, discuss bugs and such. The channel is not currently logged. GitHub issues are the primary way for communicating about specific proposed changes to this project. In both contexts, please follow the conduct guidelines above. Language issues are often contentious and we'd like to keep discussion brief, civil and focused on what we're actually doing, not wandering off into too much imaginary stuff. # Frequently Asked Questions See [the FAQ docs page](/docs/FAQ.md) node-gulp-4.0.2+~cs38.20.35/EXPENSE_POLICY.md000066400000000000000000000033541415667007300175550ustar00rootroot00000000000000# Expense Policy ## Funding can be requested for significant changes made by Core Members. * Discuss the changes in the private gulp team forum. * Include a cost estimation with either a fixed price or hours + rate (suggested $50 per hour). * Notify the team before you exceed an estimate. ## Bug bounties may be assigned at the Core Members’ discretion to issues of significant importance - usually issues outstanding for at least 6 months. * Issues with bug bounties will be labeled “Bug Bounty: $x”. * In order to claim a bug bounty, create a Pull Request that fixes an issue with a “Bug Bounty” label. * The Pull Request must be reviewed and merged by a Core Member. If competing submissions exist, the best solution will be chosen by a Core Member. All else equal, the first submission will be chosen. * Once your Pull Request is merged, you can submit an expense to our [Open Collective](https://opencollective.com/gulpjs/expenses/new) which includes the link to your submission in the description (e.g. $100 bug bounty claim for https://github.com/gulpjs/gulp/pull/2226). You will also need to provide an invoice, see the [Open Collective Expense FAQ](https://opencollective.com/faq/expenses) for more details and to get a Google Docs template that you can use. * Then, add a comment on your Pull Request, noting that you’ve claimed the money, with a link to your Open Collective expense. This is to ensure the same person who fixed the issue is claiming the money. * Your expense will be validated by a Core Member and then your payment will be dispersed by Open Collective the following Friday. ## If you're doing other good things for gulp that end up costing you real money, feel free to reach out and we can discuss helping with those expenses! node-gulp-4.0.2+~cs38.20.35/LICENSE000066400000000000000000000022211415667007300160420ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2013-2018 Blaine Bublitz , Eric Schoffstall and other contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. node-gulp-4.0.2+~cs38.20.35/README.md000066400000000000000000000215251415667007300163240ustar00rootroot00000000000000

The streaming build system

[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Azure Pipelines Build Status][azure-pipelines-image]][azure-pipelines-url] [![Build Status][travis-image]][travis-url] [![AppVeyor Build Status][appveyor-image]][appveyor-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![OpenCollective Backers][backer-badge]][backer-url] [![OpenCollective Sponsors][sponsor-badge]][sponsor-url] [![Gitter chat][gitter-image]][gitter-url] ## What is gulp? - **Automation** - gulp is a toolkit that helps you automate painful or time-consuming tasks in your development workflow. - **Platform-agnostic** - Integrations are built into all major IDEs and people are using gulp with PHP, .NET, Node.js, Java, and other platforms. - **Strong Ecosystem** - Use npm modules to do anything you want + over 2000 curated plugins for streaming file transformations - **Simple** - By providing only a minimal API surface, gulp is easy to learn and simple to use ## What's new in 4.0?! * The task system was rewritten from the ground-up, allowing task composition using `series()` and `parallel()` methods * The watcher was updated, now using chokidar (no more need for gulp-watch!), with feature parity to our task system * First-class support was added for incremental builds using `lastRun()` * A `symlink()` method was exposed to create symlinks instead of copying files * Built-in support for sourcemaps was added - the gulp-sourcemaps plugin is no longer necessary! * Task registration of exported functions - using node or ES exports - is now recommended * Custom registries were designed, allowing for shared tasks or augmented functionality * Stream implementations were improved, allowing for better conditional and phased builds ## Installation Follow our [Quick Start guide][quick-start]. ## Roadmap Find out about all our work-in-progress and outstanding issues at https://github.com/orgs/gulpjs/projects. ## Documentation Check out the [Getting Started guide][getting-started-guide] and [API docs][api-docs] on our website! __Excuse our dust! All other docs will be behind until we get everything updated. Please open an issue if something isn't working.__ ## Sample `gulpfile.js` This file will give you a taste of what gulp does. ```js var gulp = require('gulp'); var less = require('gulp-less'); var babel = require('gulp-babel'); var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); var rename = require('gulp-rename'); var cleanCSS = require('gulp-clean-css'); var del = require('del'); var paths = { styles: { src: 'src/styles/**/*.less', dest: 'assets/styles/' }, scripts: { src: 'src/scripts/**/*.js', dest: 'assets/scripts/' } }; /* Not all tasks need to use streams, a gulpfile is just another node program * and you can use all packages available on npm, but it must return either a * Promise, a Stream or take a callback and call it */ function clean() { // You can use multiple globbing patterns as you would with `gulp.src`, // for example if you are using del 2.0 or above, return its promise return del([ 'assets' ]); } /* * Define our tasks using plain functions */ function styles() { return gulp.src(paths.styles.src) .pipe(less()) .pipe(cleanCSS()) // pass in options to the stream .pipe(rename({ basename: 'main', suffix: '.min' })) .pipe(gulp.dest(paths.styles.dest)); } function scripts() { return gulp.src(paths.scripts.src, { sourcemaps: true }) .pipe(babel()) .pipe(uglify()) .pipe(concat('main.min.js')) .pipe(gulp.dest(paths.scripts.dest)); } function watch() { gulp.watch(paths.scripts.src, scripts); gulp.watch(paths.styles.src, styles); } /* * Specify if tasks run in series or parallel using `gulp.series` and `gulp.parallel` */ var build = gulp.series(clean, gulp.parallel(styles, scripts)); /* * You can use CommonJS `exports` module notation to declare tasks */ exports.clean = clean; exports.styles = styles; exports.scripts = scripts; exports.watch = watch; exports.build = build; /* * Define default task that can be called by just running `gulp` from cli */ exports.default = build; ``` ## Use latest JavaScript version in your gulpfile __Most new versions of node support most features that Babel provides, except the `import`/`export` syntax. When only that syntax is desired, rename to `gulpfile.esm.js`, install the [esm][esm-module] module, and skip the Babel portion below.__ Node already supports a lot of __ES2015+__ features, but to avoid compatibility problems we suggest to install Babel and rename your `gulpfile.js` to `gulpfile.babel.js`. ```sh npm install --save-dev @babel/register @babel/core @babel/preset-env ``` Then create a **.babelrc** file with the preset configuration. ```js { "presets": [ "@babel/preset-env" ] } ``` And here's the same sample from above written in **ES2015+**. ```js import gulp from 'gulp'; import less from 'gulp-less'; import babel from 'gulp-babel'; import concat from 'gulp-concat'; import uglify from 'gulp-uglify'; import rename from 'gulp-rename'; import cleanCSS from 'gulp-clean-css'; import del from 'del'; const paths = { styles: { src: 'src/styles/**/*.less', dest: 'assets/styles/' }, scripts: { src: 'src/scripts/**/*.js', dest: 'assets/scripts/' } }; /* * For small tasks you can export arrow functions */ export const clean = () => del([ 'assets' ]); /* * You can also declare named functions and export them as tasks */ export function styles() { return gulp.src(paths.styles.src) .pipe(less()) .pipe(cleanCSS()) // pass in options to the stream .pipe(rename({ basename: 'main', suffix: '.min' })) .pipe(gulp.dest(paths.styles.dest)); } export function scripts() { return gulp.src(paths.scripts.src, { sourcemaps: true }) .pipe(babel()) .pipe(uglify()) .pipe(concat('main.min.js')) .pipe(gulp.dest(paths.scripts.dest)); } /* * You could even use `export as` to rename exported tasks */ function watchFiles() { gulp.watch(paths.scripts.src, scripts); gulp.watch(paths.styles.src, styles); } export { watchFiles as watch }; const build = gulp.series(clean, gulp.parallel(styles, scripts)); /* * Export a default task */ export default build; ``` ## Incremental Builds You can filter out unchanged files between runs of a task using the `gulp.src` function's `since` option and `gulp.lastRun`: ```js const paths = { ... images: { src: 'src/images/**/*.{jpg,jpeg,png}', dest: 'build/img/' } } function images() { return gulp.src(paths.images.src, {since: gulp.lastRun(images)}) .pipe(imagemin({optimizationLevel: 5})) .pipe(gulp.dest(paths.images.dest)); } function watch() { gulp.watch(paths.images.src, images); } ``` Task run times are saved in memory and are lost when gulp exits. It will only save time during the `watch` task when running the `images` task for a second time. ## Want to contribute? Anyone can help make this project better - check out our [Contributing guide](/CONTRIBUTING.md)! ## Backers Support us with a monthly donation and help us continue our activities. [![Backers][backers-image]][support-url] ## Sponsors Become a sponsor to get your logo on our README on Github. [![Sponsors][sponsors-image]][support-url] [downloads-image]: https://img.shields.io/npm/dm/gulp.svg [npm-url]: https://www.npmjs.com/package/gulp [npm-image]: https://img.shields.io/npm/v/gulp.svg [azure-pipelines-url]: https://dev.azure.com/gulpjs/gulp/_build/latest?definitionId=1&branchName=master [azure-pipelines-image]: https://dev.azure.com/gulpjs/gulp/_apis/build/status/gulp?branchName=master [travis-url]: https://travis-ci.org/gulpjs/gulp [travis-image]: https://img.shields.io/travis/gulpjs/gulp.svg?label=travis-ci [appveyor-url]: https://ci.appveyor.com/project/gulpjs/gulp [appveyor-image]: https://img.shields.io/appveyor/ci/gulpjs/gulp.svg?label=appveyor [coveralls-url]: https://coveralls.io/r/gulpjs/gulp [coveralls-image]: https://img.shields.io/coveralls/gulpjs/gulp/master.svg [gitter-url]: https://gitter.im/gulpjs/gulp [gitter-image]: https://badges.gitter.im/gulpjs/gulp.svg [backer-url]: #backers [backer-badge]: https://opencollective.com/gulpjs/backers/badge.svg?color=blue [sponsor-url]: #sponsors [sponsor-badge]: https://opencollective.com/gulpjs/sponsors/badge.svg?color=blue [support-url]: https://opencollective.com/gulpjs#support [backers-image]: https://opencollective.com/gulpjs/backers.svg [sponsors-image]: https://opencollective.com/gulpjs/sponsors.svg [quick-start]: https://gulpjs.com/docs/en/getting-started/quick-start [getting-started-guide]: https://gulpjs.com/docs/en/getting-started/quick-start [api-docs]: https://gulpjs.com/docs/en/api/concepts node-gulp-4.0.2+~cs38.20.35/appveyor.yml000066400000000000000000000007561415667007300174400ustar00rootroot00000000000000# https://www.appveyor.com/docs/appveyor-yml # https://www.appveyor.com/docs/lang/nodejs-iojs environment: matrix: # node.js - nodejs_version: "0.10" - nodejs_version: "0.12" - nodejs_version: "4" - nodejs_version: "6" - nodejs_version: "8" - nodejs_version: "10" install: - ps: Install-Product node $env:nodejs_version - npm install test_script: - node --version - npm --version - cmd: npm test build: off # build version format version: "{build}" node-gulp-4.0.2+~cs38.20.35/bin/000077500000000000000000000000001415667007300156105ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/bin/gulp.js000077500000000000000000000000541415667007300171170ustar00rootroot00000000000000#!/usr/bin/env node require('gulp-cli')(); node-gulp-4.0.2+~cs38.20.35/docs/000077500000000000000000000000001415667007300157705ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/docs/CLI.md000066400000000000000000000071711415667007300167270ustar00rootroot00000000000000## gulp CLI docs ### Flags gulp has very few flags to know about. All other flags are for tasks to use if needed. - `-v` or `--version` will display the global and local gulp versions - `--require ` will require a module before running the gulpfile. This is useful for transpilers but also has other applications. You can use multiple `--require` flags - `--gulpfile ` will manually set path of gulpfile. Useful if you have multiple gulpfiles. This will set the CWD to the gulpfile directory as well - `--cwd ` will manually set the CWD. The search for the gulpfile, as well as the relativity of all requires will be from here - `-T` or `--tasks` will display the task dependency tree for the loaded gulpfile. It will include the task names and their [description](./API.md#fndescription). - `--tasks-simple` will display a plaintext list of tasks for the loaded gulpfile - `--verify` will verify plugins referenced in project's package.json against the plugins blacklist - `--color` will force gulp and gulp plugins to display colors even when no color support is detected - `--no-color` will force gulp and gulp plugins to not display colors even when color support is detected - `--silent` will disable all gulp logging The CLI adds process.env.INIT_CWD which is the original cwd it was launched from. #### Task specific flags Refer to this [StackOverflow](https://stackoverflow.com/questions/23023650/is-it-possible-to-pass-a-flag-to-gulp-to-have-it-run-tasks-in-different-ways) link for how to add task specific flags ### Tasks Tasks can be executed by running `gulp ...`. If more than one task is listed, Gulp will execute all of them concurrently, that is, as if they had all been listed as dependencies of a single task. Gulp does not serialize tasks listed on the command line. From using other comparable tools users may expect to execute something like `gulp clean build`, with tasks named `clean` and `build`. This will not produce the intended result, as the two tasks will be executed concurrently. Just running `gulp` will execute the task `default`. If there is no `default` task, gulp will error. ### Compilers You can find a list of supported languages at [interpret](https://github.com/tkellen/node-interpret#jsvariants). If you would like to add support for a new language send pull request/open issues there. ### Examples #### Example gulpfile ```js gulp.task('one', function(done) { // do stuff done(); }); gulp.task('two', function(done) { // do stuff done(); }); gulp.task('three', three); function three(done) { done(); } three.description = "This is the description of task three"; gulp.task('four', gulp.series('one', 'two')); gulp.task('five', gulp.series('four', gulp.parallel('three', function(done) { // do more stuff done(); }) ) ); ``` ### `-T` or `--tasks` Command: `gulp -T` or `gulp --tasks` Output: ```shell [20:58:55] Tasks for ~\exampleProject\gulpfile.js [20:58:55] ├── one [20:58:55] ├── two [20:58:55] ├── three This is the description of task three [20:58:55] ├─┬ four [20:58:55] │ └─┬ [20:58:55] │ ├── one [20:58:55] │ └── two [20:58:55] ├─┬ five [20:58:55] │ └─┬ [20:58:55] │ ├─┬ four [20:58:55] │ │ └─┬ [20:58:55] │ │ ├── one [20:58:55] │ │ └── two [20:58:55] │ └─┬ [20:58:55] │ ├── three [20:58:55] │ └── ``` ### `--tasks-simple` Command: `gulp --tasks-simple` Output: ```shell one two three four five ``` node-gulp-4.0.2+~cs38.20.35/docs/FAQ.md000066400000000000000000000034051415667007300167230ustar00rootroot00000000000000# FAQ ## Why gulp? Why not ____? See the [gulp introduction slideshow] for a rundown on how gulp came to be. ## Is it "gulp" or "Gulp"? gulp is always lowercase. The only exception is in the gulp logo where gulp is capitalized. ## Where can I find a list of gulp plugins? gulp plugins always include the `gulpplugin` keyword. [Search gulp plugins][search-gulp-plugins] or [view all plugins][npm plugin search]. ## I want to write a gulp plugin, how do I get started? See the [Writing a gulp plugin] wiki page for guidelines and an example to get you started. ## My plugin does ____, is it doing too much? Probably. Ask yourself: 1. Is my plugin doing something that other plugins may need to do? - If so, that piece of functionality should be a separate plugin. [Check if it already exists on npm][npm plugin search]. 1. Is my plugin doing two, completely different things based on a configuration option? - If so, it may serve the community better to release it as two separate plugins - If the two tasks are different, but very closely related, it's probably OK ## How should newlines be represented in plugin output? Always use `\n` to prevent diff issues between operating systems. ## Where can I get updates on gulp? gulp updates can be found on the following twitters: - [@wearefractal](https://twitter.com/wearefractal) - [@eschoff](https://twitter.com/eschoff) - [@gulpjs](https://twitter.com/gulpjs) ## Does gulp have an chat channel? Yes, come chat with us on [Gitter](https://gitter.im/gulpjs/gulp). [Writing a gulp plugin]: writing-a-plugin/README.md [gulp introduction slideshow]: https://slid.es/contra/gulp [Freenode]: https://freenode.net/ [search-gulp-plugins]: https://gulpjs.com/plugins/ [npm plugin search]: https://npmjs.org/browse/keyword/gulpplugin node-gulp-4.0.2+~cs38.20.35/docs/README.md000066400000000000000000000063751415667007300172620ustar00rootroot00000000000000# gulp documentation * [Getting Started](getting-started/) - Get started with gulp * [API documentation](api/) - The programming interface, defined * [CLI documentation](CLI.md) - Learn how to call tasks and use compilers * [Writing a Plugin](writing-a-plugin/) - The essentials of writing a gulp plugin * [Why Use Pump?](why-use-pump/README.md) - Why to use the `pump` module instead of calling `.pipe` yourself * [Simplified Chinese documentation][SimplifiedChineseDocs] - gulp 简体中文文档 * [Korean documentation][KoreanDocs] - gulp 한국어 참조 문서 ## FAQ See the [FAQ](FAQ.md) for the answers to commonly asked questions. ## Recipes The community has written [recipes](recipes#recipes) for common gulp use-cases. ## Still got questions? Post on [StackOverflow with a #gulp tag](https://stackoverflow.com/questions/tagged/gulp) or come chat with us in [#gulpjs](https://webchat.freenode.net/?channels=gulpjs) on [Freenode](https://freenode.net/). ## Videos * [Intro to Gulp 4](https://youtu.be/N42LQ2dLoA8) presented by @addyosmani and @gauntface ## Books * [Developing a gulp Edge](http://shop.oreilly.com/product/9781939902146.do) * [Getting Started with Gulp – Second Edition](https://www.packtpub.com/application-development/getting-started-gulp-%E2%80%93-second-edition) - Travis Maynard, Packt (April 2017) ## Articles * [Tagtree intro to gulp video](http://tagtree.io/gulp) * [Introduction to node.js streams](https://github.com/substack/stream-handbook) * [Video introduction to node.js streams](https://www.youtube.com/watch?v=QgEuZ52OZtU) * [Getting started with gulp (by @markgdyr)](https://markgoodyear.com/2014/01/getting-started-with-gulp/) * [A cheatsheet for gulp](https://github.com/osscafe/gulp-cheatsheet) * [Why you shouldn’t create a gulp plugin (or, how to stop worrying and learn to love existing node packages)](http://blog.overzealous.com/post/74121048393/why-you-shouldnt-create-a-gulp-plugin-or-how-to-stop) * [Inspiration (slides) about why gulp was made](http://slid.es/contra/gulp) * [Building With Gulp](http://www.smashingmagazine.com/2014/06/11/building-with-gulp/) * [Gulp - The Basics (screencast)](https://www.youtube.com/watch?v=dwSLFai8ovQ) * [Get started with gulp (video series)](https://www.youtube.com/playlist?list=PLRk95HPmOM6PN-G1xyKj9q6ap_dc9Yckm) * [Optimize your web code with gulp](http://www.linuxuser.co.uk/tutorials/optimise-your-web-code-with-gulp-js) * [Automate Your Tasks Easily with Gulp.js ](https://scotch.io/tutorials/automate-your-tasks-easily-with-gulp-js) * [How to upgrade to Gulp v4](https://www.liquidlight.co.uk/blog/article/how-do-i-update-to-gulp-4/) ## Examples - [Web Starter Kit gulpfile](https://github.com/google/web-starter-kit/blob/master/gulpfile.babel.js) ## License All the documentation is covered by the CC0 license *(do whatever you want with it - public domain)*. [![CC0](https://i.creativecommons.org/p/zero/1.0/88x31.png)](https://creativecommons.org/publicdomain/zero/1.0/) To the extent possible under law, [Fractal](http://wearefractal.com) has waived all copyright and related or neighboring rights to this work. [SpanishDocs]: https://github.com/bucaran/gulp-docs-es [SimplifiedChineseDocs]: https://github.com/lisposter/gulp-docs-zh-cn [KoreanDocs]: https://github.com/preco21/gulp-docs-ko node-gulp-4.0.2+~cs38.20.35/docs/api/000077500000000000000000000000001415667007300165415ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/docs/api/README.md000066400000000000000000000006071415667007300200230ustar00rootroot00000000000000## Table of Contents * [API Concepts](concepts.md) * [src()](src.md) * [dest()](dest.md) * [symlink()](symlink.md) * [lastRun()](last-run.md) * [series()](series.md) * [parallel()](parallel.md) * [watch()](watch.md) * [task()](task.md) * [registry()](registry.md) * [tree()](tree.md) * [Vinyl](vinyl.md) * [Vinyl.isVinyl()](vinyl-isvinyl.md) * [Vinyl.isCustomProp()](vinyl-iscustomprop.md) node-gulp-4.0.2+~cs38.20.35/docs/api/concepts.md000066400000000000000000000121061415667007300207010ustar00rootroot00000000000000 # Concepts The following concepts are prerequisites to understanding the API docs. They will be referenced throughout, refer back to this page for detailed explanations. If you're new here, begin with the [Getting Started Guide][quick-start-docs]. ## Vinyl Vinyl is a metadata object that describes a file. The main properties of a Vinyl instance are `path` and `contents` - core aspects of a file on your file system. Vinyl objects can be used to describe files from many sources - on a local file system or any remote storage option. ## Vinyl adapters While Vinyl provides a way to describe a file, a way to access these files is needed. Each file source is accessed using a Vinyl adapter. An adapter exposes: * A method with the signature `src(globs, [options])` and returns a stream that produces Vinyl objects. * A method with the signature `dest(folder, [options])` and returns a stream that consumes Vinyl objects. * Any extra methods specific to their input/output medium - such as the `symlink` method `vinyl-fs` provides. They should always return streams that produce and/or consume Vinyl objects. ## Tasks Each gulp task is an asynchronous JavaScript function that either accepts an error-first callback or returns a stream, promise, event emitter, child process, or observable. Due to some platform limitations, synchronous tasks aren't supported. For a more detailed explanation, see [Creating Tasks][creating-tasks-doc]. ## Globs A glob is a string of literal and/or wildcard characters, like `*`, `**`, or `!`, used to match filepaths. Globbing is the act of locating files on a file system using one or more globs. If you don't have experience with globs, see [Explaining Globs][explaining-globs-docs]. ## Glob base A glob base - sometimes called glob parent - is the path segment before any special characters in a glob string. As such, the glob base of `/src/js/**.js` is `/src/js/`. All paths that match the glob are guaranteed to share the glob base - that path segment can't be variable. Vinyl instances generated by `src()` are constructed with the glob base set as their `base` property. When written to the file system with `dest()`, the `base` will be removed from the output path to preserve directory structures. For more in depth information, see the [glob-parent][glob-parent-external] repository. ## File system stats File metadata is provided as an instance of Node's [`fs.Stats`][fs-stats-external]. It is available as the `stat` property on your Vinyl instances and used internally to determine if a Vinyl object represents a directory or symbolic link. When written to the file system, permissions and time values are synchronized from the Vinyl object's `stat` property. ## File system modes File system modes determine what permissions exist for a file. Most files and directories on your file system will have a fairly permissive mode, allowing gulp to read/write/update files on your behalf. By default, gulp will create files with the same permissions as the running process, but you can configure the modes through options in `src()`, `dest()`, etc. If you're experiencing permission (EPERM) issues, check the modes on your files. ## Modules Gulp is made up of many small modules that are pulled together to work cohesively. By utilizing [semver][semver-external] within the small modules, we can release bug fixes and features without publishing new versions of gulp. Often, when you don't see progress on the main repository, work is being done in one of these modules. If you're having trouble, ensure your current modules are updated using the `npm update` command. If the problem persists, open an issue on the individual project repository. * [undertaker][undertaker-external] - the task registration system * [vinyl][vinyl-external] - the virtual file objects * [vinyl-fs][vinyl-fs-external] - a vinyl adapter to your local file system * [glob-watcher][glob-watcher-external] - the file watcher * [bach][bach-external] - task orchestration using `series()` and `parallel()` * [last-run][last-run-external] - tracks the last run time of a task * [vinyl-sourcemap][vinyl-sourcemap-external] - built-in sourcemap support * [gulp-cli][gulp-cli-external] - the command line interface for interacting with gulp [quick-start-docs]: ../getting-started/1-quick-start.md [creating-tasks-doc]: ../getting-started/3-creating-tasks.md [explaining-globs-docs]: ../getting-started/6-explaining-globs.md [undertaker-external]: https://github.com/gulpjs/undertaker [vinyl-external]: https://github.com/gulpjs/vinyl [vinyl-fs-external]: https://github.com/gulpjs/vinyl-fs [glob-watcher-external]: https://github.com/gulpjs/glob-watcher [bach-external]: https://github.com/gulpjs/bach [last-run-external]: https://github.com/gulpjs/last-run [vinyl-sourcemap-external]: https://github.com/gulpjs/vinyl-sourcemap [gulp-cli-external]: https://github.com/gulpjs/gulp-cli [semver-external]: https://semver.org [fs-stats-external]: https://nodejs.org/api/fs.html#fs_class_fs_stats [glob-parent-external]: https://github.com/es128/glob-parent node-gulp-4.0.2+~cs38.20.35/docs/api/dest.md000066400000000000000000000146651415667007300200360ustar00rootroot00000000000000 # dest() Creates a stream for writing [Vinyl][vinyl-concepts] objects to the file system. ## Usage ```js const { src, dest } = require('gulp'); function copy() { return src('input/*.js') .pipe(dest('output/')); } exports.copy = copy; ``` ## Signature ```js dest(directory, [options]) ``` ### Parameters | parameter | type | note | |:--------------:|:-----:|--------| | directory
**(required)** | string
function | The path of the output directory where files will be written. If a function is used, the function will be called with each Vinyl object and must return a string directory path. | | options | object | Detailed in [Options][options-section] below. | ### Returns A stream that can be used in the middle or at the end of a pipeline to create files on the file system. Whenever a Vinyl object is passed through the stream, it writes the contents and other details out to the file system at the given directory. If the Vinyl object has a `symlink` property, a symbolic link will be created instead of writing the contents. After the file is created, its [metadata will be updated][metadata-updates-section] to match the Vinyl object. Whenever a file is created on the file system, the Vinyl object will be modified. * The `cwd`, `base`, and `path` properties will be updated to match the created file. * The `stat` property will be updated to match the file on the file system. * If the `contents` property is a stream, it will be reset so it can be read again. ### Errors When `directory` is an empty string, throws an error with the message, "Invalid dest() folder argument. Please specify a non-empty string or a function." When `directory` is not a string or function, throws an error with the message, "Invalid dest() folder argument. Please specify a non-empty string or a function." When `directory` is a function that returns an empty string or `undefined`, emits an error with the message, "Invalid output folder". ### Options **For options that accept a function, the passed function will be called with each Vinyl object and must return a value of another listed type.** | name | type | default | note | |:-------:|:------:|-----------|-------| | cwd | string
function | `process.cwd()` | The directory that will be combined with any relative path to form an absolute path. Is ignored for absolute paths. Use to avoid combining `directory` with `path.join()`. | | mode | number
function | `stat.mode` of the Vinyl object | The mode used when creating files. If not set and `stat.mode` is missing, the process' mode will be used instead. | | dirMode | number
function | | The mode used when creating directories. If not set, the process' mode will be used. | | overwrite | boolean
function | true | When true, overwrites existing files with the same path. | | append | boolean
function | false | If true, adds contents to the end of the file, instead of replacing existing contents. | | sourcemaps | boolean
string
function | false | If true, writes inline sourcemaps to the output file. Specifying a `string` path will write external [sourcemaps][sourcemaps-section] at the given path. | | relativeSymlinks | boolean
function | false | When false, any symbolic links created will be absolute.
**Note**: Ignored if a junction is being created, as they must be absolute. | | useJunctions | boolean
function | true | This option is only relevant on Windows and ignored elsewhere. When true, creates directory symbolic link as a junction. Detailed in [Symbolic links on Windows][symbolic-links-section] below. | ## Metadata updates Whenever the `dest()` stream creates a file, the Vinyl object's `mode`, `mtime`, and `atime` are compared to the created file. If they differ, the created file will be updated to reflect the Vinyl object's metadata. If those properties are the same, or gulp doesn't have permissions to make changes, the attempt is skipped silently. This functionality is disabled on Windows or other operating systems that don't support Node's `process.getuid()` or `process.geteuid()` methods. This is due to Windows having unexpected results through usage of `fs.fchmod()` and `fs.futimes()`. **Note**: The `fs.futimes()` method internally converts `mtime` and `atime` timestamps to seconds. This division by 1000 may cause some loss of precision on 32-bit operating systems. ## Sourcemaps Sourcemap support is built directly into `src()` and `dest()`, but it is disabled by default. Enable it to produce inline or external sourcemaps. Inline sourcemaps: ```js const { src, dest } = require('gulp'); const uglify = require('gulp-uglify'); src('input/**/*.js', { sourcemaps: true }) .pipe(uglify()) .pipe(dest('output/', { sourcemaps: true })); ``` External sourcemaps: ```js const { src, dest } = require('gulp'); const uglify = require('gulp-uglify'); src('input/**/*.js', { sourcemaps: true }) .pipe(uglify()) .pipe(dest('output/', { sourcemaps: '.' })); ``` ## Symbolic links on Windows When creating symbolic links on Windows, a `type` argument is passed to Node's `fs.symlink()` method which specifies the kind of target being linked. The link type is set to: * `'file'` when the target is a regular file * `'junction'` when the target is a directory * `'dir'` when the target is a directory and the user disables the `useJunctions` option If you try to create a dangling (pointing to a non-existent target) link, the link type can't be determined automatically. In these cases, behavior will vary depending on whether the dangling link is being created via `symlink()` or via `dest()`. For dangling links created via `symlink()`, the incoming Vinyl object represents the target, so its stats will determine the desired link type. If `isDirectory()` returns false then a `'file'` link is created, otherwise a `'junction'` or a `'dir'` link is created depending on the value of the `useJunctions` option. For dangling links created via `dest()`, the incoming Vinyl object represents the link - typically loaded from disk via `src(..., { resolveSymlinks: false })`. In this case, the link type can't be reasonably determined and defaults to using `'file'`. This may cause unexpected behavior if you are creating a dangling link to a directory. **Avoid this scenario.** [sourcemaps-section]: #sourcemaps [symbolic-links-section]: #symbolic-links-on-windows [options-section]: #options [metadata-updates-section]: #metadata-updates [vinyl-concepts]: ../api/concepts.md#vinyl node-gulp-4.0.2+~cs38.20.35/docs/api/last-run.md000066400000000000000000000051041415667007300206300ustar00rootroot00000000000000 # lastRun() Retrieves the last time a task was successfully completed during the current running process. Most useful on subsequent task runs while a watcher is running. When combined with `src()`, enables incremental builds to speed up execution times by skipping files that haven't changed since the last successful task completion. ## Usage ```js const { src, dest, lastRun, watch } = require('gulp'); const imagemin = require('gulp-imagemin'); function images() { return src('src/images/**/*.jpg', { since: lastRun(images) }) .pipe(imagemin()) .pipe(dest('build/img/')); } exports.default = function() { watch('src/images/**/*.jpg', images); }; ``` ## Signature ```js lastRun(task, [precision]) ``` ### Parameters | parameter | type | note | |:--------------:|:------:|-------| | task
**(required)** | function
string | The task function or the string alias of a registered task. | | precision | number | Default: `1000` on Node v0.10, `0` on Node v0.12+. Detailed in [Timestamp precision][timestamp-precision-section] section below. | ### Returns A timestamp (in milliseconds), matching the last completion time of the task. If the task has not been run or has failed, returns `undefined`. To avoid an invalid state being cached, the returned value will be `undefined` if a task errors. ### Errors When called with a value other than a string or function, throws an error with the message, "Only functions can check lastRun". When called on a non-extensible function and Node is missing WeakMap, throws an error with the message, "Only extensible functions can check lastRun". ## Timestamp precision While there are sensible defaults for the precision of timestamps, they can be rounded using the `precision` parameter. Useful if your file system or Node version has a lossy precision on file time attributes. * `lastRun(someTask)` returns 1426000001111 * `lastRun(someTask, 100)` returns 1426000001100 * `lastRun(someTask, 1000)` returns 1426000001000 A file's [mtime stat][fs-stats-concepts] precision may vary depending on the node version and/or the file system used. | platform | precision | |:-----------:|:------------:| | Node v0.10 | 1000ms | | Node v0.12+ | 1ms | | FAT32 file system | 2000ms | | HFS+ or Ext3 file systems | 1000ms | | NTFS using Node v0.10 | 1s | | NTFS using Node 0.12+ | 100ms | | Ext4 using Node v0.10 | 1000ms | | Ext4 using Node 0.12+ | 1ms | [timestamp-precision-section]: #timestamp-precision [fs-stats-concepts]: ../api/concepts.md#file-system-stats node-gulp-4.0.2+~cs38.20.35/docs/api/parallel.md000066400000000000000000000063151415667007300206640ustar00rootroot00000000000000 # parallel() Combines task functions and/or composed operations into larger operations that will be executed simultaneously. There are no imposed limits on the nesting depth of composed operations using `series()` and `parallel()`. ## Usage ```js const { parallel } = require('gulp'); function javascript(cb) { // body omitted cb(); } function css(cb) { // body omitted cb(); } exports.build = parallel(javascript, css); ``` ## Signature ```js parallel(...tasks) ``` ### Parameters | parameter | type | note | |:--------------:|:------:|-------| | tasks
**(required)** | function
string | Any number of task functions can be passed as individual arguments. Strings can be used if you've registered tasks previously, but this is not recommended. | ### Returns A composed operation to be registered as a task or nested within other `series` and/or `parallel` compositions. When the composed operation is executed, all tasks will be run at maximum concurrency. If an error occurs in one task, other tasks nondeterministically may or may not complete. ### Errors When no tasks are passed, throws an error with the message, "One or more tasks should be combined using series or parallel". When invalid tasks or unregistered tasks are passed, throws an error with the message, "Task never defined". ## Forward references A forward reference is when you compose tasks, using string references, that haven't been registered yet. This was a common practice in older versions, but this feature was removed to achieve faster task runtime and promote the use of named functions. In newer versions, you'll get an error, with the message "Task never defined", if you try to use forward references. You may experience this when trying to use `exports` for task registration _and_ composing tasks by string. In this situation, use named functions instead of string references. During migration, you may need the [forward reference registry][undertaker-forward-reference-external]. This will add an extra closure to every task reference and dramatically slow down your build. **Don't rely on this fix for very long**. ## Avoid duplicating tasks When a composed operation is run, each task will be executed every time it was supplied. A `clean` task referenced in two different compositions would be run twice and lead to undesired results. Instead, refactor the `clean` task to be specified in the final composition. If you have code like this: ```js // This is INCORRECT const { series, parallel } = require('gulp'); const clean = function(cb) { // body omitted cb(); }; const css = series(clean, function(cb) { // body omitted cb(); }); const javascript = series(clean, function(cb) { // body omitted cb(); }); exports.build = parallel(css, javascript); ``` Migrate to this: ```js const { series, parallel } = require('gulp'); function clean(cb) { // body omitted cb(); } function css(cb) { // body omitted cb(); } function javascript(cb) { // body omitted cb(); } exports.build = series(clean, parallel(css, javascript)); ``` [undertaker-forward-reference-external]: https://github.com/gulpjs/undertaker-forward-reference node-gulp-4.0.2+~cs38.20.35/docs/api/registry.md000066400000000000000000000043551415667007300207420ustar00rootroot00000000000000 # registry() Allows custom registries to be plugged into the task system, which can provide shared tasks or augmented functionality. **Note:** Only tasks registered with `task()` will be provided to the custom registry. The task functions passed directly to `series()` or `parallel()` will not be provided - if you need to customize the registry behavior, compose tasks with string references. When assigning a new registry, each task from the current registry will be transferred and the current registry will be replaced with the new one. This allows for adding multiple custom registries in sequential order. See [Creating Custom Registries][creating-custom-registries] for details. ## Usage ```js const { registry, task, series } = require('gulp'); const FwdRef = require('undertaker-forward-reference'); registry(FwdRef()); task('default', series('forward-ref')); task('forward-ref', function(cb) { // body omitted cb(); }); ``` ## Signature ```js registry([registryInstance]) ``` ### Parameters | parameter | type | note | |:--------------:|:-----:|--------| | registryInstance | object | An instance - not the class - of a custom registry. | ### Returns If a `registryInstance` is passed, nothing will be returned. If no arguments are passed, returns the current registry instance. ### Errors When a constructor (instead of an instance) is passed as `registryInstance`, throws an error with the message, "Custom registries must be instantiated, but it looks like you passed a constructor". When a registry without a `get` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `get` function". When a registry without a `set` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `set` function". When a registry without an `init` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `init` function" When a registry without a `tasks` method is passed as `registryInstance`, throws an error with the message, "Custom registry must have `tasks` function". [creating-custom-registries]: ../documentation-missing.md node-gulp-4.0.2+~cs38.20.35/docs/api/series.md000066400000000000000000000063001415667007300203540ustar00rootroot00000000000000 # series() Combines task functions and/or composed operations into larger operations that will be executed one after another, in sequential order. There are no imposed limits on the nesting depth of composed operations using `series()` and `parallel()`. ## Usage ```js const { series } = require('gulp'); function javascript(cb) { // body omitted cb(); } function css(cb) { // body omitted cb(); } exports.build = series(javascript, css); ``` ## Signature ```js series(...tasks) ``` ### Parameters | parameter | type | note | |:--------------:|:------:|-------| | tasks
**(required)** | function
string | Any number of task functions can be passed as individual arguments. Strings can be used if you've registered tasks previously, but this is not recommended. | ### Returns A composed operation to be registered as a task or nested within other `series` and/or `parallel` compositions. When the composed operation is executed, all tasks will be run sequentially. If an error occurs in one task, no subsequent tasks will be run. ### Errors When no tasks are passed, throws an error with the message, "One or more tasks should be combined using series or parallel". When invalid tasks or unregistered tasks are passed, throws an error with the message, "Task never defined". ## Forward references A forward reference is when you compose tasks, using string references, that haven't been registered yet. This was a common practice in older versions, but this feature was removed to achieve faster task runtime and promote the use of named functions. In newer versions, you'll get an error, with the message "Task never defined", if you try to use forward references. You may experience this when trying to use `exports` for your task registration *and* composing tasks by string. In this situation, use named functions instead of string references. During migration, you may need to use the [forward reference registry][undertaker-forward-reference-external]. This will add an extra closure to every task reference and dramatically slow down your build. **Don't rely on this fix for very long**. ## Avoid duplicating tasks When a composed operation is run, each task will be executed every time it was supplied. A `clean` task referenced in two different compositions would be run twice and lead to undesired results. Instead, refactor the `clean` task to be specified in the final composition. If you have code like this: ```js // This is INCORRECT const { series, parallel } = require('gulp'); const clean = function(cb) { // body omitted cb(); }; const css = series(clean, function(cb) { // body omitted cb(); }); const javascript = series(clean, function(cb) { // body omitted cb(); }); exports.build = parallel(css, javascript); ``` Migrate to this: ```js const { series, parallel } = require('gulp'); function clean(cb) { // body omitted cb(); } function css(cb) { // body omitted cb(); } function javascript(cb) { // body omitted cb(); } exports.build = series(clean, parallel(css, javascript)); ``` [undertaker-forward-reference-external]: https://github.com/gulpjs/undertaker-forward-reference node-gulp-4.0.2+~cs38.20.35/docs/api/src.md000066400000000000000000000215641415667007300176620ustar00rootroot00000000000000 # src() Creates a stream for reading [Vinyl][vinyl-concepts] objects from the file system. **Note:** BOMs (byte order marks) have no purpose in UTF-8 and will be removed from UTF-8 files read by `src()`, unless disabled using the `removeBOM` option. ## Usage ```javascript const { src, dest } = require('gulp'); function copy() { return src('input/*.js') .pipe(dest('output/')); } exports.copy = copy; ``` ## Signature ```js src(globs, [options]) ``` ### Parameters | parameter | type | note | |:--------------:|:------:|-------| | globs | string
array | [Globs][globs-concepts] to watch on the file system. | | options | object | Detailed in [Options][options-section] below. | ### Returns A stream that can be used at the beginning or in the middle of a pipeline to add files based on the given globs. ### Errors When the `globs` argument can only match one file (such as `foo/bar.js`) and no match is found, throws an error with the message, "File not found with singular glob". To suppress this error, set the `allowEmpty` option to `true`. When an invalid glob is given in `globs`, throws an error with the message, "Invalid glob argument". ### Options **For options that accept a function, the passed function will be called with each Vinyl object and must return a value of another listed type.** | name | type | default | note | |:--------:|:------:|------------|--------| | buffer | boolean
function | true | When true, file contents are buffered into memory. If false, the Vinyl object's `contents` property will be a paused stream. It may not be possible to buffer the contents of large files.
**Note:** Plugins may not implement support for streaming contents. | | read | boolean
function | true | If false, files will be not be read and their Vinyl objects won't be writable to disk via `.dest()`. | | since | date
timestamp
function | | When set, only creates Vinyl objects for files modified since the specified time. | | removeBOM | boolean
function | true | When true, removes the BOM from UTF-8 encoded files. If false, ignores a BOM. | | sourcemaps | boolean
function | false | If true, enables [sourcemaps][sourcemaps-section] support on Vinyl objects created. Loads inline sourcemaps and resolves external sourcemap links. | | resolveSymlinks | boolean
function | true | When true, recursively resolves symbolic links to their targets. If false, preserves the symbolic links and sets the Vinyl object's `symlink` property to the original file's path. | | cwd | string | `process.cwd()` | The directory that will be combined with any relative path to form an absolute path. Is ignored for absolute paths. Use to avoid combining `globs` with `path.join()`.
_This option is passed directly to [glob-stream][glob-stream-external]._ | | base | string | | Explicitly set the `base` property on created Vinyl objects. Detailed in [API Concepts][glob-base-concepts].
_This option is passed directly to [glob-stream][glob-stream-external]._ | | cwdbase | boolean | false | If true, `cwd` and `base` options should be aligned.
_This option is passed directly to [glob-stream][glob-stream-external]._ | | root | string | | The root path that `globs` are resolved against.
_This option is passed directly to [glob-stream][glob-stream-external]._ | | allowEmpty | boolean | false | When false, `globs` which can only match one file (such as `foo/bar.js`) causes an error to be thrown if they don't find a match. If true, suppresses glob failures.
_This option is passed directly to [glob-stream][glob-stream-external]._ | | uniqueBy | string
function | `'path'` | Remove duplicates from the stream by comparing the string property name or the result of the function.
**Note:** When using a function, the function receives the streamed data (objects containing `cwd`, `base`, `path` properties). | | dot | boolean | false | If true, compare globs against dot files, like `.gitignore`.
_This option is passed directly to [node-glob][node-glob-external]._ | | silent | boolean | true | When true, suppresses warnings from printing on `stderr`.
**Note:** This option is passed directly to [node-glob][node-glob-external] but defaulted to `true` instead of `false`. | | mark | boolean | false | If true, a `/` character will be appended to directory matches. Generally not needed because paths are normalized within the pipeline.
_This option is passed directly to [node-glob][node-glob-external]._ | | nosort | boolean | false | If true, disables sorting the glob results.
_This option is passed directly to [node-glob][node-glob-external]._ | | stat | boolean | false | If true, `fs.stat()` is called on all results. This adds extra overhead and generally should not be used.
_This option is passed directly to [node-glob][node-glob-external]._ | | strict | boolean | false | If true, an error will be thrown if an unexpected problem is encountered while attempting to read a directory.
_This option is passed directly to [node-glob][node-glob-external]._ | | nounique | boolean | false | When false, prevents duplicate files in the result set.
_This option is passed directly to [node-glob][node-glob-external]._ | | debug | boolean | false | If true, debugging information will be logged to the command line.
_This option is passed directly to [node-glob][node-glob-external]._ | | nobrace | boolean | false | If true, avoids expanding brace sets - e.g. `{a,b}` or `{1..3}`.
_This option is passed directly to [node-glob][node-glob-external]._ | | noglobstar | boolean | false | If true, treats double-star glob character as single-star glob character.
_This option is passed directly to [node-glob][node-glob-external]._ | | noext | boolean | false | If true, avoids matching [extglob][extglob-docs] patterns - e.g. `+(ab)`.
_This option is passed directly to [node-glob][node-glob-external]._ | | nocase | boolean | false | If true, performs a case-insensitive match.
**Note:** On case-insensitive file systems, non-magic patterns will match by default.
_This option is passed directly to [node-glob][node-glob-external]._ | | matchBase | boolean | false | If true and globs don't contain any `/` characters, traverses all directories and matches that glob - e.g. `*.js` would be treated as equivalent to `**/*.js`.
_This option is passed directly to [node-glob][node-glob-external]._ | | nodir | boolean | false | If true, only matches files, not directories.
**Note:** To match only directories, end your glob with a `/`.
_This option is passed directly to [node-glob][node-glob-external]._ | | ignore | string
array | | Globs to exclude from matches. This option is combined with negated `globs`.
**Note:** These globs are always matched against dot files, regardless of any other settings.
_This option is passed directly to [node-glob][node-glob-external]._ | | follow | boolean | false | If true, symlinked directories will be traversed when expanding `**` globs.
**Note:** This can cause problems with cyclical links.
_This option is passed directly to [node-glob][node-glob-external]._ | | realpath | boolean | false | If true, `fs.realpath()` is called on all results. This may result in dangling links.
_This option is passed directly to [node-glob][node-glob-external]._ | | cache | object | | A previously generated cache object - avoids some file system calls.
_This option is passed directly to [node-glob][node-glob-external]._ | | statCache | object | | A previously generated cache of `fs.Stat` results - avoids some file system calls.
_This option is passed directly to [node-glob][node-glob-external]._ | | symlinks | object | | A previously generated cache of symbolic links - avoids some file system calls.
_This option is passed directly to [node-glob][node-glob-external]._ | | nocomment | boolean | false | When false, treat a `#` character at the start of a glob as a comment.
_This option is passed directly to [node-glob][node-glob-external]._ | ## Sourcemaps Sourcemap support is built directly into `src()` and `dest()`, but is disabled by default. Enable it to produce inline or external sourcemaps. Inline sourcemaps: ```js const { src, dest } = require('gulp'); const uglify = require('gulp-uglify'); src('input/**/*.js', { sourcemaps: true }) .pipe(uglify()) .pipe(dest('output/', { sourcemaps: true })); ``` External sourcemaps: ```js const { src, dest } = require('gulp'); const uglify = require('gulp-uglify'); src('input/**/*.js', { sourcemaps: true }) .pipe(uglify()) .pipe(dest('output/', { sourcemaps: '.' })); ``` [sourcemaps-section]: #sourcemaps [options-section]: #options [vinyl-concepts]: ../api/concepts.md#vinyl [glob-base-concepts]: ../api/concepts.md#glob-base [globs-concepts]: ../api/concepts.md#globs [extglob-docs]: ../documentation-missing.md [node-glob-external]: https://github.com/isaacs/node-glob [glob-stream-external]: https://github.com/gulpjs/glob-stream node-gulp-4.0.2+~cs38.20.35/docs/api/symlink.md000066400000000000000000000107771415667007300205650ustar00rootroot00000000000000 # symlink() Creates a stream for linking [Vinyl][vinyl-concepts] objects to the file system. ## Usage ```js const { src, symlink } = require('gulp'); function link() { return src('input/*.js') .pipe(symlink('output/')); } exports.link = link; ``` ## Signature ```js symlink(directory, [options]) ``` ### Parameters | parameter | type | note | |:--------------:|:-----:|--------| | directory
**(required)** | string
function | The path of the output directory where symbolic links will be created. If a function is used, the function will be called with each Vinyl object and must return a string directory path. | | options | object | Detailed in [Options][options-section] below. | ### Returns A stream that can be used in the middle or at the end of a pipeline to create symbolic links on the file system. Whenever a Vinyl object is passed through the stream, it creates a symbolic link to the original file on the file system at the given directory. Whenever a symbolic link is created on the file system, the Vinyl object will be modified. * The `cwd`, `base`, and `path` properties will be updated to match the created symbolic link. * The `stat` property will be updated to match the symbolic link on the file system. * The `contents` property will be set to `null`. * The `symlink` property will be added or replaced with original path. **Note:** On Windows, directory links are created using junctions by default. The `useJunctions` option disables this behavior. ### Errors When `directory` is an empty string, throws an error with the message, "Invalid symlink() folder argument. Please specify a non-empty string or a function." When `directory` is not a string or function, throws an error with the message, "Invalid symlink() folder argument. Please specify a non-empty string or a function." When `directory` is a function that returns an empty string or `undefined`, emits an error with the message, "Invalid output folder". ### Options **For options that accept a function, the passed function will be called with each Vinyl object and must return a value of another listed type.** | name | type | default | note | |:-------:|:------:|-----------|-------| | cwd | string
function | `process.cwd()` |The directory that will be combined with any relative path to form an absolute path. Is ignored for absolute paths. Use to avoid combining `directory` with `path.join()`. | | dirMode | number
function | | The mode used when creating directories. If not set, the process' mode will be used. | | overwrite | boolean
function | true | When true, overwrites existing files with the same path. | | relativeSymlinks | boolean
function | false | When false, any symbolic links created will be absolute.
**Note**: Ignored if a junction is being created, as they must be absolute. | | useJunctions | boolean
function | true | This option is only relevant on Windows and ignored elsewhere. When true, creates directory symbolic link as a junction. Detailed in [Symbolic links on Windows][symbolic-links-section] below. | ## Symbolic links on Windows When creating symbolic links on Windows, a `type` argument is passed to Node's `fs.symlink()` method which specifies the type of target being linked. The link type is set to: * `'file'` when the target is a regular file * `'junction'` when the target is a directory * `'dir'` when the target is a directory and the user disables the `useJunctions` option If you try to create a dangling (pointing to a non-existent target) link, the link type can't be determined automatically. In these cases, behavior will vary depending on whether the dangling link is being created via `symlink()` or via `dest()`. For dangling links created via `symlink()`, the incoming Vinyl object represents the target, so its stats will determine the desired link type. If `isDirectory()` returns false then a `'file'` link is created, otherwise a `'junction'` or `'dir'` link is created depending on the value of the `useJunctions` option. For dangling links created via `dest()`, the incoming Vinyl object represents the link - typically loaded from disk via `src(..., { resolveSymlinks: false })`. In this case, the link type can't be reasonably determined and defaults to using `'file'`. This may cause unexpected behavior when creating a dangling link to a directory. **Avoid this scenario.** [options-section]: #options [symbolic-links-section]: #symbolic-links-on-windows [vinyl-concepts]: ../api/concepts.md#vinyl node-gulp-4.0.2+~cs38.20.35/docs/api/task.md000066400000000000000000000066411415667007300200340ustar00rootroot00000000000000 # task() **Reminder**: This API isn't the recommended pattern anymore - [export your tasks][creating-tasks-docs]. Defines a task within the task system. The task can then be accessed from the command line and the `series()`, `parallel()`, and `lastRun()` APIs. ## Usage Register a named function as a task: ```js const { task } = require('gulp'); function build(cb) { // body omitted cb(); } task(build); ``` Register an anonymous function as a task: ```js const { task } = require('gulp'); task('build', function(cb) { // body omitted cb(); }); ``` Retrieve a task that has been registered previously: ```js const { task } = require('gulp'); task('build', function(cb) { // body omitted cb(); }); const build = task('build'); ``` ## Signature ```js task([taskName], taskFunction) ``` ### Parameters If the `taskName` is not provided, the task will be referenced by the `name` property of a named function or a user-defined `displayName` property. The `taskName` parameter must be used for anonymous functions missing a `displayName` property. Since any registered task can be run from the command line, avoid using spaces in task names. | parameter | type | note | |:--------------:|:------:|-------| | taskName | string | An alias for the task function within the the task system. Not needed when using named functions for `taskFunction`. | | taskFunction
**(required)** | function | A [task function][task-concepts] or composed task - generated by `series()` and `parallel()`. Ideally a named function. [Task metadata][task-metadata-section] can be attached to provide extra information to the command line. | ### Returns When registering a task, nothing is returned. When retrieving a task, a wrapped task (not the original function) registered as `taskName` will be returned. The wrapped task has an `unwrap()` method that will return the original function. ### Errors When registering a task where `taskName` is missing and `taskFunction` is anonymous, will throw an error with the message, "Task name must be specified". ## Task metadata | property | type | note | |:--------------:|:------:|-------| | name | string | A special property of named functions. Used to register the task.
**Note:** [`name`][function-name-external] is not writable; it cannot be set or changed. | | displayName | string | When attached to a `taskFunction` creates an alias for the task. If using characters that aren't allowed in function names, use this property. | | description | string | When attached to a `taskFunction` provides a description to be printed by the command line when listing tasks. | | flags | object | When attached to a `taskFunction` provides flags to be printed by the command line when listing tasks. The keys of the object represent the flags and the values are their descriptions. | ```js const { task } = require('gulp'); const clean = function(cb) { // body omitted cb(); }; clean.displayName = 'clean:all'; task(clean); function build(cb) { // body omitted cb(); } build.description = 'Build the project'; build.flags = { '-e': 'An example flag' }; task(build); ``` [task-metadata-section]: #task-metadata [task-concepts]: ../api/concepts.md#tasks [creating-tasks-docs]: ../getting-started/3-creating-tasks.md [function-name-external]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name node-gulp-4.0.2+~cs38.20.35/docs/api/tree.md000066400000000000000000000067241415667007300200330ustar00rootroot00000000000000 # tree() Fetches the current task dependency tree - in the rare case that it is needed. Generally, `tree()` won't be used by gulp consumers, but it is exposed so the CLI can show the dependency graph of the tasks defined in a gulpfile. ## Usage Example gulpfile: ```js const { series, parallel } = require('gulp'); function one(cb) { // body omitted cb(); } function two(cb) { // body omitted cb(); } function three(cb) { // body omitted cb(); } const four = series(one, two); const five = series(four, parallel(three, function(cb) { // Body omitted cb(); }) ); module.exports = { one, two, three, four, five }; ``` Output for `tree()`: ```js { label: 'Tasks', nodes: [ 'one', 'two', 'three', 'four', 'five' ] } ``` Output for `tree({ deep: true })`: ```js { label: "Tasks", nodes: [ { label: "one", type: "task", nodes: [] }, { label: "two", type: "task", nodes: [] }, { label: "three", type: "task", nodes: [] }, { label: "four", type: "task", nodes: [ { label: "", type: "function", branch: true, nodes: [ { label: "one", type: "function", nodes: [] }, { label: "two", type: "function", nodes: [] } ] } ] }, { label: "five", type: "task", nodes: [ { label: "", type: "function", branch: true, nodes: [ { label: "", type: "function", branch: true, nodes: [ { label: "one", type: "function", nodes: [] }, { label: "two", type: "function", nodes: [] } ] }, { label: "", type: "function", branch: true, nodes: [ { label: "three", type: "function", nodes: [] }, { label: "", type: "function", nodes: [] } ] } ] } ] } ] } ``` ## Signature ```js tree([options]) ``` ### Parameters | parameter | type | note | |:--------------:|------:|--------| | options | object | Detailed in [Options][options-section] below. | ### Returns An object detailing the tree of registered tasks - containing nested objects with `'label'` and `'nodes'` properties (which is [archy][archy-external] compatible). Each object may have a `type` property that can be used to determine if the node is a `task` or `function`. Each object may have a `branch` property that, when `true`, indicates the node was created using `series()` or `parallel()`. ### Options | name | type | default | note | |:-------:|:-------:|------------|--------| | deep | boolean | false | If true, the entire tree will be returned. When false, only top level tasks will be returned. | [options-section]: #options [archy-external]: https://www.npmjs.com/package/archy node-gulp-4.0.2+~cs38.20.35/docs/api/vinyl-iscustomprop.md000066400000000000000000000032341415667007300227730ustar00rootroot00000000000000 # Vinyl.isCustomProp() Determines if a property is internally managed by Vinyl. Used by Vinyl when setting values inside the constructor or when copying properties in the `clone()` instance method. This method is useful when extending the Vinyl class. Detailed in [Extending Vinyl][extending-vinyl-section] below. ## Usage ```js const Vinyl = require('vinyl'); Vinyl.isCustomProp('sourceMap') === true; Vinyl.isCustomProp('path') === false; ``` ## Signature ```js Vinyl.isCustomProp(property) ``` ### Parameters | parameter | type | note | |:--------------:|:------:|-------| | property | string | The property name to check. | ### Returns True if the property is not internally managed. ## Extending Vinyl When custom properties are managed internally, the static `isCustomProp` method must be extended and return false when one of the custom properties is queried. ```js const Vinyl = require('vinyl'); const builtInProps = ['foo', '_foo']; class SuperFile extends Vinyl { constructor(options) { super(options); this._foo = 'example internal read-only value'; } get foo() { return this._foo; } static isCustomProp(name) { return super.isCustomProp(name) && builtInProps.indexOf(name) === -1; } } ``` In the example above, `foo` and `_foo` will not be assigned to the new object when cloning or passed in `options` to `new SuperFile(options)`. If your custom properties or logic require special handling during cloning, override the `clone` method while extending Vinyl. [extending-vinyl-section]: #extending-vinyl node-gulp-4.0.2+~cs38.20.35/docs/api/vinyl-isvinyl.md000066400000000000000000000014031415667007300217150ustar00rootroot00000000000000 # Vinyl.isVinyl() Determines if an object is a Vinyl instance. Use this method instead of `instanceof`. **Note**: This method uses an internal property that some older versions of Vinyl didn't expose resulting in a false negative if using an outdated version. ## Usage ```js const Vinyl = require('vinyl'); const file = new Vinyl(); const notAFile = {}; Vinyl.isVinyl(file) === true; Vinyl.isVinyl(notAFile) === false; ``` ## Signature ```js Vinyl.isVinyl(file); ``` ### Parameters | parameter | type | note | |:--------------:|:------:|-------| | file | object | The object to check. | ### Returns True if the `file` object is a Vinyl instance. node-gulp-4.0.2+~cs38.20.35/docs/api/vinyl.md000066400000000000000000000203471415667007300202320ustar00rootroot00000000000000 # Vinyl A virtual file format. When a file is read by `src()`, a Vinyl object is generated to represent the file - including the path, contents, and other metadata. Vinyl objects can have transformations applied using [plugins][using-plugins-docs]. They may also be persisted to the file system using `dest()`. When creating your own Vinyl objects - instead of generating with `src()` - use the external `vinyl` module, as shown in Usage below. ## Usage ```js const Vinyl = require('vinyl'); const file = new Vinyl({ cwd: '/', base: '/test/', path: '/test/file.js', contents: new Buffer('var x = 123') }); file.relative === 'file.js'; file.dirname === '/test'; file.dirname = '/specs'; file.path === '/specs/file.js'; file.basename === 'file.js'; file.basename = 'file.txt'; file.path === '/specs/file.txt'; file.stem === 'file'; file.stem = 'foo'; file.path === '/specs/foo.txt'; file.extname === '.txt'; file.extname = '.js'; file.path === '/specs/file.js'; ``` ## Signature ```js new Vinyl([options]) ``` ### Parameters | parameter | type | note | |:--------------:|:------:|-------| | options | object | Detailed in [Options][options-section] below. | ### Returns An instance of the Vinyl class representing a single virtual file, detailed in [Vinyl instance][vinyl-instance-section] below. ### Errors When any passed options don't conform to the [instance property definitions][instance-properties-section] (like if `path` is set to a number) throws as defined in the table. ### Options | name | type | default | note | |:-------:|:------:|-----------|--------| | cwd | string | `process.cwd()` | The directory from which relative paths will be derived. Will be [normalized][normalization-and-concatenation-section] and have trailing separators removed. | | base | string | | Used to calculate the `relative` instance property. Falls back to the value of `cwd` if not set. Typically set to the [glob base][glob-base-concepts]. Will be [normalized][normalization-and-concatenation-section] and have trailing separators removed.| | path | string | | The full, absolute file path. Will be [normalized][normalization-and-concatenation-section] and have trailing separators removed. | | history | array | `[ ]` | An array of paths to pre-populate the `history` of a Vinyl instance. Usually comes from deriving a new Vinyl object from a previous Vinyl object. If `path` and `history` are both passed, `path` is appended to `history`. Each item will be [normalized][normalization-and-concatenation-section] and have trailing separators removed. | | stat | object | | An instance of `fs.Stats`, usually the result of calling `fs.stat()` on a file. Used to determine if a Vinyl object represents a directory or symbolic link. | | contents | ReadableStream
Buffer
`null` | `null` | The contents of the file. If `contents` is a ReadableStream, it is wrapped in a [cloneable-readable][cloneable-readable-external] stream. | Any other properties on `options` will be directly assigned to the Vinyl instance. ```js const Vinyl = require('vinyl'); const file = new Vinyl({ foo: 'bar' }); file.foo === 'bar'; ``` ## Vinyl instance Each instance of a Vinyl object will have properties and methods to access and/or modify information about the virtual file. ### Instance properties All internally managed paths - any instance property except `contents` and `stat` - are normalized and have trailing separators removed. See [Normalization and concatenation][normalization-and-concatenation-section] for more information. | property | type | description | throws | |:-----------:|:------:|----------------|----------| | contents | ReadableStream
Buffer
`null` | Gets and sets the contents of the virtual file. If set to a ReadableStream, it is wrapped in a [cloneable-readable][cloneable-readable-external] stream. | If set to any value other than a ReadableStream, a Buffer, or `null`. | | stat | object | Gets and sets an instance of [`fs.Stats`][fs-stats-concepts]. Used when determining if a Vinyl object represents a directory or symbolic link. | | | cwd | string | Gets and sets the current working directory. Used for deriving relative paths. | If set to an empty string or any non-string value. | | base | string | Gets and sets the base directory. Used to calculate the `relative` instance property. On a Vinyl object generated by `src()` will be set to the [glob base][glob-base-concepts]. If set to `null` or `undefined`, falls back to the value of the `cwd` instance property. | If set to an empty string or any non-string value (except `null` or `undefined`). | | path | string | Gets and sets the full, absolute file path. Setting to a value different from the current `path` appends the new path to the `history` instance property. | If set to any non-string value. | | history | array | Array of all `path` values the Vinyl object has been assigned. The first element is the original path and the last element is the current path. This property and its elements should be treated as read-only and only altered indirectly by setting the `path` instance property. | | | relative | string | Gets the relative path segment between the `base` and the `path` instance properties. | If set to any value. If accessed when `path` is not available. | | dirname | string | Gets and sets the directory of the `path` instance property. | If accessed when `path` is not available. | | stem | string | Gets and sets the stem (filename without extension) of the `path` instance property. | If accessed when `path` is not available. | | extname | string | Gets and sets the extension of the `path` instance property. | If accessed when `path` is not available. | | basename | string | Gets and sets the filename (`stem + extname`) of the `path` instance property. | If accessed when `path` is not available. | | symlink | string | Gets and sets the reference path of a symbolic link. | If set to any non-string value. | ### Instance methods | method | return type | returns | |:----------:|:--------------:|--------| | `isBuffer()` | boolean | If the `contents` instance property is a Buffer, returns true. | | `isStream()` | boolean | If the `contents` instance property is a Stream, returns true. | | `isNull()` | boolean | If the `contents` instance property is `null`, returns true. | | `isDirectory()` | boolean | If the instance represents a directory, returns true. An instance is considered a directory when `isNull()` returns true, the `stat` instance property is an object, and `stat.isDirectory()` returns true. This assumes a Vinyl object was constructed with a valid (or properly mocked) `fs.Stats` object. | | `isSymbolic()` | boolean | If the instance represents a symbolic link, returns true. An instance is considered symbolic when `isNull()` returns true, the `stat` instance property is an object, and `stat.isSymbolicLink()` returns true. This assumes a Vinyl object was constructed with a valid (or properly mocked) `fs.Stats` object. | | `clone([options])` | object | A new Vinyl object with all properties cloned. By default custom properties are deep cloned. If the `deep` option is false, custom attributes will be shallow cloned. If the `contents` option is false and the `contents` instance property is a Buffer, the Buffer will be reused instead of cloned. | | `inspect()` | string | Returns a formatted interpretation of the Vinyl object. Automatically called by Node's console.log. | ## Normalization and concatenation All path properties are normalized by their setters. Concatenate paths with `/`, instead of using `path.join()`, and normalization will occur properly on all platforms. Never concatenate with `\` - it is a valid filename character on POSIX system. ```js const file = new File(); file.path = '/' + 'test' + '/' + 'foo.bar'; console.log(file.path); // posix => /test/foo.bar // win32 => \\test\\foo.bar ``` [options-section]: #options [vinyl-instance-section]: #vinyl-instance [instance-properties-section]: #instance-properties [normalization-and-concatenation-section]: #normalization-and-concatenation [glob-base-concepts]: ../api/concepts.md#glob-base [fs-stats-concepts]: ../api/concepts.md#file-system-stats [using-plugins-docs]: ../getting-started/7-using-plugins.md [cloneable-readable-external]: https://github.com/mcollina/cloneable-readable node-gulp-4.0.2+~cs38.20.35/docs/api/watch.md000066400000000000000000000202401415667007300201670ustar00rootroot00000000000000 # watch() Allows watching globs and running a task when a change occurs. Tasks are handled uniformly with the rest of the task system. ## Usage ```js const { watch } = require('gulp'); watch(['input/*.js', '!input/something.js'], function(cb) { // body omitted cb(); }); ``` ## Signature ```js watch(globs, [options], [task]) ``` ### Parameters | parameter | type | note | |:--------------:|:-----:|--------| | globs
**(required)** | string
array | [Globs][globs-concepts] to watch on the file system. | | options | object | Detailed in [Options][options-section] below. | | task | function
string | A [task function][tasks-concepts] or composed task - generated by `series()` and `parallel()`. | ### Returns An instance of [chokidar][chokidar-instance-section] for fine-grained control over your watch setup. ### Errors When a non-string or array with any non-strings is passed as `globs`, throws an error with the message, "Non-string provided as watch path". When a string or array is passed as `task`, throws an error with the message, "watch task has to be a function (optionally generated by using gulp.parallel or gulp.series)". ### Options | name | type | default | note | |:-------:|:------:|-----------|--------| | ignoreInitial | boolean | true | If false, the task is called during instantiation as file paths are discovered. Use to trigger the task during startup.
**Note:** This option is passed to [chokidar][chokidar-external] but is defaulted to `true` instead of `false`. | | delay | number | 200 | The millisecond delay between a file change and task execution. Allows for waiting on many changes before executing a task, e.g. find-and-replace on many files. | | queue | boolean | true | When true and the task is already running, any file changes will queue a single task execution. Keeps long running tasks from overlapping. | | events | string
array | [ 'add',
'change',
'unlink' ] | The events being watched to trigger task execution. Can be `'add'`, `'addDir'`, `'change'`, `'unlink'`, `'unlinkDir'`, `'ready'`, and/or `'error'`. Additionally `'all'` is available, which represents all events other than `'ready'` and `'error'`.
_This option is passed directly to [chokidar][chokidar-external]._ | | persistent | boolean | true | If false, the watcher will not keep the Node process running. Disabling this option is not recommended.
_This option is passed directly to [chokidar][chokidar-external]._ | | ignored | array
string
RegExp
function | | Defines globs to be ignored. If a function is provided, it will be called twice per path - once with just the path, then with the path and the `fs.Stats` object of that file.
_This option is passed directly to [chokidar][chokidar-external]._ | | followSymlinks | boolean | true | When true, changes to both symbolic links and the linked files trigger events. If false, only changes to the symbolic links trigger events.
_This option is passed directly to [chokidar][chokidar-external]._ | | cwd | string | | The directory that will be combined with any relative path to form an absolute path. Is ignored for absolute paths. Use to avoid combining `globs` with `path.join()`.
_This option is passed directly to [chokidar][chokidar-external]._ | | disableGlobbing | boolean | false | If true, all `globs` are treated as literal path names, even if they have special characters.
_This option is passed directly to [chokidar][chokidar-external]._ | | usePolling | boolean | false | When false, the watcher will use `fs.watch()` (or [fsevents][fsevents-external] on Mac) for watching. If true, use `fs.watchFile()` polling instead - needed for successfully watching files over a network or other non-standard situations. Overrides the `useFsEvents` default.
_This option is passed directly to [chokidar][chokidar-external]._ | | interval | number | 100 | Combine with `usePolling: true`. Interval of file system polling.
_This option is passed directly to [chokidar][chokidar-external]._ | | binaryInterval | number | 300 | Combine with `usePolling: true`. Interval of file system polling for binary files.
_This option is passed directly to [chokidar][chokidar-external]._ | | useFsEvents | boolean | true | When true, uses fsevents for watching if available. If explicitly set to true, supersedes the `usePolling` option. If set to false, automatically sets `usePolling` to true.
_This option is passed directly to [chokidar][chokidar-external]._ | | alwaysStat | boolean | false | If true, always calls `fs.stat()` on changed files - will slow down file watcher. The `fs.Stat` object is only available if you are using the chokidar instance directly.
_This option is passed directly to [chokidar][chokidar-external]._ | | depth | number | | Indicates how many nested levels of directories will be watched.
_This option is passed directly to [chokidar][chokidar-external]._ | | awaitWriteFinish | boolean | false | Do not use this option, use `delay` instead.
_This option is passed directly to [chokidar][chokidar-external]._ | | ignorePermissionErrors | boolean | false | Set to true to watch files that don't have read permissions. Then, if watching fails due to EPERM or EACCES errors, they will be skipped silently.
_This option is passed directly to [chokidar][chokidar-external]._ | | atomic | number | 100 | Only active if `useFsEvents` and `usePolling` are false. Automatically filters out artifacts that occur from "atomic writes" by some editors. If a file is re-added within the specified milliseconds of being deleted, a change event - instead of unlink then add - will be emitted.
_This option is passed directly to [chokidar][chokidar-external]._ | ## Chokidar instance The `watch()` method returns the underlying instance of [chokidar][chokidar-external], providing fine-grained control over your watch setup. Most commonly used to register individual event handlers that provide the `path` or `stats` of the changed files. **When using the chokidar instance directly, you will not have access to the task system integrations, including async completion, queueing, and delay.** ```js const { watch } = require('gulp'); const watcher = watch(['input/*.js']); watcher.on('change', function(path, stats) { console.log(`File ${path} was changed`); }); watcher.on('add', function(path, stats) { console.log(`File ${path} was added`); }); watcher.on('unlink', function(path, stats) { console.log(`File ${path} was removed`); }); watcher.close(); ``` `watcher.on(eventName, eventHandler)` Registers `eventHandler` functions to be called when the specified event occurs. | parameter | type | note | |:--------------:|:-----:|--------| | eventName | string | The events that may be watched are `'add'`, `'addDir'`, `'change'`, `'unlink'`, `'unlinkDir'`, `'ready'`, `'error'`, or `'all'`. | | eventHandler | function | Function to be called when the specified event occurs. Arguments detailed in the table below. | | argument | type | note | |:-------------:|:-----:|--------| | path | string | The path of the file that changed. If the `cwd` option was set, the path will be made relative by removing the `cwd`. | | stats | object | An [fs.Stat][fs-stats-concepts] object, but could be `undefined`. If the `alwaysStat` option was set to `true`, `stats` will always be provided. | `watcher.close()` Shuts down the file watcher. Once shut down, no more events will be emitted. `watcher.add(globs)` Adds additional globs to an already-running watcher instance. | parameter | type | note | |:-------------:|:-----:|--------| | globs | string
array | The additional globs to be watched. | `watcher.unwatch(globs)` Removes globs that are being watched, while the watcher continues with the remaining paths. | parameter | type | note | |:-------------:|:-----:|--------| | globs | string
array | The globs to be removed. | [chokidar-instance-section]: #chokidar-instance [options-section]: #options [tasks-concepts]: ../api/concepts.md#tasks [globs-concepts]: ../api/concepts.md#globs [fs-stats-concepts]: ../api/concepts.md#file-system-stats [chokidar-external]: https://github.com/paulmillr/chokidar [fsevents-external]: https://github.com/strongloop/fsevents node-gulp-4.0.2+~cs38.20.35/docs/documentation-missing.md000066400000000000000000000007661415667007300226430ustar00rootroot00000000000000 # Excuse our dust! We're in the process of rewriting **all** our documentation and some of the links we've added to completed docs haven't been written yet. You've likely clicked on one of those to end up here. We're sorry about that but please check back later on the topic you're interested in. If you want to help out, we'll happily accept a Pull Request for this missing documentation. -The Gulp Team node-gulp-4.0.2+~cs38.20.35/docs/getting-started.md000066400000000000000000000003431415667007300214170ustar00rootroot00000000000000## This documentation has moved! You can find the new documentation in our [Quick Start](getting-started/1-quick-start.md) guide. While you are there, check out our expanded [Getting Started](getting-started/) documentation. node-gulp-4.0.2+~cs38.20.35/docs/getting-started/000077500000000000000000000000001415667007300210755ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/docs/getting-started/1-quick-start.md000066400000000000000000000043411415667007300240260ustar00rootroot00000000000000 # Quick Start If you've previously installed gulp globally, run `npm rm --global gulp` before following these instructions. For more information, read this [Sip][sip-article]. ## Check for node, npm, and npx ```sh node --version ``` ![Output: v8.11.1][img-node-version-command] ```sh npm --version ``` ![Output: 5.6.0][img-npm-version-command] ```sh npx --version ``` ![Output: 9.7.1][img-npx-version-command] If they are not installed, follow the instructions [here][node-install]. ## Install the gulp command line utility ```sh npm install --global gulp-cli ``` ## Create a project directory and navigate into it ```sh npx mkdirp my-project ``` ```sh cd my-project ``` ## Create a package.json file in your project directory ```sh npm init ``` This will guide you through giving your project a name, version, description, etc. ## Install the gulp package in your devDependencies ```sh npm install --save-dev gulp ``` ## Verify your gulp versions ```sh gulp --version ``` Ensure the output matches the screenshot below or you might need to restart the steps in this guide. ![Output: CLI version 2.0.1 & Local version 4.0.0][img-gulp-version-command] ## Create a gulpfile Using your text editor, create a file named gulpfile.js in your project root with these contents: ```js function defaultTask(cb) { // place code for your default task here cb(); } exports.default = defaultTask ``` ## Test it Run the gulp command in your project directory: ```sh gulp ``` To run multiple tasks, you can use `gulp `. ## Result The default task will run and do nothing. ![Output: Starting default & Finished default][img-gulp-command] [sip-article]: https://medium.com/gulpjs/gulp-sips-command-line-interface-e53411d4467 [node-install]: https://nodejs.org/en/ [img-node-version-command]: https://gulpjs.com/img/docs-node-version-command.png [img-npm-version-command]: https://gulpjs.com/img/docs-npm-version-command.png [img-npx-version-command]: https://gulpjs.com/img/docs-npx-version-command.png [img-gulp-version-command]: https://gulpjs.com/img/docs-gulp-version-command.png [img-gulp-command]: https://gulpjs.com/img/docs-gulp-command.png node-gulp-4.0.2+~cs38.20.35/docs/getting-started/2-javascript-and-gulpfiles.md000066400000000000000000000051061415667007300264560ustar00rootroot00000000000000 # JavaScript and Gulpfiles Gulp allows you to use existing JavaScript knowledge to write gulpfiles or to use your experience with gulpfiles to write plain JavaScript. Although a few utilities are provided to simplify working with the filesystem and command line, everything else you write is pure JavaScript. ## Gulpfile explained A gulpfile is a file in your project directory titled `gulpfile.js` (or capitalized as `Gulpfile.js`, like Makefile), that automatically loads when you run the `gulp` command. Within this file, you'll often see gulp APIs, like `src()`, `dest()`, `series()`, or `parallel()` but any vanilla JavaScript or Node modules can be used. Any exported functions will be registered into gulp's task system. ## Transpilation You can write a gulpfile using a language that requires transpilation, like TypeScript or Babel, by changing the extension on your `gulpfile.js` to indicate the language and install the matching transpiler module. * For TypeScript, rename to `gulpfile.ts` and install the [ts-node][ts-node-module] module. * For Babel, rename to `gulpfile.babel.js` and install the [@babel/register][babel-register-module] module. __Most new versions of node support most features that TypeScript or Babel provide, except the `import`/`export` syntax. When only that syntax is desired, rename to `gulpfile.esm.js` and install the [esm][esm-module] module.__ For a more advanced dive into this topic and the full list of supported extensions, see our [gulpfile transpilation][gulpfile-transpilation-advanced] documentation. ## Splitting a gulpfile Many users start by adding all logic to a gulpfile. If it ever grows too big, it can be refactored into separate files. Each task can be split into its own file, then imported into your gulpfile for composition. Not only does this keep things organized, but it allows you to test each task independently or vary composition based on conditions. Node's module resolution allows you to replace your `gulpfile.js` file with a directory named `gulpfile.js` that contains an `index.js` file which is treated as a `gulpfile.js`. This directory could then contain your individual modules for tasks. If you are using a transpiler, name the folder and file accordingly. [gulpfile-transpilation-advanced]: ../documentation-missing.md [ts-node-module]: https://www.npmjs.com/package/ts-node [babel-register-module]: https://www.npmjs.com/package/@babel/register [esm-module]: https://www.npmjs.com/package/esm node-gulp-4.0.2+~cs38.20.35/docs/getting-started/3-creating-tasks.md000066400000000000000000000115611415667007300245020ustar00rootroot00000000000000 # Creating Tasks Each gulp task is an asynchronous JavaScript function - a function that accepts an error-first callback or returns a stream, promise, event emitter, child process, or observable ([more on that later][async-completion-docs]). Due to some platform limitations, synchronous tasks aren't supported, though there is a pretty nifty [alternative][using-async-await-docs]. ## Exporting Tasks can be considered **public** or **private**. * **Public tasks** are exported from your gulpfile, which allows them to be run by the `gulp` command. * **Private tasks** are made to be used internally, usually used as part of `series()` or `parallel()` composition. A private task looks and acts like any other task, but an end-user can't ever execute it independently. To register a task publicly, export it from your gulpfile. ```js const { series } = require('gulp'); // The `clean` function is not exported so it can be considered a private task. // It can still be used within the `series()` composition. function clean(cb) { // body omitted cb(); } // The `build` function is exported so it is public and can be run with the `gulp` command. // It can also be used within the `series()` composition. function build(cb) { // body omitted cb(); } exports.build = build; exports.default = series(clean, build); ``` ![ALT TEXT MISSING][img-gulp-tasks-command] In the past, `task()` was used to register your functions as tasks. While that API is still available, exporting should be the primary registration mechanism, except in edge cases where exports won't work. ## Compose tasks Gulp provides two powerful composition methods, `series()` and `parallel()`, allowing individual tasks to be composed into larger operations. Both methods accept any number of task functions or composed operations. `series()` and `parallel()` can be nested within themselves or each other to any depth. To have your tasks execute in order, use the `series()` method. ```js const { series } = require('gulp'); function transpile(cb) { // body omitted cb(); } function bundle(cb) { // body omitted cb(); } exports.build = series(transpile, bundle); ``` For tasks to run at maximum concurrency, combine them with the `parallel()` method. ```js const { parallel } = require('gulp'); function javascript(cb) { // body omitted cb(); } function css(cb) { // body omitted cb(); } exports.build = parallel(javascript, css); ``` Tasks are composed immediately when either `series()` or `parallel()` is called. This allows variation in the composition instead of conditional behavior inside individual tasks. ```js const { series } = require('gulp'); function minify(cb) { // body omitted cb(); } function transpile(cb) { // body omitted cb(); } function livereload(cb) { // body omitted cb(); } if (process.env.NODE_ENV === 'production') { exports.build = series(transpile, minify); } else { exports.build = series(transpile, livereload); } ``` `series()` and `parallel()` can be nested to any arbitrary depth. ```js const { series, parallel } = require('gulp'); function clean(cb) { // body omitted cb(); } function cssTranspile(cb) { // body omitted cb(); } function cssMinify(cb) { // body omitted cb(); } function jsTranspile(cb) { // body omitted cb(); } function jsBundle(cb) { // body omitted cb(); } function jsMinify(cb) { // body omitted cb(); } function publish(cb) { // body omitted cb(); } exports.build = series( clean, parallel( cssTranspile, series(jsTranspile, jsBundle) ), parallel(cssMinify, jsMinify), publish ); ``` When a composed operation is run, each task will be executed every time it was referenced. For example, a `clean` task referenced before two different tasks would be run twice and lead to undesired results. Instead, refactor the `clean` task to be specified in the final composition. If you have code like this: ```js // This is INCORRECT const { series, parallel } = require('gulp'); const clean = function(cb) { // body omitted cb(); }; const css = series(clean, function(cb) { // body omitted cb(); }); const javascript = series(clean, function(cb) { // body omitted cb(); }); exports.build = parallel(css, javascript); ``` Migrate to this: ```js const { series, parallel } = require('gulp'); function clean(cb) { // body omitted cb(); } function css(cb) { // body omitted cb(); } function javascript(cb) { // body omitted cb(); } exports.build = series(clean, parallel(css, javascript)); ``` [async-completion-docs]: ../getting-started/4-async-completion.md [using-async-await-docs]: ../getting-started/4-async-completion.md#using-async-await [img-gulp-tasks-command]: https://gulpjs.com/img/docs-gulp-tasks-command.png [async-once]: https://github.com/gulpjs/async-once node-gulp-4.0.2+~cs38.20.35/docs/getting-started/4-async-completion.md000066400000000000000000000105231415667007300250450ustar00rootroot00000000000000 # Async Completion Node libraries handle asynchronicity in a variety of ways. The most common pattern is [error-first callbacks][node-api-error-first-callbacks], but you might also encounter [streams][stream-docs], [promises][promise-docs], [event emitters][event-emitter-docs], [child processes][child-process-docs], or [observables][observable-docs]. Gulp tasks normalize all these types of asynchronicity. ## Signal task completion When a stream, promise, event emitter, child process, or observable is returned from a task, the success or error informs gulp whether to continue or end. If a task errors, gulp will end immediately and show that error. When composing tasks with `series()`, an error will end the composition and no further tasks will be executed. When composing tasks with `parallel()`, an error will end the composition but the other parallel tasks may or may not complete. ### Returning a stream ```js const { src, dest } = require('gulp'); function streamTask() { return src('*.js') .pipe(dest('output')); } exports.default = streamTask; ``` ### Returning a promise ```js function promiseTask() { return Promise.resolve('the value is ignored'); } exports.default = promiseTask; ``` ### Returning an event emitter ```js const { EventEmitter } = require('events'); function eventEmitterTask() { const emitter = new EventEmitter(); // Emit has to happen async otherwise gulp isn't listening yet setTimeout(() => emitter.emit('finish'), 250); return emitter; } exports.default = eventEmitterTask; ``` ### Returning a child process ```js const { exec } = require('child_process'); function childProcessTask() { return exec('date'); } exports.default = childProcessTask; ``` ### Returning an observable ```js const { Observable } = require('rxjs'); function observableTask() { return Observable.of(1, 2, 3); } exports.default = observableTask; ``` ### Using an error-first callback If nothing is returned from your task, you must use the error-first callback to signal completion. The callback will be passed to your task as the only argument - named `cb()` in the examples below. ```js function callbackTask(cb) { // `cb()` should be called by some async work cb(); } exports.default = callbackTask; ``` To indicate to gulp that an error occurred in a task using an error-first callback, call it with an `Error` as the only argument. ```js function callbackError(cb) { // `cb()` should be called by some async work cb(new Error('kaboom')); } exports.default = callbackError; ``` However, you'll often pass this callback to another API instead of calling it yourself. ```js const fs = require('fs'); function passingCallback(cb) { fs.access('gulpfile.js', cb); } exports.default = passingCallback; ``` ## No synchronous tasks Synchronous tasks are no longer supported. They often led to subtle mistakes that were hard to debug, like forgetting to return your streams from a task. When you see the _"Did you forget to signal async completion?"_ warning, none of the techniques mentioned above were used. You'll need to use the error-first callback or return a stream, promise, event emitter, child process, or observable to resolve the issue. ## Using async/await When not using any of the previous options, you can define your task as an [`async` function][async-await-docs], which wraps your task in a promise. This allows you to work with promises synchronously using `await` and use other synchronous code. ```js const fs = require('fs'); async function asyncAwaitTask() { const { version } = fs.readFileSync('package.json'); console.log(version); await Promise.resolve('some result'); } exports.default = asyncAwaitTask; ``` [node-api-error-first-callbacks]: https://nodejs.org/api/errors.html#errors_error_first_callbacks [stream-docs]: https://nodejs.org/api/stream.html#stream_stream [promise-docs]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises [event-emitter-docs]: https://nodejs.org/api/events.html#events_events [child-process-docs]: https://nodejs.org/api/child_process.html#child_process_child_process [observable-docs]: https://github.com/tc39/proposal-observable/blob/master/README.md [async-await-docs]: https://developers.google.com/web/fundamentals/primers/async-functions node-gulp-4.0.2+~cs38.20.35/docs/getting-started/5-working-with-files.md000066400000000000000000000101451415667007300253130ustar00rootroot00000000000000 # Working with Files The `src()` and `dest()` methods are exposed by gulp to interact with files on your computer. `src()` is given a [glob][explaining-globs-docs] to read from the file system and produces a [Node stream][node-streams-docs]. It locates all matching files and reads them into memory to pass through the stream. The stream produced by `src()` should be returned from a task to signal async completion, as mentioned in [Creating Tasks][creating-tasks-docs]. ```js const { src, dest } = require('gulp'); exports.default = function() { return src('src/*.js') .pipe(dest('output/')); } ``` The main API of a stream is the `.pipe()` method for chaining Transform or Writable streams. ```js const { src, dest } = require('gulp'); const babel = require('gulp-babel'); exports.default = function() { return src('src/*.js') .pipe(babel()) .pipe(dest('output/')); } ``` `dest()` is given an output directory string and also produces a [Node stream][node-streams-docs] which is generally used as a terminator stream. When it receives a file passed through the pipeline, it writes the contents and other details out to the filesystem at a given directory. The `symlink()` method is also available and operates like `dest()`, but creates links instead of files (see [`symlink()`][symlink-api-docs] for details). Most often plugins will be placed between `src()` and `dest()` using the `.pipe()` method and will transform the files within the stream. ## Adding files to the stream `src()` can also be placed in the middle of a pipeline to add files to the stream based on the given globs. The additional files will only be available to transformations later in the stream. If [globs overlap][overlapping-globs-docs], the files will be added again. This can be useful for transpiling some files before adding plain JavaScript files to the pipeline and uglifying everything. ```js const { src, dest } = require('gulp'); const babel = require('gulp-babel'); const uglify = require('gulp-uglify'); exports.default = function() { return src('src/*.js') .pipe(babel()) .pipe(src('vendor/*.js')) .pipe(uglify()) .pipe(dest('output/')); } ``` ## Output in phases `dest()` can be used in the middle of a pipeline to write intermediate states to the filesystem. When a file is received, the current state is written out to the filesystem, the path is updated to represent the new location of the output file, then that file continues down the pipeline. This feature can be useful to create unminified and minified files with the same pipeline. ```js const { src, dest } = require('gulp'); const babel = require('gulp-babel'); const uglify = require('gulp-uglify'); const rename = require('gulp-rename'); exports.default = function() { return src('src/*.js') .pipe(babel()) .pipe(src('vendor/*.js')) .pipe(dest('output/')) .pipe(uglify()) .pipe(rename({ extname: '.min.js' })) .pipe(dest('output/')); } ``` ## Modes: streaming, buffered, and empty `src()` can operate in three modes: buffering, streaming, and empty. These are configured with the `buffer` and `read` [options][src-options-api-docs] on `src()`. * Buffering mode is the default and loads the file contents into memory. Plugins usually operate in buffering mode and many don't support streaming mode. * Streaming mode exists mainly to operate on large files that can't fit in memory, like giant images or movies. The contents are streamed from the filesystem in small chunks instead of loaded all at once. If you need to use streaming mode, look for a plugin that supports it or write your own. * Empty mode contains no contents and is useful when only working with file metadata. [explaining-globs-docs]: ../getting-started/6-explaining-globs.md [creating-tasks-docs]: ../getting-started/3-creating-tasks.md [overlapping-globs-docs]: ../getting-started/6-explaining-globs.md#overlapping-globs [node-streams-docs]: https://nodejs.org/api/stream.html [symlink-api-docs]: ../api/symlink.md [src-options-api-docs]: ../api/src.md#options node-gulp-4.0.2+~cs38.20.35/docs/getting-started/6-explaining-globs.md000066400000000000000000000101701415667007300250230ustar00rootroot00000000000000 # Explaining Globs A glob is a string of literal and/or wildcard characters used to match filepaths. Globbing is the act of locating files on a filesystem using one or more globs. The `src()` method expects a single glob string or an array of globs to determine which files your pipeline will operate on. At least one match must be found for your glob(s) otherwise `src()` will error. When an array of globs is used, they are matched in array order - especially useful for negative globs. ## Segments and separators A segment is everything between separators. The separator in a glob is always the `/` character - regardless of the operating system - even in Windows where the path separator is `\\`. In a glob, `\\` is reserved as the escape character. Here, the * is escaped, so it is treated as a literal instead of a wildcard character. ```js 'glob_with_uncommon_\\*_character.js' ``` Avoid using Node's `path` methods, like `path.join`, to create globs. On Windows, it produces an invalid glob because Node uses `\\` as the separator. Also avoid the `__dirname` global, `__filename` global, or `process.cwd()` for the same reasons. ```js const invalidGlob = path.join(__dirname, 'src/*.js'); ``` ## Special character: * (single-star) Matches any amount - including none - of characters within a single segment. Useful for globbing files within one directory. This glob will match files like `index.js`, but not files like `scripts/index.js` or `scripts/nested/index.js` ```js '*.js' ``` ## Special character: ** (double-star) Matches any amount - including none - of characters across segments. Useful for globbing files in nested directories. Make sure to appropriately restrict your double-star globs, to avoid matching large directories unnecessarily. Here, the glob is appropriately restricted to the `scripts/` directory. It will match files like `scripts/index.js`, `scripts/nested/index.js`, and `scripts/nested/twice/index.js`. ```js 'scripts/**/*.js' ``` In the previous example, if `scripts/` wasn't prefixed, all dependencies in `node_modules` or other directories would also be matched. ## Special character: ! (negative) Since globs are matched in array order, a negative glob must follow at least one non-negative glob in an array. The first finds a set of matches, then the negative glob removes a portion of those results. When excluding all files within a directory, you must add `/**` after the directory name, which the globbing library optimizes internally. ```js ['scripts/**/*.js', '!scripts/vendor/**'] ``` If any non-negative globs follow a negative, nothing will be removed from the later set of matches. ```js ['scripts/**/*.js', '!scripts/vendor/**', 'scripts/vendor/react.js'] ``` Negative globs can be used as an alternative for restricting double-star globs. ```js ['**/*.js', '!node_modules/**'] ``` In the previous example, if the negative glob was `!node_modules/**/*.js`, the globbing library wouldn't optimize the negation and every match would have to be compared against the negative glob, which would be extremely slow. To ignore all files in a directory, only add the `/**` glob after the directory name. ## Overlapping globs Two or more globs that (un)intentionally match the same file are considered overlapping. When overlapping globs are used within a single `src()`, gulp does its best to remove the duplicates, but doesn't attempt to deduplicate across separate `src()` calls. ## Advanced resources Most of what you'll need to work with globs in gulp is covered here. If you'd like to get more in depth, here are a few resources. * [Micromatch Documentation][micromatch-docs] * [node-glob's Glob Primer][glob-primer-docs] * [Begin's Globbing Documentation][begin-globbing-docs] * [Wikipedia's Glob Page][wikipedia-glob] [micromatch-docs]: https://github.com/micromatch/micromatch [glob-primer-docs]: https://github.com/isaacs/node-glob#glob-primer [begin-globbing-docs]: https://github.com/begin/globbing#what-is-globbing [wikipedia-glob]: https://en.wikipedia.org/wiki/Glob_(programming) node-gulp-4.0.2+~cs38.20.35/docs/getting-started/7-using-plugins.md000066400000000000000000000066541415667007300244020ustar00rootroot00000000000000 # Using Plugins Gulp plugins are [Node Transform Streams][through2-docs] that encapsulate common behavior to transform files in a pipeline - often placed between `src()` and `dest()` using the `.pipe()` method. They can change the filename, metadata, or contents of every file that passes through the stream. Plugins from npm - using the "gulpplugin" and "gulpfriendly" keywords - can be browsed and searched on the [plugin search page][gulp-plugin-site]. Each plugin should only do a small amount of work, so you can connect them like building blocks. You may need to combine a bunch of them to get the desired result. ```js const { src, dest } = require('gulp'); const uglify = require('gulp-uglify'); const rename = require('gulp-rename'); exports.default = function() { return src('src/*.js') // The gulp-uglify plugin won't update the filename .pipe(uglify()) // So use gulp-rename to change the extension .pipe(rename({ extname: '.min.js' })) .pipe(dest('output/')); } ``` ## Do you need a plugin? Not everything in gulp should use plugins. They are a quick way to get started, but many operations are improved by using a module or library instead. ```js const { rollup } = require('rollup'); // Rollup's promise API works great in an `async` task exports.default = async function() { const bundle = await rollup.rollup({ input: 'src/index.js' }); return bundle.write({ file: 'output/bundle.js', format: 'iife' }); } ``` Plugins should always transform files. Use a (non-plugin) Node module or library for any other operations. ```js const del = require('delete'); exports.default = function(cb) { // Use the `delete` module directly, instead of using gulp-rimraf del(['output/*.js'], cb); } ``` ## Conditional plugins Since plugin operations shouldn't be file-type-aware, you may need a plugin like [gulp-if][gulp-if-package] to transform subsets of files. ```js const { src, dest } = require('gulp'); const gulpif = require('gulp-if'); const uglify = require('gulp-uglify'); function isJavaScript(file) { // Check if file extension is '.js' return file.extname === '.js'; } exports.default = function() { // Include JavaScript and CSS files in a single pipeline return src(['src/*.js', 'src/*.css']) // Only apply gulp-uglify plugin to JavaScript files .pipe(gulpif(isJavaScript, uglify())) .pipe(dest('output/')); } ``` ## Inline plugins Inline plugins are one-off Transform Streams you define inside your gulpfile by writing the desired behavior. There are two situations where creating an inline plugin is helpful: * Instead of creating and maintaining your own plugin. * Instead of forking a plugin that exists to add a feature you want. ```js const { src, dest } = require('gulp'); const uglify = require('uglify-js'); const through2 = require('through2'); exports.default = function() { return src('src/*.js') // Instead of using gulp-uglify, you can create an inline plugin .pipe(through2.obj(function(file, _, cb) { if (file.isBuffer()) { const code = uglify.minify(file.contents.toString()) file.contents = Buffer.from(code) } cb(null, file); })) .pipe(dest('output/')); } ``` [gulp-plugin-site]: https://gulpjs.com/plugins/ [through2-docs]: https://github.com/rvagg/through2 [gulp-if-package]: https://www.npmjs.com/package/gulp-if node-gulp-4.0.2+~cs38.20.35/docs/getting-started/8-watching-files.md000066400000000000000000000107051415667007300244730ustar00rootroot00000000000000 # Watching Files The `watch()` API connects [globs][globs-docs] to [tasks][creating-tasks-docs] using a file system watcher. It watches for changes to files that match the globs and executes the task when a change occurs. If the task doesn't signal [Async Completion][async-completion-doc], it will never be run a second time. This API provides built-in delay and queueing based on most-common-use defaults. ```js const { watch, series } = require('gulp'); function clean(cb) { // body omitted cb(); } function javascript(cb) { // body omitted cb(); } function css(cb) { // body omitted cb(); } exports.default = function() { // You can use a single task watch('src/*.css', css); // Or a composed task watch('src/*.js', series(clean, javascript)); }; ``` ## Warning: avoid synchronous A watcher's task cannot be synchronous, like tasks registered into the task system. If you pass a sync task, the completion can't be determined and the task won't run again - it is assumed to still be running. There is no error or warning message provided because the file watcher keeps your Node process running. Since the process doesn't exit, it cannot be determined whether the task is done or just taking a really, really long time to run. ## Watched events By default, the watcher executes tasks whenever a file is created, changed, or deleted. If you need to use different events, you can use the `events` option when calling `watch()`. The available events are `'add'`, `'addDir'`, `'change'`, `'unlink'`, `'unlinkDir'`, `'ready'`, `'error'`. Additionally `'all'` is available, which represents all events other than `'ready'` and `'error'`. ```js const { watch } = require('gulp'); exports.default = function() { // All events will be watched watch('src/*.js', { events: 'all' }, function(cb) { // body omitted cb(); }); }; ``` ## Initial execution Upon calling `watch()`, the tasks won't be executed, instead they'll wait for the first file change. To execute tasks before the first file change, set the `ignoreInitial` option to `false`. ```js const { watch } = require('gulp'); exports.default = function() { // The task will be executed upon startup watch('src/*.js', { ignoreInitial: false }, function(cb) { // body omitted cb(); }); }; ``` ## Queueing Each `watch()` guarantees that its currently running task won't execute again concurrently. When a file change is made while a watcher task is running, another execution will queue up to run when the task finishes. Only one run can be queued up at a time. To disable queueing, set the `queue` option to `false`. ```js const { watch } = require('gulp'); exports.default = function() { // The task will be run (concurrently) for every change made watch('src/*.js', { queue: false }, function(cb) { // body omitted cb(); }); }; ``` ## Delay Upon file change, a watcher task won't run until a 200ms delay has elapsed. This is to avoid starting a task too early when many files are being changed at once - like find-and-replace. To adjust the delay duration, set the `delay` option to a positive integer. ```js const { watch } = require('gulp'); exports.default = function() { // The task won't be run until 500ms have elapsed since the first change watch('src/*.js', { delay: 500 }, function(cb) { // body omitted cb(); }); }; ``` ## Using the watcher instance You likely won't use this feature, but if you need full control over changed files - like access to paths or metadata - use the [chokidar][chokidar-module-package] instance returned from `watch()`. __Be careful:__ The returned chokidar instance doesn't have queueing, delay, or async completion features. ## Optional dependency Gulp has an optional dependency called [fsevents][fsevents-package], which is a Mac-specific file watcher. If you see an installation warning for fsevents - _"npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents"_ - it is not an issue. If fsevents installation is skipped, a fallback watcher will be used and any errors occurring in your gulpfile aren't related to this warning. [globs-docs]: ../getting-started/6-explaining-globs.md [creating-tasks-docs]: ../getting-started/3-creating-tasks.md [async-completion-doc]: ../getting-started/4-async-completion.md [chokidar-module-package]: https://www.npmjs.com/package/chokidar [fsevents-package]: https://www.npmjs.com/package/fsevents node-gulp-4.0.2+~cs38.20.35/docs/getting-started/README.md000066400000000000000000000005671415667007300223640ustar00rootroot00000000000000# Getting Started 1. [Quick Start](1-quick-start.md) 2. [JavaScript and Gulpfiles](2-javascript-and-gulpfiles.md) 3. [Creating Tasks](3-creating-tasks.md) 4. [Async Completion](4-async-completion.md) 5. [Working with Files](5-working-with-files.md) 6. [Explaining Globs](6-explaining-globs.md) 7. [Using Plugins](7-using-plugins.md) 8. [Watching Files](8-watching-files.md) node-gulp-4.0.2+~cs38.20.35/docs/recipes/000077500000000000000000000000001415667007300174225ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/docs/recipes/README.md000066400000000000000000000036631415667007300207110ustar00rootroot00000000000000# Recipes * [Automate release workflow](automate-release-workflow.md) * [Combining streams to handle errors](combining-streams-to-handle-errors.md) * [Delete files and folders](delete-files-folder.md) * [Fast browserify builds with watchify](fast-browserify-builds-with-watchify.md) * [Incremental rebuilding, including operating on full file sets](incremental-builds-with-concatenate.md) * [Make stream from buffer (memory contents)](make-stream-from-buffer.md) * [Mocha test-runner with gulp](mocha-test-runner-with-gulp.md) * [Only pass through changed files](only-pass-through-changed-files.md) * [Pass parameters from the command line](pass-arguments-from-cli.md) * [Rebuild only files that change](rebuild-only-files-that-change.md) * [Generating a file per folder](running-task-steps-per-folder.md) * [Running tasks in series](running-tasks-in-series.md) * [Server with live-reloading and CSS injection](server-with-livereload-and-css-injection.md) * [Sharing streams with stream factories](sharing-streams-with-stream-factories.md) * [Specifying a new cwd (current working directory)](specifying-a-cwd.md) * [Split tasks across multiple files](split-tasks-across-multiple-files.md) * [Using external config file](using-external-config-file.md) * [Using multiple sources in one task](using-multiple-sources-in-one-task.md) * [Browserify + Uglify with sourcemaps](browserify-uglify-sourcemap.md) * [Browserify + Globs](browserify-with-globs.md) * [Browserify + Globs (multiple destination)](browserify-multiple-destination.md) * [Output both a minified and non-minified version](minified-and-non-minified.md) * [Templating with Swig and YAML front-matter](templating-with-swig-and-yaml-front-matter.md) * [Run Grunt Tasks from Gulp](run-grunt-tasks-from-gulp.md) * [Exports as tasks](exports-as-tasks.md) * [Rollup with rollup-stream](rollup-with-rollup-stream.md) * [Run gulp task via cron job](cron-task.md) * [Running shell commands](running-shell-commands.md) node-gulp-4.0.2+~cs38.20.35/docs/recipes/automate-release-workflow.md000066400000000000000000000046661415667007300250650ustar00rootroot00000000000000# Automate release workflow If your project follows a semantic versioning, it may be a good idea to automatize the steps needed to do a release. Below you have a simple recipe that bumps the project version, commits the changes to git and creates a new tag. ``` javascript var gulp = require('gulp'); var conventionalChangelog = require('gulp-conventional-changelog'); var conventionalGithubReleaser = require('conventional-github-releaser'); var bump = require('gulp-bump'); var log = require('gulplog'); var git = require('gulp-git'); var fs = require('fs'); gulp.task('changelog', function () { return gulp.src('CHANGELOG.md', { buffer: false }) .pipe(conventionalChangelog({ preset: 'angular' // Or to any other commit message convention you use. })) .pipe(gulp.dest('./')); }); gulp.task('github-release', function(done) { conventionalGithubReleaser({ type: "oauth", token: '0126af95c0e2d9b0a7c78738c4c00a860b04acc8' // change this to your own GitHub token or use an environment variable }, { preset: 'angular' // Or to any other commit message convention you use. }, done); }); gulp.task('bump-version', function () { // We hardcode the version change type to 'patch' but it may be a good idea to // use minimist (https://www.npmjs.com/package/minimist) to determine with a // command argument whether you are doing a 'major', 'minor' or a 'patch' change. return gulp.src(['./bower.json', './package.json']) .pipe(bump({type: "patch"}).on('error', log.error)) .pipe(gulp.dest('./')); }); gulp.task('commit-changes', function () { return gulp.src('.') .pipe(git.add()) .pipe(git.commit('[Prerelease] Bumped version number')); }); gulp.task('push-changes', function (done) { git.push('origin', 'master', done); }); gulp.task('create-new-tag', function (done) { var version = getPackageJsonVersion(); git.tag(version, 'Created Tag for version: ' + version, function (error) { if (error) { return done(error); } git.push('origin', 'master', {args: '--tags'}, done); }); function getPackageJsonVersion () { // We parse the json file instead of using require because require caches // multiple calls so the version number won't be updated return JSON.parse(fs.readFileSync('./package.json', 'utf8')).version; }; }); gulp.task('release', gulp.series( 'bump-version', 'changelog', 'commit-changes', 'push-changes', 'create-new-tag', 'github-release' )); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/browserify-multiple-destination.md000066400000000000000000000023731415667007300263140ustar00rootroot00000000000000# Browserify + Globs (multiple destination) This example shows how to set up a task of bundling multiple entry points into multiple destinations using browserify. The below `js` task bundles all the `.js` files under `src/` as entry points and writes the results under `dest/`. ```js var gulp = require('gulp'); var browserify = require('browserify'); var log = require('gulplog'); var tap = require('gulp-tap'); var buffer = require('gulp-buffer'); var sourcemaps = require('gulp-sourcemaps'); var uglify = require('gulp-uglify'); gulp.task('js', function () { return gulp.src('src/**/*.js', {read: false}) // no need of reading file because browserify does. // transform file objects using gulp-tap plugin .pipe(tap(function (file) { log.info('bundling ' + file.path); // replace file contents with browserify's bundle stream file.contents = browserify(file.path, {debug: true}).bundle(); })) // transform streaming contents into buffer contents (because gulp-sourcemaps does not support streaming contents) .pipe(buffer()) // load and init sourcemaps .pipe(sourcemaps.init({loadMaps: true})) .pipe(uglify()) // write sourcemaps .pipe(sourcemaps.write('./')) .pipe(gulp.dest('dest')); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/browserify-transforms.md000066400000000000000000000025141415667007300243350ustar00rootroot00000000000000# Browserify + Transforms [Browserify](https://github.com/browserify/browserify) has become an important and indispensable tool but requires being wrapped before working well with gulp. Below is a simple recipe for using Browserify with transforms. See also: the [Combining Streams to Handle Errors](https://github.com/gulpjs/gulp/blob/master/docs/recipes/combining-streams-to-handle-errors.md) recipe for handling errors with browserify or uglify in your stream. ``` javascript 'use strict'; var browserify = require('browserify'); var gulp = require('gulp'); var source = require('vinyl-source-stream'); var buffer = require('vinyl-buffer'); var log = require('gulplog'); var uglify = require('gulp-uglify'); var sourcemaps = require('gulp-sourcemaps'); var reactify = require('reactify'); gulp.task('javascript', function () { // set up the browserify instance on a task basis var b = browserify({ entries: './entry.js', debug: true, // defining transforms here will avoid crashing your stream transform: [reactify] }); return b.bundle() .pipe(source('app.js')) .pipe(buffer()) .pipe(sourcemaps.init({loadMaps: true})) // Add transformation tasks to the pipeline here. .pipe(uglify()) .on('error', log.error) .pipe(sourcemaps.write('./')) .pipe(gulp.dest('./dist/js/')); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/browserify-uglify-sourcemap.md000066400000000000000000000025241415667007300254330ustar00rootroot00000000000000# Browserify + Uglify2 with sourcemaps [Browserify](https://github.com/browserify/browserify) has become an important and indispensable tool but requires being wrapped before working well with gulp. Below is a simple recipe for using Browserify with full sourcemaps that resolve to the original individual files. See also: the [Combining Streams to Handle Errors](https://github.com/gulpjs/gulp/blob/master/docs/recipes/combining-streams-to-handle-errors.md) recipe for handling errors with browserify or uglify in your stream. A simple `gulpfile.js` file for Browserify + Uglify2 with sourcemaps: ``` javascript 'use strict'; var browserify = require('browserify'); var gulp = require('gulp'); var source = require('vinyl-source-stream'); var buffer = require('vinyl-buffer'); var uglify = require('gulp-uglify'); var sourcemaps = require('gulp-sourcemaps'); var log = require('gulplog'); gulp.task('javascript', function () { // set up the browserify instance on a task basis var b = browserify({ entries: './entry.js', debug: true }); return b.bundle() .pipe(source('app.js')) .pipe(buffer()) .pipe(sourcemaps.init({loadMaps: true})) // Add transformation tasks to the pipeline here. .pipe(uglify()) .on('error', log.error) .pipe(sourcemaps.write('./')) .pipe(gulp.dest('./dist/js/')); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/browserify-with-globs.md000066400000000000000000000044211415667007300242150ustar00rootroot00000000000000# Browserify + Globs [Browserify + Uglify2](https://github.com/gulpjs/gulp/blob/master/docs/recipes/browserify-uglify-sourcemap.md) shows how to setup a basic gulp task to bundle a JavaScript file with its dependencies, and minify the bundle with UglifyJS while preserving source maps. It does not, however, show how one may use gulp and Browserify with multiple entry files. See also: the [Combining Streams to Handle Errors](https://github.com/gulpjs/gulp/blob/master/docs/recipes/combining-streams-to-handle-errors.md) recipe for handling errors with Browserify or UglifyJS in your stream. ``` javascript 'use strict'; var browserify = require('browserify'); var gulp = require('gulp'); var source = require('vinyl-source-stream'); var buffer = require('vinyl-buffer'); var globby = require('globby'); var through = require('through2'); var log = require('gulplog'); var uglify = require('gulp-uglify'); var sourcemaps = require('gulp-sourcemaps'); var reactify = require('reactify'); gulp.task('javascript', function () { // gulp expects tasks to return a stream, so we create one here. var bundledStream = through(); bundledStream // turns the output bundle stream into a stream containing // the normal attributes gulp plugins expect. .pipe(source('app.js')) // the rest of the gulp task, as you would normally write it. // here we're copying from the Browserify + Uglify2 recipe. .pipe(buffer()) .pipe(sourcemaps.init({loadMaps: true})) // Add gulp plugins to the pipeline here. .pipe(uglify()) .on('error', log.error) .pipe(sourcemaps.write('./')) .pipe(gulp.dest('./dist/js/')); // "globby" replaces the normal "gulp.src" as Browserify // creates it's own readable stream. globby(['./entries/*.js']).then(function(entries) { // create the Browserify instance. var b = browserify({ entries: entries, debug: true, transform: [reactify] }); // pipe the Browserify stream into the stream we created earlier // this starts our gulp pipeline. b.bundle().pipe(bundledStream); }).catch(function(err) { // ensure any errors from globby are handled bundledStream.emit('error', err); }); // finally, we return the stream, so gulp knows when this task is done. return bundledStream; }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/combining-streams-to-handle-errors.md000066400000000000000000000016441415667007300265550ustar00rootroot00000000000000# Combining streams to handle errors By default, emitting an error on a stream will cause it to be thrown unless it already has a listener attached to the `error` event. This gets a bit tricky when you're working with longer pipelines of streams. By using [stream-combiner2](https://github.com/substack/stream-combiner2) you can turn a series of streams into a single stream, meaning you only need to listen to the `error` event in one place in your code. Here's an example of using it in a gulpfile: ```js var combiner = require('stream-combiner2'); var uglify = require('gulp-uglify'); var gulp = require('gulp'); gulp.task('test', function() { return combiner.obj([ gulp.src('bootstrap/js/*.js'), uglify(), gulp.dest('public/bootstrap') ]) // any errors in the above streams will get caught // by this listener, instead of being thrown: .on('error', console.error.bind(console)); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/cron-task.md000066400000000000000000000016241415667007300216500ustar00rootroot00000000000000# Run gulp task via cron job While logged in via a user that has privileges to run `gulp`, run the following: crontab -e to edit your current "[crontab](https://en.wikipedia.org/wiki/Cron)" file. Typically, within a cron job, you want to run any binary using absolute paths, so an initial approach to running `gulp build` every minute might look like: * * * * * cd /your/dir/to/run/in && /usr/local/bin/gulp build However, you might see in the cron logs that you get this error: > `/usr/bin/env: node: No such file or directory` To fix this, we need to add a [symbolic link](https://en.wikipedia.org/wiki/Ln_\(Unix\)) within `/usr/bin` to point to the actual path of our node binary. Be sure you are logged in as a **sudo** user, and paste in the following command to your terminal: sudo ln -s $(which node) /usr/bin/node Once this link is established, your cron task should run successfully. node-gulp-4.0.2+~cs38.20.35/docs/recipes/delete-files-folder.md000066400000000000000000000043111415667007300235560ustar00rootroot00000000000000# Delete files and folders You might want to delete some files before running your build. Since deleting files doesn't work on the file contents, there's no reason to use a gulp plugin. An excellent opportunity to use a vanilla node module. Let's use the [`del`](https://github.com/sindresorhus/del) module for this example as it supports multiple files and [globbing](https://github.com/sindresorhus/multimatch#globbing-patterns): ```sh $ npm install --save-dev gulp del ``` Imagine the following file structure: ``` . ├── dist │   ├── report.csv │   ├── desktop │   └── mobile │   ├── app.js │   ├── deploy.json │   └── index.html └── src ``` In the gulpfile we want to clean out the contents of the `mobile` folder before running our build: ```js var gulp = require('gulp'); var del = require('del'); gulp.task('clean:mobile', function () { return del([ 'dist/report.csv', // here we use a globbing pattern to match everything inside the `mobile` folder 'dist/mobile/**/*', // we don't want to clean this file though so we negate the pattern '!dist/mobile/deploy.json' ]); }); gulp.task('default', gulp.series('clean:mobile')); ``` ## Delete files in a pipeline You might want to delete some files after processing them in a pipeline. We'll use [vinyl-paths](https://github.com/sindresorhus/vinyl-paths) to easily get the file path of files in the stream and pass it to the `del` method. ```sh $ npm install --save-dev gulp del vinyl-paths ``` Imagine the following file structure: ``` . ├── tmp │   ├── rainbow.js │   └── unicorn.js └── dist ``` ```js var gulp = require('gulp'); var stripDebug = require('gulp-strip-debug'); // only as an example var del = require('del'); var vinylPaths = require('vinyl-paths'); gulp.task('clean:tmp', function () { return gulp.src('tmp/*') .pipe(vinylPaths(del)) .pipe(stripDebug()) .pipe(gulp.dest('dist')); }); gulp.task('default', gulp.series('clean:tmp')); ``` This will only delete the tmp dir. Only do this if you're already using other plugins in the pipeline, otherwise just use the module directly as `gulp.src` is costly. node-gulp-4.0.2+~cs38.20.35/docs/recipes/exports-as-tasks.md000066400000000000000000000007371415667007300232030ustar00rootroot00000000000000# Exports as Tasks Using the ES2015 module syntax you can use your exports as tasks. ```js import gulp from 'gulp'; import babel from 'gulp-babel'; // named task export function build() { return gulp.src('src/*.js') .pipe(babel()) .pipe(gulp.dest('lib')); } // default task export default function dev() { gulp.watch('src/*.js', ['build']); } ``` This will **not** work with the gulp-cli version bundled with gulp 3.x. You must use the latest published version. node-gulp-4.0.2+~cs38.20.35/docs/recipes/fast-browserify-builds-with-watchify.md000066400000000000000000000041611415667007300271410ustar00rootroot00000000000000# Fast browserify builds with watchify As a [browserify](https://github.com/browserify/browserify) project begins to expand, the time to bundle it slowly gets longer and longer. While it might start at 1 second, it's possible to be waiting 30 seconds for your project to build on particularly large projects. That's why [substack](https://github.com/substack) wrote [watchify](https://github.com/browserify/watchify), a persistent browserify bundler that watches files for changes and *only rebuilds what it needs to*. This way, that first build might still take 30 seconds, but subsequent builds can still run in under 100ms – which is a huge improvement. Watchify doesn't have a gulp plugin, and it doesn't need one: you can use [vinyl-source-stream](https://github.com/hughsk/vinyl-source-stream) to pipe the bundle stream into your gulp pipeline. ``` javascript 'use strict'; var watchify = require('watchify'); var browserify = require('browserify'); var gulp = require('gulp'); var source = require('vinyl-source-stream'); var buffer = require('vinyl-buffer'); var log = require('gulplog'); var sourcemaps = require('gulp-sourcemaps'); var assign = require('lodash.assign'); // add custom browserify options here var customOpts = { entries: ['./src/index.js'], debug: true }; var opts = assign({}, watchify.args, customOpts); var b = watchify(browserify(opts)); // add transformations here // i.e. b.transform(coffeeify); gulp.task('js', bundle); // so you can run `gulp js` to build the file b.on('update', bundle); // on any dep update, runs the bundler b.on('log', log.info); // output build logs to terminal function bundle() { return b.bundle() // log errors if they happen .on('error', log.error.bind(log, 'Browserify Error')) .pipe(source('bundle.js')) // optional, remove if you don't need to buffer file contents .pipe(buffer()) // optional, remove if you dont want sourcemaps .pipe(sourcemaps.init({loadMaps: true})) // loads map from browserify file // Add transformation tasks to the pipeline here. .pipe(sourcemaps.write('./')) // writes .map file .pipe(gulp.dest('./dist')); } ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/handling-the-delete-event-on-watch.md000066400000000000000000000020111415667007300263750ustar00rootroot00000000000000# Handling the Delete Event on Watch You can listen for `'unlink'` events to fire on the watcher returned from `gulp.watch`. This gets fired when files are removed, so you can delete the file from your destination directory, using something like: ```js 'use strict'; var del = require('del'); var path = require('path'); var gulp = require('gulp'); var header = require('gulp-header'); var footer = require('gulp-footer'); gulp.task('scripts', function() { return gulp.src('src/**/*.js', {base: 'src'}) .pipe(header('(function () {\r\n\t\'use strict\'\r\n')) .pipe(footer('\r\n})();')) .pipe(gulp.dest('build')); }); gulp.task('watch', function () { var watcher = gulp.watch('src/**/*.js', ['scripts']); watcher.on('unlink', function (filepath) { var filePathFromSrc = path.relative(path.resolve('src'), filepath); // Concatenating the 'build' absolute path used by gulp.dest in the scripts task var destFilePath = path.resolve('build', filePathFromSrc); del.sync(destFilePath); }); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/incremental-builds-with-concatenate.md000066400000000000000000000034441415667007300267650ustar00rootroot00000000000000# Incremental rebuilding, including operating on full file sets The trouble with incremental rebuilds is you often want to operate on _all_ processed files, not just single files. For example, you may want to lint and module-wrap just the file(s) that have changed, then concatenate it with all other linted and module-wrapped files. This is difficult without the use of temp files. Use [gulp-cached](https://github.com/wearefractal/gulp-cached) and [gulp-remember](https://github.com/ahaurw01/gulp-remember) to achieve this. ```js var gulp = require('gulp'); var header = require('gulp-header'); var footer = require('gulp-footer'); var concat = require('gulp-concat'); var jshint = require('gulp-jshint'); var cached = require('gulp-cached'); var remember = require('gulp-remember'); var scriptsGlob = 'src/**/*.js'; gulp.task('scripts', function() { return gulp.src(scriptsGlob) .pipe(cached('scripts')) // only pass through changed files .pipe(jshint()) // do special things to the changed files... .pipe(header('(function () {')) // e.g. jshinting ^^^ .pipe(footer('})();')) // and some kind of module wrapping .pipe(remember('scripts')) // add back all files to the stream .pipe(concat('app.js')) // do things that require all files .pipe(gulp.dest('public/')); }); gulp.task('watch', function () { var watcher = gulp.watch(scriptsGlob, gulp.series('scripts')); // watch the same files in our scripts task watcher.on('change', function (event) { if (event.type === 'deleted') { // if a file is deleted, forget about it delete cached.caches.scripts[event.path]; // gulp-cached remove api remember.forget('scripts', event.path); // gulp-remember remove api } }); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/maintain-directory-structure-while-globbing.md000066400000000000000000000026021415667007300304730ustar00rootroot00000000000000# Maintain Directory Structure while Globbing If you are planning to read a few files/folders from a directory and maintain their relative path, you need to pass `{base: '.'}` as the second argument to `gulp.src()`. For example, if you have a directory structure like ![Dev setup](https://cloud.githubusercontent.com/assets/2562992/3178498/bedf75b4-ec1a-11e3-8a71-a150ad94b450.png) and want to read only a few files say ```js [ 'index.html', 'css/**', 'js/**', 'lib/**', 'images/**', 'plugin/**' ] ``` In this case, Gulp will read all the sub-folders of (_say_) `css` folder and arrange them relative to your root folder and they will no longer be the sub-folder of `css`. The output after globbing would look like ![Zipped-Unzipped](https://cloud.githubusercontent.com/assets/2562992/3178614/27208c52-ec1c-11e3-852e-8bbb8e420c7f.png) If you want to maintain the structure, you need to pass `{base: '.'}` to `gulp.src()`. Like ```js gulp.task('task', function () { return gulp.src(['index.html', 'css/**', 'js/**', 'lib/**', 'images/**', 'plugin/**' ], {base: '.'}) .pipe(operation1()) .pipe(operation2()); }); ``` And the input to your `operation1()` will be a folder structure like ![with-base](https://cloud.githubusercontent.com/assets/2562992/3178607/053d6722-ec1c-11e3-9ba8-7ce39e1a480e.png) node-gulp-4.0.2+~cs38.20.35/docs/recipes/make-stream-from-buffer.md000066400000000000000000000102041415667007300243570ustar00rootroot00000000000000# Make stream from buffer (memory contents) Sometimes you may need to start a stream with files that their contents are in a variable and not in a physical file. In other words, how to start a 'gulp' stream without using `gulp.src()`. Let's say for example that we have a directory with js lib files and another directory with versions of some module. The target of the build would be to create one js file for each version, containing all the libs and the version of the module concatenated. Logically we would break it down like this: * load the lib files * concatenate the lib file contents * load the versions files * for each version file, concatenate the libs' contents and the version file contents * for each version file, output the result in a file Imagine this file structure: ```sh ├── libs │   ├── lib1.js │   └── lib2.js └── versions ├── version.1.js └── version.2.js ``` You should get: ```sh └── output ├── version.1.complete.js # lib1.js + lib2.js + version.1.js └── version.2.complete.js # lib1.js + lib2.js + version.2.js ``` A simple and modular way to do this would be the following: ```js var gulp = require('gulp'); var source = require('vinyl-source-stream'); var vinylBuffer = require('vinyl-buffer'); var tap = require('gulp-tap'); var concat = require('gulp-concat'); var size = require('gulp-size'); var path = require('path'); var es = require('event-stream'); var memory = {}; // we'll keep our assets in memory // task of loading the files' contents in memory gulp.task('load-lib-files', function() { // read the lib files from the disk return gulp.src('src/libs/*.js') // concatenate all lib files into one .pipe(concat('libs.concat.js')) // tap into the stream to get each file's data .pipe(tap(function(file) { // save the file contents in memory memory[path.basename(file.path)] = file.contents.toString(); })); }); gulp.task('load-versions', function() { memory.versions = {}; // read the version files from the disk return gulp.src('src/versions/version.*.js') // tap into the stream to get each file's data .pipe( tap(function(file) { // save the file contents in the assets memory.versions[path.basename(file.path)] = file.contents.toString(); })); }); gulp.task('write-versions', function() { // we store all the different version file names in an array var availableVersions = Object.keys(memory.versions); // we make an array to store all the stream promises var streams = []; availableVersions.forEach(function(v) { // make a new stream with fake file name var stream = source('final.' + v); var streamEnd = stream; // we load the data from the concatenated libs var fileContents = memory['libs.concat.js'] + // we add the version's data '\n' + memory.versions[v]; // write the file contents to the stream stream.write(fileContents); process.nextTick(function() { // in the next process cycle, end the stream stream.end(); }); streamEnd = streamEnd // transform the raw data into the stream, into a vinyl object/file .pipe(vinylBuffer()) //.pipe(tap(function(file) { /* do something with the file contents here */ })) .pipe(gulp.dest('output')); // add the end of the stream, otherwise the task would finish before all the processing // is done streams.push(streamEnd); }); return es.merge.apply(this, streams); }); //============================================ our main task gulp.task('default', gulp.series( // load the files in parallel gulp.parallel('load-lib-files', 'load-versions'), // ready to write once all resources are in memory 'write-versions' ) ); //============================================ our watcher task // only watch after having run 'default' once so that all resources // are already in memory gulp.task('watch', gulp.series( 'default', function() { gulp.watch('./src/libs/*.js', gulp.series( 'load-lib-files', 'write-versions' )); gulp.watch('./src/versions/*.js', gulp.series( 'load-lib-files', 'write-versions' )); } )); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/minified-and-non-minified.md000066400000000000000000000012561415667007300246460ustar00rootroot00000000000000# Output both a minified and non-minified version Outputting both a minified and non-minified version of your combined JavaScript files can be achieved by using `gulp-rename` and piping to `dest` twice (once before minifying and once after minifying): ```js 'use strict'; var gulp = require('gulp'); var rename = require('gulp-rename'); var uglify = require('gulp-uglify'); var DEST = 'build/'; gulp.task('default', function() { return gulp.src('foo.js') // This will output the non-minified version .pipe(gulp.dest(DEST)) // This will minify and rename to foo.min.js .pipe(uglify()) .pipe(rename({ extname: '.min.js' })) .pipe(gulp.dest(DEST)); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/minimal-browsersync-setup-with-gulp4.md000066400000000000000000000070051415667007300271120ustar00rootroot00000000000000# Minimal BrowserSync setup with Gulp 4 [BrowserSync](https://www.browsersync.io/) is a great tool to streamline the development process with the ability to reflect code changes instantaneously in the browser through live-reloading. Setting up a live-reloading BrowserSync server with Gulp 4 is very clean and easy. ## Step 1: Install the dependencies ``` npm install --save-dev browser-sync ``` ## Step 2: Setup the project structure ``` src/ scripts/ |__ index.js dist/ scripts/ index.html gulpfile.babel.js ``` The goal here is to be able to: - Build the source script file in `src/scripts/`, e.g. compiling with babel, minifying, etc. - Put the compiled version in `dist/scripts` for use in `index.html` - Watch for changes in the source file and rebuild the `dist` package - With each rebuild of the `dist` package, reload the browser to immediately reflect the changes ## Step 3: Write the gulpfile The gulpfile could be broken in 3 parts. ### 1. Write the task to prepare the dist package as usual Refer to the main [README](https://github.com/gulpjs/gulp/blob/4.0/README.md#use-last-javascript-version-in-your-gulpfile) for more information. ```javascript import babel from 'gulp-babel'; import concat from 'gulp-concat'; import del from 'del'; import gulp from 'gulp'; import uglify from 'gulp-uglify'; const paths = { scripts: { src: 'src/scripts/*.js', dest: 'dist/scripts/' } }; const clean = () => del(['dist']); function scripts() { return gulp.src(paths.scripts.src, { sourcemaps: true }) .pipe(babel()) .pipe(uglify()) .pipe(concat('index.min.js')) .pipe(gulp.dest(paths.scripts.dest)); } ``` ### 2. Setup the BrowserSync server And write the tasks to serve and reload the server accordingly. ```javascript import browserSync from 'browser-sync'; const server = browserSync.create(); function reload(done) { server.reload(); done(); } function serve(done) { server.init({ server: { baseDir: './' } }); done(); } ``` ### 3. Watch for source change, rebuild the scripts and reload the server This is trivially accomplished with `gulp.series` ```javascript const watch = () => gulp.watch(paths.scripts.src, gulp.series(scripts, reload)); ``` ## Step 4: Bring it all together The last step is to expose the default task ```javascript const dev = gulp.series(clean, scripts, serve, watch); export default dev; ``` And profit ```bash $ gulp ``` Now if you go to [http://localhost:3000](http://localhost:3000), which is the default address of the BrowserSync server, you will see that the end result in the browser is updated everytime you change the content of the source file. Here is the whole gulpfile: ```javascript import babel from 'gulp-babel'; import concat from 'gulp-concat'; import del from 'del'; import gulp from 'gulp'; import uglify from 'gulp-uglify'; import browserSync from 'browser-sync'; const server = browserSync.create(); const paths = { scripts: { src: 'src/scripts/*.js', dest: 'dist/scripts/' } }; const clean = () => del(['dist']); function scripts() { return gulp.src(paths.scripts.src, { sourcemaps: true }) .pipe(babel()) .pipe(uglify()) .pipe(concat('index.min.js')) .pipe(gulp.dest(paths.scripts.dest)); } function reload(done) { server.reload(); done(); } function serve(done) { server.init({ server: { baseDir: './' } }); done(); } const watch = () => gulp.watch(paths.scripts.src, gulp.series(scripts, reload)); const dev = gulp.series(clean, scripts, serve, watch); export default dev; ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/mocha-test-runner-with-gulp.md000066400000000000000000000015041415667007300252350ustar00rootroot00000000000000# Mocha test-runner with gulp ### Passing shared module in all tests ```js // npm install gulp gulp-mocha var gulp = require('gulp'); var mocha = require('gulp-mocha'); gulp.task('default', function() { return gulp.src(['test/test-*.js'], { read: false }) .pipe(mocha({ reporter: 'spec', globals: { should: require('should') } })); }); ``` ### Running mocha tests when files change ```js // npm install gulp gulp-mocha gulplog var gulp = require('gulp'); var mocha = require('gulp-mocha'); var log = require('gulplog'); gulp.task('mocha', function() { return gulp.src(['test/*.js'], { read: false }) .pipe(mocha({ reporter: 'list' })) .on('error', log.error); }); gulp.task('watch-mocha', function() { gulp.watch(['lib/**', 'test/**'], gulp.series('mocha')); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/only-pass-through-changed-files.md000066400000000000000000000016071415667007300260420ustar00rootroot00000000000000# Only pass through changed files Files are passed through the whole pipe chain on every run by default. By using [gulp-changed](https://github.com/sindresorhus/gulp-changed) only changed files will be passed through. This can speed up consecutive runs considerably. ```js // npm install --save-dev gulp gulp-changed gulp-jscs gulp-uglify var gulp = require('gulp'); var changed = require('gulp-changed'); var jscs = require('gulp-jscs'); var uglify = require('gulp-uglify'); // we define some constants here so they can be reused var SRC = 'src/*.js'; var DEST = 'dist'; gulp.task('default', function() { return gulp.src(SRC) // the `changed` task needs to know the destination directory // upfront to be able to figure out which files changed .pipe(changed(DEST)) // only files that has changed will pass through here .pipe(jscs()) .pipe(uglify()) .pipe(gulp.dest(DEST)); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/pass-arguments-from-cli.md000066400000000000000000000012211415667007300244170ustar00rootroot00000000000000# Pass arguments from the command line ```js // npm install --save-dev gulp gulp-if gulp-uglify minimist var gulp = require('gulp'); var gulpif = require('gulp-if'); var uglify = require('gulp-uglify'); var minimist = require('minimist'); var knownOptions = { string: 'env', default: { env: process.env.NODE_ENV || 'production' } }; var options = minimist(process.argv.slice(2), knownOptions); gulp.task('scripts', function() { return gulp.src('**/*.js') .pipe(gulpif(options.env === 'production', uglify())) // only minify in production .pipe(gulp.dest('dist')); }); ``` Then run gulp with: ```sh $ gulp scripts --env development ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/rebuild-only-files-that-change.md000066400000000000000000000005431415667007300256340ustar00rootroot00000000000000# Rebuild only files that change With [`gulp-watch`](https://github.com/floatdrop/gulp-watch): ```js var gulp = require('gulp'); var sass = require('gulp-sass'); var watch = require('gulp-watch'); gulp.task('default', function() { return gulp.src('sass/*.scss') .pipe(watch('sass/*.scss')) .pipe(sass()) .pipe(gulp.dest('dist')); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/rollup-with-rollup-stream.md000066400000000000000000000041761415667007300250460ustar00rootroot00000000000000# Rollup with rollup-stream Like Browserify, [Rollup](https://rollupjs.org/) is a bundler and thus only fits naturally into gulp if it's at the start of the pipeline. Unlike Browserify, Rollup doesn't natively produce a stream as output and needs to be wrapped before it can take this position. [rollup-stream](https://github.com/Permutatrix/rollup-stream) does this for you, producing output just like that of Browserify's `bundle()` method—as a result, most of the Browserify recipes here will also work with rollup-stream. ## Basic usage ```js // npm install --save-dev gulp rollup-stream vinyl-source-stream var gulp = require('gulp'); var rollup = require('rollup-stream'); var source = require('vinyl-source-stream'); gulp.task('rollup', function() { return rollup({ entry: './src/main.js' }) // give the file the name you want to output with .pipe(source('app.js')) // and output to ./dist/app.js as normal. .pipe(gulp.dest('./dist')); }); ``` ## Usage with sourcemaps ```js // npm install --save-dev gulp rollup-stream gulp-sourcemaps vinyl-source-stream vinyl-buffer // optional: npm install --save-dev gulp-rename var gulp = require('gulp'); var rollup = require('rollup-stream'); var sourcemaps = require('gulp-sourcemaps'); //var rename = require('gulp-rename'); var source = require('vinyl-source-stream'); var buffer = require('vinyl-buffer'); gulp.task('rollup', function() { return rollup({ entry: './src/main.js', sourceMap: true }) // point to the entry file. .pipe(source('main.js', './src')) // buffer the output. most gulp plugins, including gulp-sourcemaps, don't support streams. .pipe(buffer()) // tell gulp-sourcemaps to load the inline sourcemap produced by rollup-stream. .pipe(sourcemaps.init({loadMaps: true})) // transform the code further here. // if you want to output with a different name from the input file, use gulp-rename here. //.pipe(rename('index.js')) // write the sourcemap alongside the output file. .pipe(sourcemaps.write('.')) // and output to ./dist/main.js as normal. .pipe(gulp.dest('./dist')); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/run-grunt-tasks-from-gulp.md000066400000000000000000000033261415667007300247420ustar00rootroot00000000000000# Run Grunt Tasks from Gulp It is possible to run Grunt tasks / Grunt plugins from within Gulp. This can be useful during a gradual migration from Grunt to Gulp or if there's a specific plugin that you need. With the described approach no Grunt CLI and no Gruntfile is required. **This approach requires Grunt >=1.0.0** very simple example `gulpfile.js`: ```js // npm install gulp grunt grunt-contrib-copy --save-dev var gulp = require('gulp'); var grunt = require('grunt'); grunt.initConfig({ copy: { main: { src: 'src/*', dest: 'dest/' } } }); grunt.loadNpmTasks('grunt-contrib-copy'); gulp.task('copy', function (done) { grunt.tasks( ['copy:main'], //you can add more grunt tasks in this array {gruntfile: false}, //don't look for a Gruntfile - there is none. :-) function () {done();} ); }); ``` Now start the task with: `gulp copy` With the aforementioned approach the grunt tasks get registered within gulp's task system. **Keep in mind grunt tasks are usually blocking (unlike gulp), therefore no other task (not even a gulp task) can run until a grunt task is completed.** ### A few words on alternatives There's a *gulpfriendly* node module `gulp-grunt` [available](https://www.npmjs.org/package/gulp-grunt) which takes a different approach. It spawns child processes and within them the grunt tasks are executed. The way it works implies some limitations though: * It is at the moment not possible to pass options / cli args etc. to the grunt tasks via `gulp-grunt` * All grunt tasks have to be defined in a separate Gruntfile * You need to have the Grunt CLI installed * The output of some grunt tasks gets malformatted (.i.e. color coding). node-gulp-4.0.2+~cs38.20.35/docs/recipes/running-shell-commands.md000066400000000000000000000014311415667007300243270ustar00rootroot00000000000000# Running Shell Commands Sometimes it is helpful to be able to call existing command line tools from gulp. There are 2 ways to handle this: node's [`child_process`](https://nodejs.org/api/child_process.html) built-in module or [`gulp-exec`](https://github.com/robrich/gulp-exec) if you need to integrate the command with an existing pipeline. ```js 'use strict'; var cp = require('child_process'); var gulp = require('gulp'); gulp.task('reset', function() { // In gulp 4, you can return a child process to signal task completion return cp.execFile('git checkout -- .'); }); ``` ```js 'use strict'; var gulp = require('gulp'); var exec = require('gulp-exec'); gulp.task('reset', function() { return gulp.src('./**/**') .pipe(exec('git checkout -- <%= file.path %>')); }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/running-task-steps-per-folder.md000066400000000000000000000035631415667007300255640ustar00rootroot00000000000000# Generating a file per folder If you have a set of folders, and wish to perform a set of tasks on each, for instance... ``` /scripts /scripts/jquery/*.js /scripts/angularjs/*.js ``` ...and want to end up with... ``` /scripts /scripts/jquery.min.js /scripts/angularjs.min.js ``` ...you'll need to do something like the following... ``` javascript var fs = require('fs'); var path = require('path'); var merge = require('merge-stream'); var gulp = require('gulp'); var concat = require('gulp-concat'); var rename = require('gulp-rename'); var uglify = require('gulp-uglify'); var scriptsPath = 'src/scripts'; function getFolders(dir) { return fs.readdirSync(dir) .filter(function(file) { return fs.statSync(path.join(dir, file)).isDirectory(); }); } gulp.task('scripts', function(done) { var folders = getFolders(scriptsPath); if (folders.length === 0) return done(); // nothing to do! var tasks = folders.map(function(folder) { return gulp.src(path.join(scriptsPath, folder, '/**/*.js')) // concat into foldername.js .pipe(concat(folder + '.js')) // write to output .pipe(gulp.dest(scriptsPath)) // minify .pipe(uglify()) // rename to folder.min.js .pipe(rename(folder + '.min.js')) // write to output again .pipe(gulp.dest(scriptsPath)); }); // process all remaining files in scriptsPath root into main.js and main.min.js files var root = gulp.src(path.join(scriptsPath, '/*.js')) .pipe(concat('main.js')) .pipe(gulp.dest(scriptsPath)) .pipe(uglify()) .pipe(rename('main.min.js')) .pipe(gulp.dest(scriptsPath)); return merge(tasks, root); }); ``` A few notes: - `folders.map` - executes the function once per folder, and returns the async stream - `merge` - combines the streams and ends only when all streams emitted end node-gulp-4.0.2+~cs38.20.35/docs/recipes/running-tasks-in-series.md000066400000000000000000000047351415667007300244540ustar00rootroot00000000000000# Running tasks in series By default, gulp CLI run tasks with maximum concurrency - e.g. it launches all the tasks at once and waits for nothing. If you want to create a series where tasks run in a particular order, you should use `gulp.series`; ```js var gulp = require('gulp'); var doAsyncStuff = require('./stuff'); gulp.task('one', function(done) { doAsyncStuff(function(err){ done(err); }); }); gulp.task('two', function(done) { // do things done(); }); gulp.task('default', gulp.series('one', 'two')); ``` Another example, using a dependency pattern. It uses [`async-once`](https://www.npmjs.com/package/async-once) to run the `clean` task operations only once: ```js var gulp = require('gulp'); var del = require('del'); // rm -rf var once = require('async-once'); gulp.task('clean', once(function(done) { // run only once. // for the next call to the clean task, once will call done with // the same arguments as the first call. del(['output'], done); })); gulp.task('templates', gulp.series('clean', function() { return gulp.src(['src/templates/*.hbs']) // do some concatenation, minification, etc. .pipe(gulp.dest('output/templates/')); })); gulp.task('styles', gulp.series('clean', function() { return gulp.src(['src/styles/app.less']) // do some hinting, minification, etc. .pipe(gulp.dest('output/css/app.css')); })); // templates and styles will be processed in parallel. // `clean` will be guaranteed to complete before either start. // `clean` operations will not be run twice, // even though it is called as a dependency twice. gulp.task('build', gulp.parallel('templates', 'styles')); // an alias. gulp.task('default', gulp.parallel('build')); ``` Note that it's an anti-pattern in Gulp 4 and the logs will show the clean task running twice. Instead, `templates` and `style` should use dedicated `clean:*` tasks: ```js var gulp = require('gulp'); var del = require('del'); gulp.task('clean:templates', function() { return del(['output/templates/']); }); gulp.task('templates', gulp.series('clean:templates', function() { return gulp.src(['src/templates/*.hbs']) .pipe(gulp.dest('output/templates/')); }); gulp.task('clean:styles', function() { return del(['output/css/']); }); gulp.task('styles', gulp.series('clean:styles', function() { return gulp.src(['src/styles/app.less']) .pipe(gulp.dest('output/css/app.css')); })); gulp.task('build', gulp.parallel('templates', 'styles')); gulp.task('default', gulp.parallel('build')); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/server-with-livereload-and-css-injection.md000066400000000000000000000054371415667007300276660ustar00rootroot00000000000000# Server with live-reloading and CSS injection With [BrowserSync](https://browsersync.io) and gulp, you can easily create a development server that is accessible to any device on the same WiFi network. BrowserSync also has live-reload built in, so there's nothing else to configure. First install the modules: ```sh $ npm install --save-dev gulp browser-sync ``` Then, considering the following file structure... ``` gulpfile.js app/ styles/ main.css scripts/ main.js index.html ``` ... you can easily serve files from the `app` directory and have all browsers reload when any of them change with the following in `gulpfile.js`: ```js var gulp = require('gulp'); var browserSync = require('browser-sync'); var reload = browserSync.reload; // watch files for changes and reload gulp.task('serve', function() { browserSync({ server: { baseDir: 'app' } }); gulp.watch(['*.html', 'styles/**/*.css', 'scripts/**/*.js'], {cwd: 'app'}, reload); }); ``` and including the CSS in `index.html`: ```html ... ... ``` to serve your files and launch a browser window pointing to the default URL (http://localhost:3000) run: ```bash gulp serve ``` ## + CSS pre-processors A common use-case is to reload CSS files after they've been pre-processed. Using Sass as an example, this is how you can instruct browsers to reload the CSS without doing a full-page refresh. Considering this updated file structure... ``` gulpfile.js app/ scss/ main.scss scripts/ main.js index.html ``` ... you can easily watch Sass files from the `scss` directory and have all browsers reload when any of them change with the following in `gulpfile.js`: ```js var gulp = require('gulp'); var sass = require('gulp-ruby-sass'); var browserSync = require('browser-sync'); var reload = browserSync.reload; gulp.task('sass', function() { return sass('scss/styles.scss') .pipe(gulp.dest('app/css')) .pipe(reload({ stream:true })); }); // watch Sass files for changes, run the Sass preprocessor with the 'sass' task and reload gulp.task('serve', gulp.series('sass', function() { browserSync({ server: { baseDir: 'app' } }); gulp.watch('scss/*.scss', gulp.series('sass')); })); ``` and including the pre-processed CSS in `index.html`: ```html ... ... ``` to serve your files and launch a browser window pointing to the default URL (http://localhost:3000) run: ```bash gulp serve ``` ## Extras - Live reload, CSS injection and scroll/form syncing works seamlessly inside of [BrowserStack](https://www.browserstack.com/) virtual machines. - Set `tunnel: true` to view your local site at a public URL (complete with all BrowserSync features). node-gulp-4.0.2+~cs38.20.35/docs/recipes/sharing-streams-with-stream-factories.md000066400000000000000000000037571415667007300273060ustar00rootroot00000000000000# Sharing streams with stream factories If you use the same plugins in multiple tasks you might find yourself getting that itch to DRY things up. This method will allow you to create factories to split out your commonly used stream chains. We'll use [lazypipe](https://github.com/OverZealous/lazypipe) to get the job done. This is our sample file: ```js var gulp = require('gulp'); var uglify = require('gulp-uglify'); var coffee = require('gulp-coffee'); var jshint = require('gulp-jshint'); var stylish = require('jshint-stylish'); gulp.task('bootstrap', function() { return gulp.src('bootstrap/js/*.js') .pipe(jshint()) .pipe(jshint.reporter(stylish)) .pipe(uglify()) .pipe(gulp.dest('public/bootstrap')); }); gulp.task('coffee', function() { return gulp.src('lib/js/*.coffee') .pipe(coffee()) .pipe(jshint()) .pipe(jshint.reporter(stylish)) .pipe(uglify()) .pipe(gulp.dest('public/js')); }); ``` and our file after using lazypipe looks like this: ```js var gulp = require('gulp'); var uglify = require('gulp-uglify'); var coffee = require('gulp-coffee'); var jshint = require('gulp-jshint'); var stylish = require('jshint-stylish'); var lazypipe = require('lazypipe'); // give lazypipe var jsTransform = lazypipe() .pipe(jshint) .pipe(jshint.reporter, stylish) .pipe(uglify); gulp.task('bootstrap', function() { return gulp.src('bootstrap/js/*.js') .pipe(jsTransform()) .pipe(gulp.dest('public/bootstrap')); }); gulp.task('coffee', function() { return gulp.src('lib/js/*.coffee') .pipe(coffee()) .pipe(jsTransform()) .pipe(gulp.dest('public/js')); }); ``` You can see we split out our JavaScript pipeline (JSHint + Uglify) that was being reused in multiple tasks into a factory. These factories can be reused in as many tasks as you want. You can also nest factories and you can chain factories together for great effect. Splitting out each shared pipeline also gives you one central location to modify if you decide to change up your workflow. node-gulp-4.0.2+~cs38.20.35/docs/recipes/specifying-a-cwd.md000066400000000000000000000007301415667007300230750ustar00rootroot00000000000000# Specifying a new cwd (current working directory) This is helpful for projects using a nested directory structure, such as: ``` /project /layer1 /layer2 ``` You can use the gulp CLI option `--cwd`. From the `project/` directory: ```sh gulp --cwd layer1 ``` If you only need to specify a cwd for a certain glob, you can use the `cwd` option on a [glob-stream](https://github.com/gulpjs/glob-stream): ```js gulp.src('./some/dir/**/*.js', { cwd: 'public' }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/split-tasks-across-multiple-files.md000066400000000000000000000016041415667007300264440ustar00rootroot00000000000000# Split tasks across multiple files If your `gulpfile.js` is starting to grow too large, you can split the tasks into separate files by using the [gulp-hub](https://github.com/frankwallis/gulp-hub/tree/4.0) module as a [custom registry](https://github.com/phated/undertaker#registryregistryinstance). Imagine the following file structure: ``` gulpfile.js tasks/ ├── dev.js ├── release.js └── test.js ``` Install the `gulp-hub` module: ```sh npm install --save-dev gulp gulp-hub ``` Add the following lines to your `gulpfile.js` file: ```js 'use strict'; var gulp = require('gulp'); var HubRegistry = require('gulp-hub'); /* load some files into the registry */ var hub = new HubRegistry(['tasks/*.js']); /* tell gulp to use the tasks just loaded */ gulp.registry(hub); ``` This recipe can also be found at https://github.com/frankwallis/gulp-hub/tree/4.0/examples/recipe node-gulp-4.0.2+~cs38.20.35/docs/recipes/templating-with-swig-and-yaml-front-matter.md000066400000000000000000000014531415667007300301530ustar00rootroot00000000000000# Templating with Swig and YAML front-matter Templating can be setup using `gulp-swig` and `gulp-front-matter`: ##### `page.html` ```html --- title: Things to do todos: - First todo - Another todo item - A third todo item --- {{ title }}

{{ title }}

    {% for todo in todos %}
  • {{ todo }}
  • {% endfor %}
``` ##### `gulpfile.js` ```js var gulp = require('gulp'); var swig = require('gulp-swig'); var frontMatter = require('gulp-front-matter'); gulp.task('compile-page', function() { gulp.src('page.html') .pipe(frontMatter({ property: 'data' })) .pipe(swig()) .pipe(gulp.dest('build')); }); gulp.task('default', ['compile-page']); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/using-external-config-file.md000066400000000000000000000016661415667007300251020ustar00rootroot00000000000000# Using external config file Beneficial because it's keeping tasks DRY and config.json can be used by another task runner, like `grunt`. - ###### `config.json` ```json { "desktop" : { "src" : [ "dev/desktop/js/**/*.js", "!dev/desktop/js/vendor/**" ], "dest" : "build/desktop/js" }, "mobile" : { "src" : [ "dev/mobile/js/**/*.js", "!dev/mobile/js/vendor/**" ], "dest" : "build/mobile/js" } } ``` - ###### `gulpfile.js` ```js // npm install --save-dev gulp gulp-uglify merge-stream var gulp = require('gulp'); var uglify = require('gulp-uglify'); var merge = require('merge-stream'); var config = require('./config.json'); function doStuff(cfg) { return gulp.src(cfg.src) .pipe(uglify()) .pipe(gulp.dest(cfg.dest)); } gulp.task('dry', function() { // return a stream to signal completion return merge([ doStuff(config.desktop), doStuff(config.mobile) ]) }); ``` node-gulp-4.0.2+~cs38.20.35/docs/recipes/using-multiple-sources-in-one-task.md000066400000000000000000000013211415667007300265230ustar00rootroot00000000000000# Using multiple sources in one task ```js // npm install --save-dev gulp merge-stream var gulp = require('gulp'); var merge = require('merge-stream'); gulp.task('test', function() { var bootstrap = gulp.src('bootstrap/js/*.js') .pipe(gulp.dest('public/bootstrap')); var jquery = gulp.src('jquery.cookie/jquery.cookie.js') .pipe(gulp.dest('public/jquery')); return merge(bootstrap, jquery); }); ``` `gulp.src` will emit files in the order they were added: ```js // npm install gulp gulp-concat var gulp = require('gulp'); var concat = require('gulp-concat'); gulp.task('default', function() { return gulp.src(['foo/*', 'bar/*']) .pipe(concat('result.txt')) .pipe(gulp.dest('build')); }); node-gulp-4.0.2+~cs38.20.35/docs/why-use-pump/000077500000000000000000000000001415667007300203505ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/docs/why-use-pump/README.md000066400000000000000000000075021415667007300216330ustar00rootroot00000000000000# Why Use Pump? When using `pipe` from the Node.js streams, errors are not propagated forward through the piped streams, and source streams aren’t closed if a destination stream closed. The [`pump`][pump] module normalizes these problems and passes you the errors in a callback. ## A common gulpfile example A common pattern in gulp files is to simply return a Node.js stream, and expect the gulp tool to handle errors. ```javascript // example of a common gulpfile var gulp = require('gulp'); var uglify = require('gulp-uglify'); gulp.task('compress', function () { // returns a Node.js stream, but no handling of error messages return gulp.src('lib/*.js') .pipe(uglify()) .pipe(gulp.dest('dist')); }); ``` ![pipe error](pipe-error.png) There’s an error in one of the JavaScript files, but that error message is the opposite of helpful. You want to know what file and line contains the error. So what is this mess? When there’s an error in a stream, the Node.js stream fire the 'error' event, but if there’s no handler for this event, it instead goes to the defined [uncaught exception][uncaughtException] handler. The default behavior of the uncaught exception handler is documented: > By default, Node.js handles such exceptions by printing the stack trace to > stderr and exiting. ## Handling the Errors Since allowing the errors to make it to the uncaught exception handler isn’t useful, we should handle the exceptions properly. Let’s give that a quick shot. ```javascript var gulp = require('gulp'); var uglify = require('gulp-uglify'); gulp.task('compress', function () { return gulp.src('lib/*.js') .pipe(uglify()) .pipe(gulp.dest('dist')) .on('error', function(err) { console.error('Error in compress task', err.toString()); }); }); ``` Unfortunately, Node.js stream’s `pipe` function doesn’t forward errors through the chain, so this error handler only handles the errors given by `gulp.dest`. Instead we need to handle errors for each stream. ```javascript var gulp = require('gulp'); var uglify = require('gulp-uglify'); gulp.task('compress', function () { function createErrorHandler(name) { return function (err) { console.error('Error from ' + name + ' in compress task', err.toString()); }; } return gulp.src('lib/*.js') .on('error', createErrorHandler('gulp.src')) .pipe(uglify()) .on('error', createErrorHandler('uglify')) .pipe(gulp.dest('dist')) .on('error', createErrorHandler('gulp.dest')); }); ``` This is a lot of complexity to add in each of your gulp tasks, and it’s easy to forget to do it. In addition, it’s still not perfect, as it doesn’t properly signal to gulp’s task system that the task has failed. We can fix this, and we can handle the other pesky issues with error propogations with streams, but it’s even more work! ## Using pump The [`pump`][pump] module is a cheat code of sorts. It’s a wrapper around the `pipe` functionality that handles these cases for you, so you can stop hacking on your gulpfiles, and get back to hacking new features into your app. ```javascript var gulp = require('gulp'); var uglify = require('gulp-uglify'); var pump = require('pump'); gulp.task('compress', function (cb) { pump([ gulp.src('lib/*.js'), uglify(), gulp.dest('dist') ], cb ); }); ``` The gulp task system provides a gulp task with a callback, which can signal successful task completion (being called with no arguments), or a task failure (being called with an Error argument). Fortunately, this is the exact same format `pump` uses! ![pump error](pump-error.png) Now it’s very clear what plugin the error was from, what the error actually was, and from what file and line number. [pump]: https://github.com/mafintosh/pump [uncaughtException]: https://nodejs.org/api/process.html#process_event_uncaughtexception node-gulp-4.0.2+~cs38.20.35/docs/why-use-pump/pipe-error.png000066400000000000000000004322221415667007300231470ustar00rootroot00000000000000PNG  IHDR!qsRGB@IDATx]`S$^(m@lAT *n' D\:RB{YܛI{s2@{{졇5yѡue2@ P(@9C?B*~ؾ/ZER OVjPhe2@ P(a@ P(d֮]ޛo >>M6m%e2@ P(eoʀX,'|rhҤI;::jPؔe2@ P(aĶ\zكB P(e2@ )|r{uu(Aq"(sͅ|A A+6T*?ʊlʳ[ǂOUWUga.05\-{'WȔe2@ P(;'_PZZڣu {}^XKA`iWˠ|3l`Re"G3sƽY]Nͬ,,`8fO8Ofqav,6 >K,cFcgt&i ee@V_ RF+>޼W'x.: %T0Mp x(ȉ/+JM~kXoOՐ 1^K@j+dLPuKdUW` w/g n+m(޻ڬOYLzm߾r̾leV7u_ʀs,D*ȱJFEAbV4_ k/枰n^Jk1APp|EXz (bWBFq#+j 1 aKVPHع>xVXr s< }]R-BN9ށB1ߖ¦1'UWd56`3U[>|`=q1NoB!ж^ x{Pg ӣZR%`CCU6:ܷaħ3lڣRT]<_|.{-<9:P5EO_ߴe0)E#![2hkF?f;;_J27 VໍŰa 3 PGS6>+E0 ȇ?e~ӎ×aۺޑx3 ʰ GZ섥+Dx!ݵ1V#I P*z-0iJw˻RYaE 1Mz4^=QħB2'R0a?H. Sq" 5^RؔV 8>e8zF tr*f;ԕs!RD9 ~۷ΝG^zBܴD{WOnhʒ{ῈA>X~>k$[HaG1y7 ' |/<6>#V@i d$|'ڏP1{QCUA}]C} U0zҙ\/~8xx%̎UIOh P yV6ȿx<8` }KO<:Yei̥^۔btД0t-7w^Lҏo#SɃqH m5LR3|Axpx8,GAARZ:1+e21 {j~E<Lc3yJj"jom' AMw3Ir FL!nP _|pMBKʎ3l}_o+ P(gf ck rrL9-5יr^{f=3pTDqƸ(W\C\o˜C%{I\r\&K(; k vSm?m"͵Z@sWMAV[A}b4H1r(fg݇LO|ȶ7qǛl)#y9dWzm}|@Lu8kf|aъ1pifxGx0V. x$ !^l 2+>$'bdl ^5HYnArKRj͔1:e2p00h;*oޠhlD|]0Ie8Ԛ yc cȳ=1lGaC$/q8 UCk#vhX8$nOh8w=P^:FSoR6]+އS98_uY0ϙc)iGa /@r9N0`"kl:{X2 $avTqRQ4՗ٽ@:\tg3콽 xŹ><PJ{L͂A*5tvhik H:#6w@u | (o4s|pNV1VT@Eig>0_j^~rSj7\u:# ;*Q__9USg(0/sK| MP[{>>`uxYM:xΚM!e ߘZ+vBN,,, SK,0hqh\uG%\RN~ ]P?u-:S0ap.*`N~RPc&.fi|b ~Ӡp8\/4KAOe ]e+ܖCf~0ct MF [,L{77(oUq&gIJH懅8׶}0.ngm'3s7⟆Hķpp&8e(8 [2 p|p +WAmp7f@_1q30L<^omzl#n!>*/p[8x`81ꕲ: œՏwW2çY9jq|9&L#a<>@,+ჯ?3f3p7^N[/}Sx{Wxo/3-'eǣ_rq_xu]ez ^H2Y( fEE&O.M<ʑ3i1| #Gf ~&ЛsbQ.Xă:e2p0 $$=jJnbcK}@p\ֳ(CVš$0=df spc/\52> .5\6Ţwz5J 26í9b\ES`y]7)W0| 6\.GTh^T?[ge E^_ B V># g{ Y&H:e2p0 0CSe2@0`3<45Y0%M4O?e:e2p0 HOORe2@ P(e&̀& P(e2@ P<qMs P(e2@ v)P(e2@ P<D'Nr9Q(e2@ P(jokT8e2@ P(e2+cłW2X'/Ӻ?fm2@ P(e2@M On*2@ P(e2@iR 1 9 DIoH(MD P(oiR[m䆊œOmI :^ǘ/%$}f:C1p HH}7>HSa*''sw&A[T5?^g^EMZ`'Ai*>g|0e2@ z'V]0q -Sk,YC{ Ի\U|M+Hvr&mDqnJX.lnJRK a#qbʺKpM2WwTmoI}NBelL ΌM(e2p0j~_O p_ G?rŊy <>ۖ]d5įYVh>Xwд2~Yu+Lv8No@ir{^)A^v"kV8cCʪ  p2/61#DI;]QEY >/ѾT4p^&,#K?7hh~0(6 9O'*M]mm]|1s%j2`شQS̿Ka)辚`tˍ^aڰ WrVVWX4I6SZU讣$ ӧv0V>UT0:<k/oWre^>VbLncݱ|vkm&ZYY#[n3 "l~רæjC^b;oZX֗G2wZ?Ϧ/M?hV'N}(egcnܻ||R~.V4D}ҮX oƋ/:v#W0u'㾣Bo_P$B5I*X$ WVh&ihhi`ALXۯܱV=$NWLJ3ﶉ!E.5v KNpmːm߰)Xj}~lE$9"@J?5 j_\4%}aY&YC~lPdA&<;`X׼CߡlpqGd2| -!abUrմ'Z:#C"ذim!ҰLXZfӵy8w$wѸoijk-_5:uH chuU‘bw㻚t|eWbamYXwLM'p$2Zj(;׆]4VcgBJZܱ#e߱ts+[ .̡;HX֮6ۓ򱭪s9i7%8nX@P8"a⩡}J.e X0Yef ? ++1 ں:Ys 7Z e2@  p['1Ff^?+=}^dC0M*n%P M*#/"ZsKklBHtbbw$誫[G[dzȬ=ݿˈ'?9!ڿ%OeY'N;^Z2? 6ЃWIXРmWtߜ+^'I yR:쎠_d?chZ1`<8ĝIYeĭ>uBTV\s2+pZCѦV | :QPq+qjP'Q )V/2;+X~kFf"_ {>8Vym^eˢǟN1\wl[Cp̔6lh[Mj E guQ[}.?ZUhf%=YuML[o];.vs;oc)/=b!iLRȀY9,Dp0L1ta[24;rH)7qCKes[wfng䒏&hm3ՖbP~s伾-je]$rA |+pX/ E!|Ks(pA,֖ bAI;6kot(OK_7=`Mt5&/peo1۞ #\ks}sĊxi?\ sbI1;յ"-u7wÅ@$.A2D2X/ԅ/0V_>kcEU2yᅳjκW|a"2@ Pd |0#&h]0fvP0|AD4>WxW) !?Q_JƂnЋ␐qD/p=}GvV3ַBp n/aAn"VZzaJEי;_.u؜f{dCeRbKc,UyÌo6{S#|ES{9̳D.XO}aU޵sd]?j6wbk]ډysHk[Hqh7z`ߥf4[_xQv W|cA'kbx -Aqk'/^%4E]r 늋S( K*n;iԩ@%Tp:Metҫ6B7%*tȑ$vk<6q3q@^z{ 5|#f|%@|psz|L?d9Qڤzy^&婫0 O5Jc}=%Ig</DHϾUd HI׍o^=q`43)S?BRz"ꞟO>oe[3K4 0a5C#fr1ЎGmfaZd+2d=$H~}Ƹ'2̜wtT$:7d*ܣ 2+ۤjhY}fxL{u4τ@r59fLXX8qYG {0,4,Ǔst·# gb72΢XS -lppQL53(ne'_Fb/K$"AqkV&+0)9N>z3y`Z5˗8\ᓉa=c|Awc P(;#;pf׌KqBb%W÷BXĀۋT}iܬa!>GZK6ð 951_owe_"r:7/F\F0⨑#’58a5aQԌunҁoI^M&$#uMM8qymU#sVqp<]Z/滥UMعˈlw8t85_l֦Ɩį*xNW"Z Z,N+_f=>vb`7 d5hAc>cIGzͥZ?~IsrJqƸfqW%]VJ;kYLvO"N2!6凑`ilSp2aPhhf뤳s](o4dDM] lW;֓Ug,NçŝYž1, J 3h# (-ޖ90TQ(7i87\߮-8:PI1|8^w@l7nxoM~-'x:aF*ēB` JMiVЫ#IM^|5pUT<8@7pѿ6E~|`>=kw£ 68[s _:Ø Y4ÃH4V6gx*lxć@ tQ(ORD`$LcLDs\WKJ#c bruCBn,pUFZRV#h ˒=K5/Q~mݳ^f匼kثJ['>0:Vz׿ ,] p;@/(e60P^^)YjuԤ9+;gPv@[ 52![5./o_O{,e}+t%hFrUV&䓗ƽr4ލh1y=w5&XE'?MqO)[,tK*GZ`򼰈q3v_տ b)@c0|Й i\w/#=!r̅nS9y=/uXܢGNfgyŧ6"_6-ҥvJ)^Q(@3ءxOugwhC'Q:C{>]'#v%("2kT7r},'}---wVI\cFD8 Z)6eEw>?.8>/{a P([1&ʣ P(e2@ ]_sJUu2@ P(e2@god;';Fœ SȑÎlBo>Q KWk^c [F{7?M^Oڼ8mWr5i2|X%˵`ڼ.mԓİ)KLK<0yoI9sd(FNo6?]7x3Ǐؕ>솎CڂRY!;Tŵ쉌7d ~ ütO??UT=!ns!0ҧFZ;I%m~-}J׭3lv-`_s=$L^Y9Ԉ||-cX_s$Rv{>>,4ҋ^>"'L'9:܄`RB691QyZxCnA 0`G A]/ ao )}=mɝR*vq~0:;YYZt]wˑ!bиU&_*4,_ʏ`k,JJ-n1 je:{%aW ¥FX;9z@ Ƚę|h'}y; SL=Zd繤 -NLK pނ.΍v_ɹjBIiNONo2?m7HW:W@QB,)swC{}di2u7h$6s4a";ci,ROw/&`IlPBCs6=4_Fo>;Wi>@hެk=@dI)bR+k{}2]oSY2=wX&gz%)w{{^؏Uѓ\@~ɺ];vhmkjO=/s v.02.Imb=23&_g9;Y,s 3I伶Fi ;;'lh#rI +it#VQ*\$_4яiz=ab3^x|g'~\ly,^ޮ)_|* tϘ}0mnάwW|TAVR|d|uG[LheeQC>.k4ݦ#[M\dv]{Y:<{ mrNN483_gjS5xM3=rQVQJrA3`/;Kk<NؐL}0ya[BG߱ S$*_O; &9T=24ʦ=I=ŕF=>q%ԝj \tJ؂rF^̎*>,@f,|0ek]h:}Grm~ݵZ%z Odžum}k6om<롰vغAV֮rG~]]%.$;s.qāe'R;뻤 PqRNF hnD`fHzLSfS:@RvΜr)fɁ=Рf5IJ&xkʹ{P|a%WK O7L}(d%;RKM71_=oqvJ5/. ˖NMkr|Īnc&|]Bbpw8"=#gpܰwCw_PP(ߓKuB/[1cKczoppJuiO细:[:>JHjǬFiSIcs?VBJZRK%p'V D,Y;R_3_ᏐHFd.Hf[psu?51Nj*"aU-GhX\*vrp=x#llY Y s_@J3͍%~XX.+wFM{.^lkj칼|ߥMxg$,EW*6]yz҃Xw`Mꠖk [3tT.^yN0,ɰǔWͅ6Z]Hl gU*uD޴/]l-`}iDi7v<앾 [_G S~]"Tu.ʏOvuWόco|2;1t嚿Y.gϽajٹگȖ-*?l,؝T//?ޛt89_٩gS |mZÍh 5G [?Wue~)Rab!ZҸTFs0b;uز6yZO|sty(~@UZK/┩를Y]^YYT* ;g'ڄ_*oЭuhȓQU^|ydvK3Õ6tQ۽"9㕔N8x?<Z8yb}mryB0Oi1q 4"@twLp%*ض]ihylclc[ tqt=*Lu/LPuM}˕§ :< Fɭ,*ubEJrNF/+rPɮaR,җ]8YԜPqTVNt4pbiqiQTX)8QQ!tu|(wǺVX7_=J]*gsO8GEΫ@tߚqchABN)ϰ2L?Qy?X -On la&.>Cf­rŎf>y8HC8e W{ (W*tu64\t%?8 @voJo6 [5lQpL]us7굇8M}T b}AC?Ζ՟N׍Obѧ:!Nr bPMy!g0}VU^Ӓ|x^eK^{5r*C}@^e1#Rqu{ۍʏOhwuيiPxڟNnqʝGhLؕnk5^ ["x;ʶ]~'<Ԍ&}S~`݆~[ F۴?緉wO[?~G`~?W >`tvʭ-.qkS{EĉS\\ &Ƹ$9[9kGy`fy³ loX{op><ZٜWa~?9&Vb'aV,;oJ7R(OK_7=`Mt5(6/peoY-rT? f N2緖Ym U^)ivOìI8ti)"ӎ+7\ nfv=?K! lEn~~麨h ϫ*s2(J.| ,K7vAx핲Ұ#%C!çv[6SF=% X]E{vu ҄YNHDBJ^ 4x=`ɤ|3짾?sg2='7VXwOn=s]Itob3+O uc8wyϏݽޅ1uc53i!-!a:'_'tѨ&臱E[ ^\̦MwT3g|?I}r.ONW9vh DzҫWB,]'1ݥ*ʯuqx|nX=C=H2pF FĴϥQ5;2ʺ8.5gB^BpiMdw'O Xdi]foMѝ3g<^2zI ;U.FQYP_%P 6Jb$pYk[Eň:wkcQpngf'B a\2)Qw~x2ZvT .@IDATl[;YZțW/ 3'GLtx0nRut06:cſ+ vfo9|!mGu=7ZX|:P:ǩÎ3Jn(ݕq;/Xj [Ǔxt:qF.*:T|;*?o')jLS6bz  /1 K_-x_-=][-t rf љ/b:>*ֈɇgMq"D3M=p 4c k8[w chCi;)^4r^PN`ᤂ$a,?^:Ʊ{.uQL}9IGcsI1xK׺-R7&*7k>kGY\ u*Ys2'LW|ܯTMtD盒~Kt#աE4nh}-TS& 'טqHHX>̏\Ish5EwxkgY{ o3k_>˼Qo|FbFLPMs9vBq*ku K&`gL)2DD:4\j?T k"KKkmsdC,?ʁvß9xC|8cqlR>ߔS q`a#YH/춽tdV!/Aȳ^Df^\řYqO59%婫0|̨^6u<8[#9e_?.^!=%@sB#xd&sB"3B]ڞ+B?uA8(Zë4A0uC½cB 5;p U oGxT;ԉ8M3^]lQ% oC{qqJevE5w:rB 6_oUSK&wX:ܧP(q.v~$!#S였K>Ӄk[;^%*0#~-4§FІ֣_d=,3evǶb՝?o~lBNvb`OMoufw;S^C@6MI##"3QQ[/hƭkM|cDo_Ǹ'qzt.ca8kKTJP ܆C<\:S<_׽|=>oŸ(aӿΛ'.W?>N5^*.O9^Kߘq~*<Bd>.LbO?Rug6^o5b '7K5[tDu ˏgnkQ,mObڴAh=l.A61M!l8\mlp7@[E/ـOUu|cq8fPcީ=(p"IdWZ}XٺS\h3 jc_]2;xAk=[܈Fw㓉 r-[WoJGeuޓ#:\FU1ҷƠԪi5[<"Ak|mSgq$я~m~F4w}AOfAQXG4D:;z592@F6>]_ܤv^^:qMhiC9GD1 _4'&U*J!0 όH6NjJ3I.Ғ=K5/1dmݳ^¤t@^`| %m^킯wgʓݹ${\8> wX@:3&HggSWAn /8J/~3eE.D/$<7?M@1>1ǾAtD[w@՝#?pīHl{US'D ц]6ߥ˄A3CǝG,BL׽Gי[6znMgX:Qz3׽A1yS+?U*uס%ӿϤw_;9 a[5nUx. kQo@yyy>p.`T!ai#MMM[Iq0g-يјÊD&^_Yܗl1?m6qaz~@Qk&69̙ Uܐ(%g@6)]]ߒ{L@nԍ^ q8b1~a*H59ӠrqsXX?P<[{jØݠ^YhVį1&u$@35\M~ 뚏l1OkOx4}˶[}6,ZѦ~nLՃ~j&3^,:dۂ.%qπ٩+.3R#.;+0>]1oj=W~'iulzeF)?HgN'&M 9A{,-׎Lg3"/q"5Zp[i=э5j@]pL}'ą"AqUrfK+}Zz:D[wݦ4=]>noQ$0BY*?FeޖۀWۢ ̸ k` v[ÍΟ.roZ;QM(e2@ P('nלwRb P(e2@ P172CNȤ4pќ Sx44e2@ P(ɀc2dc[jP4^nY2ɋƒDŽ)e9aUi-9}V%,\8#agP+-g@|!`goVNnXZB*<4^V~`1\)k 4KQD8|X'3je"Z\K&p||ȂWlu|Idҡ)e2b<$i_֏5|?P2;ц9]ef)ƙaDû%xp]Šq/-LUdl1hX= gwȏ`k,JJ-n1ǃVuDNJ,+:$K獍vr&<͓\g}uݿT89nNwqx"-_51&3)Oh;\|ۚ{|OM P(@Wz6NڑgܶCk[SKV~y[PwTgj sr+-j:$`>$f ж~ӟJ'(¹c$r^[4ಁyi L~ʮ/RvNO7VcUxܜ _B%_G䬭d@t[?ô{~?~98 _#| D<>=X,%|%Zg_}eiG2wZ?Ϧ/M/y:Ȗb BL˧ bȑ-bO3_X&Mڙ*LT󢕏򲳶hk ,S~y`e=񐔘Ѻh$d5ǵA}dngiM^v7֒C5ٰ&°VhY~^ 1a2]iu:99:Gg7}#e2 l\L錯KTiPn<8[59YcXju~k32vU^&+S֜ٻ/8M%;"Fscir/7W*߽/%B-Goܼ3N*y9l,Vξvm?NIu u0J+3- vؑXjA ?+PRnր~qQ0#aiviM_nޞn0-jٞ$2/\*V+k>8dvUNX "ɩ Y'Smf?`fmc&rh?{.Kk'qnj* @^L`Vq:~ޕր:XgtXY0 B0'Qb_g5V\m~HUƉJҜXl3[)Q/LC0E P(eOdw8ab!ZҸTFs0e_íUVX\ݦ8sS8Ozu &]m?*݋ onz^ʛ啕hB,٤*kVI GwJKbz_gglWA0?!ŸlrѪp![P}Q[!1<<*W(KN$O,O-G!]1 (vu~+ϳcĉ1={=ANH8qTO5 %Ȱ}{rޭk/=`x LCfǕQzr}_̅"\]d|SXsTS8{{eq YQ!sgN[W{ 0w L o{ ZbIl &T^7'dRybFJK* z**z 44x#G >$T`6Md^/C>QGx,(*+R48ݜH47ڙWts?Nr37ҎQQG^AUo 1]G7bꮍ=@ (fJnϒr55Zjݭr[u(Z=مx^d2Nקڝbj^8{>oԯc٩=凨"QPئF&Ta?z[/FwX]yQCM*%s [w,@.#Cڊʲwg^}\ xZTp`,޳|ٵ>ovyS7 f(oaci޹׆Ԇ#ԌfɪGqkx|{oGŎ#xjکN8*equڻF75eZ'2Sx T˒ۥw JvB-qݖnTqA @ 0>Cx: 8r-칐{QK6tҬ>7:svw@@@A.>ݔJpr[<4 tl9u᪻ɧojuL+oа0{|ܥ_ޢ9$[6AaaӞSCr~kZ9u2ykPϊy**]zsk75:q[-!B(yNE2dX;Ɂ,>\<~. C<{O_2=nP뽒ܖ +atQ/G:^9K˷*.U;s^Lv=+bX7%f8r埮ۏٝ 7 3uSq wbp&_#ɧ=ɦaؔbT'6,X [v|XT<뚮ݺ"v?1ƙAw:nZl][C0Hdk8@ hQ+; j^38=Ebh557Y"Ǯ*|wCQI|ӜUW-2D&L=}*mG& V{r뺛61st).FNU_z>eI?v{prjBWTM'=?L0 9]ZCa|>$N,fы6}1.1$%4p[=1hU9 ȲiuH.5&_nE'[l!/^ܙoe>,\Л**ta = #o*oƙK @@Gnӆ4%4uuu,St\߷>{Ͱ"$]aXaHƘ-M2mwNh_m^H6At^O'jsB}ss# JVhxnqvrQP ypͭ)00 Nta3d>ʇc @h Ǖg磱y8x*#[LMf{~C*Ĺ{19 _9ȓUwiKzõ˘h*P5X3⯭ @ I<>Ijj @.FA|@؀@ "" @ 8`@ @  5&T @6@ pPcBU@ 8`@ @  5&T @6@ pPcBU@ 8`@ @  5&T @6@ pPcBU@ 8`@ @  5&T @5|~0!Z@ @LC9I[ 8eɀ.:a?.#'3~ 8܈cш @ &6Qtw?sRZ˃U!m!apOoo"ž; s<xk @ ft`ܔ#c\3%=z1|,;}{9~k}x`j}hl*$96C4yrnK$u)GI9ٟxm #,dNY+)}燃w7e rx\nVf⚹:79^Wͱ󙈁S @ `? 4vxOYQם:XPsulܒxf\k!2ZH9X!w3$>B,r#Gf_p_qdMM=s~uSչ}gS&Vb8- k*"9뼬"YŨgg<1֢_ r~*OMI(,rpvs଩e>zQxO>Qh7Wo؀H65NB䠀_KimrNa!8@ # NFi'_.6f93fd`VevjElP3Q蝂%ərď=%JXIԸ.'m?k>+B+$oPԖ-&#-lehwz~<Oo&Spn?Wd9^2s;_6;s6s%Xr@@ ho~=GE&zE5ʠH#م7% ahAUoHH2 ST %l ܞ0QLe/95`pj ?IIǴ,+dfm[ݜ Y7~dG{k~qrG_z/V#ե @ xӚ\U2Y=wۤȻ v)jG~xzNVֱZ*- P1窙֢Oee|;y]Ȩ/DN x.n_DtNIR ۽81;nK7W/IdI&\"Sו\oRQVS:[c/}4A @&@?_\Ƣ}?{@/J^V 6P|E=)p_j@Y+ [>[ҶN&otbsbȜrnNw&;*TWV9vs>nZlB߳s^mo̩:3d ͈ EΈ_ΞwqƌW^•VKWN40*54@ @@C~AGHVO {DhsaWN:z`Eav~:K>A05 A;(MSS_QA~_ FOz1(tҋTJhX7R_'kD )jew4vux@Y ^f0?^ O-As/I2Bx;E=zo}>p@ Ls|$zsPX%5^ҙؚO-GIQQX !N #tƣM.~:ikrK+3,4Rôp@ ڙ@eeep8:$l*Wr\WWH(Ou O-&+=Yeꗁ;i@m @qtpe;+*O;pP-t C~O T @ t]X“v,(@8@ "t_"j @4p@ j[ 0j"t H'I[v^6&gҔy 3kcMkyH۝ېO2 >s e6,c;}@tL]'hyȬ.暿˵jU*Ofgju4伛ii6A$On(r-dk3S 0I$ZT)&촳Iߧ;LP @$Щ_ [ۼ$zÌCrw-=5{z>x巖~^Ek?=_w֣ ԮTt -{)&p;#J.X_NLtζ~&})CWLH8CVecྗ89h%3 IҳB,uaw.|cwKORm1h݅ű4ģC[gGfZT-55ѕ*ɯ5 a%2 ӘZ*A(p~El=qdq2嘆JGګ4.쓔˖3I6:D/;ëZAV=_(EƘm9l}z/h@ `٨ )^{q3+W7Uݗz6uoieѓ8CJ3R]~T8/Fl5K~ZB> t0(iʰ^⦝_e-[/@=Esߠ~`rz^3w I7)+jS j$uQ x&PǁF{&thJir8Ӵ `:RÚ4%ع)8xu=| |e CK?K~Qrޞ"nՁzrʡٻ8&lЧcowf`Os>δzjhw,uȸ*C.(dНd C*%)&%bn[K}VE@ 8#F,[Zn]ڦڳ''׭Yw_DFFFψ)Xǟj!CB#7.jU\QK\Uᣝ ҽ3 #x/l}\ɡ<>Bpq8L`Q0<=+0s"!"BnꋪB$ hvJRY^u6?ZVoOaRQ2&֌ =ڕ\qghRie Bv$m$R~ ![;*S[X-\):lQڝ!>ժ0cSGgC:Y|18=H@5 ԧT0 @q\9Si^X*֍nD-MVXqҥ,[܆R7<M>22{.Q89'ǣ#[=GEJ`kA*ht$ڶ9kF r[>S!x:O%mlqF OlDX;W[RVUO=~ 7l#m~ֽfʵފϙHj 6cO]6L:=͏,HviHwPjQO+!@ )s4E'9\`&=ل*)/5k%m@[pnG&q4 Oᇟde`'JV@tAz=dFW+=o?7))ϗG3x&.QU 1cpFz9 _~o6pwwξSge_jdK'?shtD OpDE8Y#$@ WU/D+%,:@Z.[7o`p Ot/ _?`eN\Znp|rG!ڱWUb|O?1 MΛ92=.-s[;T#h_t˜۝ܶjZ4Qm[C*-[ԓG_mƖ&4iM@v]bcg+&!$g74nYwÛV;$vm!Y֧O$Qrv_HK+U#7Uť+{]tkeN {D"hsJ̺^b,H# njݒRh-,6@6nݸqv 8_" h6dS SҾ}~@c@O#JiNOF$C /;m#lPJ̯^XzN.[. @?hl]iFFcu( A3Z%f~m @R @NCA.NR(@ xȀA<@ # t [v9ygS$A(  @t ]a}S@pA @ G~,RBsĸ.xmP@ @ ȤqN=oҚcM@ m'|>2Q0^4\N_q?/ @ +X/wɁ~i@.(^+6& @tj7dZMR~(Xh@ +J+V @ :*Xɶ @ `z @ 8@A @ `=pg)@ @'~o"P @XO|YAJ @ @ &,B[DD޵2M&p @ @!@c ?vur b)LE@ @_ۏ)RikPeuO_WuvԤ#8![0M޲b\j@9D>[> @zs[pGZ1` =7lgk^hd8:;;{ vVxЭOyB{%MK^ܴ3뼌»qKB5Bi @  0ߐ gY=H{Z"*(%04jR(ݙSxGx|qeHDQ#H*nfGT @ `';|ۗH^&7Fn&AW8RR4qnCy<nsg4B @ |Ty+6isoA'TuR6״R)5|LL,@ `"@໪8d,;Kl-*׉˩.Qf4#\$ʼnKT8LK?]7~dwԄ.bh# @ zxQˣΈn`_ެT5G鎘㎠#$Ɂ$åňa`Χ @ @X @͜H KhIE8 @ TVVFxxx C#JяIh2$0@ /!@ 8@i @ @O|z. @ :%p;e@NJf͛g# ;1+l/ ~'"ގ:t?iˁ,ЎMpD r2ss#r9k/[όزfŋ`RܻA13>1JѓH'<z#ssE.&ɼ@*pc߲͌xm Woh6lFeFð3᤹NK^y&] 4;8xC6ɪ3iActGb.6(CdnYЁtT:'LskuX`m^w!d.=7$Ӫ[*ǸIzz ^pڨWS_Ȩ#gd6q3.,I{NG4sӟz|txn:99hۑw:tܼ⣓;&ŋ`j7&/{իp2ZsY^ֶ߮{Y{*J'BF6KHO,jgC͍Tɕ]* )y3SÓ\# wNy%h(wrf6!im~F2+œ41Ȝ4ϿB?31#z8TbG~=U]?59OtLZw)re lѳkSDf6]qo8GQn帍l$q/|q^I*gj O@wx/}"cn[fa$`PL<7>Q/G2혵1K:; |Y׿܂ܐKCIS~):bi{ ōFlWi(3 ,JtN^~F0D+d?$\ٹ9{8^:yۯke ?/Flାy{p<@D(f䂜 1 |G]#f6&[ 75SGS%Ƣ'5el2ng F]bG$*؛QXMV;= <9:Y趢URYdltiv$GAJHѐbYy*4oHU\LFک.t8rW6J˫%6R KNQZ/O 332aMmר6;!T%=lt6=YMY,c p`;Z,zRACz{='ikjceҧY\3 ߣC_cy6]XX&Q5t<9{؆;J']O2ͰEП=p8ӂ|'98+ޞ{["$4dz"EL6X56FȞsd 1^ IiB}_UN Rf6^[t1;uhFѺs:ԡfZ k]&t{ {h}glv1|{ sgjUѫNlHH>p3 OQFiK{dw.Q89'q J4?oYG# n )CW 3m)cSS g:"%c;0k?Mb:qkx|q<5>vu }L-m^5Ĭ&L}UO f]"N.kOfi8^Xtaj#}94-k d/6.GcrZnp|rG!]"ܤ$Dž84kLKTws'oݒ g?x6Uz8N^/#s:7xaP`ՔS 8^5| >-:n:/8^|Y3A&$̈~a@>q(7'b;e+WXn.v C'Xvw͚7>;4it3f '1a nK7Z4t2.򖦁~Q`X4oQO 嗚~!Iahzt1NNsaN@Ao|ݹ>c/ʉ Ag*RglmĖEr.߹Ax*J'o43h}6//wkĬY N~*瞪-Q Cg*"#yu=]KW)3fi l2Ԉ3[uS%{7a< =x~X0N7UdӬXt"S#zL4gzVdt=ӶM8&OM\]\x=#V|[Gbg}кVVOV]XOSw/ekO6by~({>]=3hkQe,.mš^ dFqrG1n Źɢ?3gNO#9þI?v{prjS_QA~+: *2WAstڸ=B:~b['dhsTWFxqodKW,wG:Y[w03j`5U@ȹnb:"R񴘯죜kF :hZb֬T5O4ǹJЯK':EJ\%HN6.ڲXOx?j`9Uwu329.8sɁD⥜5sf+A DW%ԖGo$ىS+ =0$Xۡh΂% #S|13JZ_Vbi_Q&yóky XG4m$h&?2Dz7bF)WAPV^MF4>}Q˃OiaaiW;%ѵW^MSLK7?g%rxN(~2qtKJq> ڸ cFa7+~L{!i X') T)VI-9L"Lmꤸqt04٧]#.~W]KYq0+Dȼ4\POz eӚ4imhIDW\%Q<@/Z#=5k6"!뱣{кR3]^i(Ky!)M,LfM؛#_(] FW6=qM,zTkNogbNRz˱Ugzm_:uNyߓo|&e6Zi1\1Aw..槁S EJkANSUzҨb{?,&֕GdSNgjT}>ﴍд4u%"k]:hAeeep8,$l*e#8>_0+ CV~qjM΢|,:wv߳}p"7ĪaK|9liJ}?BU +cp5 ք"ʂ$?ucnwugLՓL V??=*zb&aui3HXbV)pYtHαQ^ ŌVIz:mio-LhPRΘ|q*;W:cU:Eׇۡڪ@OS"\ޫ2Tuelx! sGw݂~ٲH=n4zUYz͗$mB$*D$i`$KwWN^g3c~ʏE_O}H? CPoW->u!&@~؎3?T؄_yr#oI*]a.XK _{歹y_sVOi ,:O+'ժ(U8l<{dɁ61^|ZuKX7iv԰n.^gmϤ'[іWg<c' :2v6M\͑`1NsD+Eo߬ď^-WP]9Fg{7:O{_CgYdl+56?&s+gTZɨ+&<ّ.}Imm[|uYLUONL@;$_?/ 7PҔ_ʭ䛟3WhKTy/EH!y,@۴]I#\~3u]3z /5w*dX܁F{SGS-{SSϜ_Tuv_jI C %/nډef-[O=g"v@9ۦ'^e 9#J3R]~T8/RH `% -]\H/e\=ED Tzci𞲢;uX]H*'Qꑆo݈t37rd{ieȰYފ4*K)ZMhZBUe>Q L&|4zgOFyםidȜUd$+b()?}+ER%UD|!K 4O ֞ب6;KȂ$xS!޷Qu<:N RpH U/.?{kRh/U?:p~;% Vs mȞ>¡~d~)eR+l7Ik*,9x%E]>M>86mj$uvTKACimn[>3aɯY!wPuo ˻*խӳWV侗vі]G 70OS6肝?\ d֞x9`{3ْ-(uU4}֦b)˨6B=|b?ԥfW=W#^t+xN3@8@ йzViee|;y]Ȩ/DN x.n_LO)Sk s89@4ess t2UdzR('P[CWI3Q׷I#&^؝OӦ1ɂ,Տe.2sza_6e$@&\QP!_+|pwGtصAezWϮ>Dr>YpܷOofٵ>ovyS7 f(os5Kl =*i?'xO>\c挭<6[¢]c~ٶ ORhThkwgHzbfOI ThU 0]ST;qVT>?HOMٙR\<{eV]Sg&c ]@|<=k(ܟ_wj}hFh!р]"}V̻TQқ[1]\igz\z#K&$`=y<).+mɨIOE:~MOU%;|z7cOL6M>*ܟNp}?e4hܴ~c|ZCdeYld 9!3km%\'.8Gy%.C_L.f́ا;3ZBbca?Ѣ w#ix;i$T~C-/T5H0_µrBr4j rGaHѬ /qP#嶹~dߛ7&!ѣ@񽁣c]t\|3fK}r B:5b,IF,c]Y\"Illbhz`a+! Mob['jlìduiRVh mmW/R/YGT(*0J(L頏>E7ZZ#h#[WiyZ򘠾J>G^`3 h܋Ӿly>mkbwn Źɢ|oR?Kk'Eʱm $|zP+z,[z#otbqi馵 z?t邨3[bZ_/~~c˼=T&_m坼Ԝf/}Uۥʃsp(i @W'@F&OU26][7G_^Q'Ib׺N _r6gRDco|1V0j[pzliıeZ'`zTZ\02k!z8Л**CfxD*5hk;ʬ20k#mSmF\980~j >MfcrL۪*$/>~L{*mix&ِYcFhf,9"^|DG";iN[Q Sm^hmOܖ7J_-Ό @eeep8:ITꨯx@Jvd\Vzˮ^+ x̯^X]-c?=is;逍 e;osߊoo3L~.g‰w.h%.ggDБκF@ !>f'qw[@++QX*^NgvPhbK^e,ZࣱfJ32ZiPMm(shކ~bC9"v; Pߡj @q_(T @tV O0!Ztֆdugּy1pd ׅԵ ]P g g`Y;O^;eh+:a?BŃ& ?+j*\͍ȥD|2/P`q; Ń#l)-̈ǰ=|W-&=mH0L8iDW^izzb~>s|7<]>x}U%j?C*ёX ЮYA[#Dض>KڃiiĚgۦe2[T =0T3.V] t1 Y=钵w؟߉P#=DCsetߝoC8h;Co:n^I%SħU[ԉU.qfG Œ$/{իp2ͪژ^0k?j-˶?qxVEd6^ :F6 [{lA3QԡxO*NM#=5P2Fu%L!itR 1#qB6=wZ^2o?TMO_mviZHM*f.VÃ֢]X[ô&1qt-`, ffyhIڮAl+xuWRv<=LyIZ7dh}R(J%oYR1k&|rS!J-MyG?-}%0 {;"|Q(Zjz8TbG~=U]?5|۝-N&oK1aDf 5?{EuBN1!zݱτ^5:=_(EFI;$ $W6׃-I/?&srpϨؗcZúC[gGfZT.Lk~^Eb6bWy~csB/K֟Â[ri(i/VOWg/7$oiF\ٹ49gkPcxQd';ɖcdՃ -N!F=@FqlM&&](H莯;Mu]|)S{ ,b|eΓ\o]<)K)+˽F'$L94c> }>gG\[ӏ.|{_׸k93Œc9OuuյY.o:;;Vpou=np՛\ɮ c~U [Ќu~Z^df{w]di#'hq^#ҧvtF`&Ӹ\ԿU^?m-]ڝ9ݷ} SRrnӈH? [W7n#w0ˇ^ܲ75MUjMݟDZD+KX r~*OMI(,rpvs଩oZWm*"9뼬"YŨgg<1D0=eE ?^w`AձqKB흽{O+~bFz Fmq4G,2mowRh}E&;ɂ9Dup@_pȀҌkN"ڈ9_@x>9ڃhş,7qbK77;7gK'O]Vbxr͹,e<LIkO|ë>g2 '%BL£)_Qu#YژlI/ph{oԄNMӇ2fXs?bTOv;c+lHhHTC`aѶ;@J?-ac֧锡ӖCP)RҏD=m͒3^X4O<l- F ;ۘc}?ۦ0 -Y / O0l9|MJ%:}uYP/_2 ¬L~M&5WS嶫_v'JPPSٰZmean'Yq-=q±_oj0] 8&eݚ@::=;fKyҤZ,Lچ_(4:~$G0m\:4dURhx/ s6<,#Of:-)hŃ;l hzjmؙbiČ:$zNߧoHkS,N<^rP) 4X*AK@sgSﳹLuA@dK _kкS*b?wz.u:+ؑ!9Y.BIOI֞6mԿ^t;5؇^`;,%>'>RMO:fG;bY\ggv<>OBhcś}SK(j*,uef/k~ I8̈́}L>^f,/43wRUtq_bbQ1X*ɜ~M?QpNٽWϳrLD',HSVtFkRQ#}Q6sbK`b1MUKg>H˥H{K3c8Zd8ۊkɱm g&3UݨaOom:fx>je/YJ O@C£ޑoK"pte's =3M0đ֡?u!vD?]0`gr,0KDnl3󮏟s8 d!zPiؖweKfƝF4԰r:jFN|>CǓe㞦 &)S{) (8.CkC:vqaQo5 zNGqiO(l>_b~]v9ޢܛg6+ЦI816+?Vpvnk,NS{"E.N6m$4TˆFԙElF:!3+#Pc4 jy/FrbU5'Vu/ui"N ~,p3b2?gq/ RHBҚ10-g#F4'6PE- Mq9 KU_`(z ݎZ5휩TcFQ_ _?PF|Uu=DE$5dp0sX`yo{/>O(n[MpSe'O&#P8;I#:FG YYf } a"<|txD!/Eol>ɶPuGIB㷅gI_ԿM(] fuhE+`kRX2\imb(O9,Oژ8Im᠕mb܎,WVEX%+_~)US1`$[ e}zKIgGnNըkV|fBsEQ UHM9F.K凳C=)A[NTw|;-?xճ=qS kr栓y%ӂ#zDo/Ё]'oeYYǁh#sK9Q yVQ.~aKf+]f~y|yy80~meK\g b8㰑Z]KAhZtaUKMvjk`kˡ&hG.B~EyyEA^_KCWs]ْ%K|9ß#[MY :l]qZށuy۩žP#+ʼnkgB{`>u~@phդԥn]ވ?Ijib9XߦѼp<>m~Ǝ-П|'uxxw0'V|}#BEcf$1-//Gyp՝9_6MĹ^)/:^4ɍexD5z~&gY(@^ۣ3;7g 8jp5&C&9aY3^^h}ӗsٝXXGG$>31 X 輻5S W : I!O5+!\b/{΃YlU`X 4H=`z DÃ"}ZcXd]EL7DМH,)ΕfmSsK3NXxY_Jgu؈ )ͱ;ING'}':nкJ)A#!E,5+K(g<4iur'{t6cjcL$Pi' b'(?a%$^J|:;-~||ڔ퍠;w'b9_NXrFlcH-;>pr@q< 'Y||ڧ˶e PrLo2)p ~Y"Na#+ќu0bk,m_U8qh|rlbe\N3ʹј)NIK^eݾtږf q)b8,P34xg 0R '9ܜكgbkqrKrg Y9aNAoqSǍ(ZT*ϔOO%&݀/'Q6.Ŝɨo#>`[+1FZO;m- dά`ͅ9-1BvbPf0'ui?N.ͭ/#5~^"p瘿lʋIGuwr_Ϭi׮΅q E1ݝR**CwrmE^/IPhT?'ۆt__.Ez83iLd2;>?"Yd>ye>i6Qs l<@IDATv]sgbAƴΖW _yP7GOqE/@ gVfY3"o!       YZ>_V'7e/Ou'nfo)k;JB$ORqO4z%1Y2 `2+ *U|f!dp.} L3 2HKz/O_z;,SW(Q I!H8      p1 r[/ſ ,u⎺b b9ѫi̪K׾v??`F2?ϸ1 3Ͳ0KMf3֝P`{ɇiIr 37KSU)o}Ga]03x`ޥ ?q13{0NW;4h͢7۳gO_fUԝ2ΨK{ (}zߖL7k<=|)V8e;֭5?x?7f&_\9~޿1:|ljJ;4o|(Po˱Aqj&5U+W7w0ږPN5(sHc'z.]S:+h0_&So5|k=%3s0skwɈWT勧t"y/WPvءZ:t娳/Ii:Sʜ{1^#>)>O׻].[.r~|,qq)      <\ CѬ/ \WP3q˩;E9!q1Mܹ%ړL? E͍ԩ*֜<[qejd^ٔ|Wn] bJˉҡc_{f8kb9|F)^O)S&|Qחo}}%.!>̈;R0+VZ}v0G{갤d<=pe=;^'B]Pz >rm_muHȜ*:{]>yIK{SyZ>/%W1-qqoMW&+GX&;yXR5~Aowz4{l;J^q*Z:wݧ9-]k×z^eef_R W+ /ol, 3Kt`{]g6\B!T{Unswv;{ïtg嘈 Y+=q±_oiZNĵuT$E5傁<-j+ s(1r2lO`?fcD;K7WS~p) d9?WpUW[/j'hX%VUMQ-iP.髛7uv\A%*d88X;'1I⪞Sj#<,N୒;T*KQVK@sgSﳹLuA$_23Q#2qenu^5?Kfۯ>=kM¤E as/bp^NpG"z)Z7[oSZc*K:m5?#):ȕT];ѳkfVfYiZ zG-M4¢d󤀕95b.x>je/Y 0k>w'-o8 QO ]aGs+Oܙf슔f)(IM# h2ahmx͍^mi1 ~ ;TMgn0KCp9֏`)cKnCǓe9 &)S{) (%.CW萮!tB6^awDM^Q\yK ӤLK)Q#KUp(n{c B74K>k-ú-*_zcd]8!/:mX#l,X=]Ba~</@5dҠGCsmpK91*m۫rdo뢸ʭH>fSQޯF</U ,eJ$΀zˆg`R!L<FXQfΐ~ oihA^nڵ۬مf'{C⣙=,I2*xrcCzߵ̒Ͻaf.HϊiĿ,9y}JG%F%|=1iiíUޞYl j{f?3I/I6p_o W~4g+\U{rεQңu\,t)C~       @E!wݟ{f/U_V4јףMx /qj)r7>}_wн ;s(uw ijz%Fw l* -110`?Ȍrq{wo,Ϗt뙊ϟ"%g3.żsmA/S({VR}ueko6ʜH۠ 3)\oZ's%Ӫ KEG>+mSL#Iڛ3//Ś|dwx{ źMLzJlqˣEiw{Tƹ?si~s+혴ⴍM6^`.ӂZ> ?ԡ~`O0ڴ]^n]ٞS'yyo Zj}`SnT貤Q~8Hf|]]U /&"meyma O O yE~#(dT2`CIfIf>8ȸwB#Y:*~]tp,rʄu!-q4e&e]iJ)f?&ifz(/.y ]=veK’h<>A_S^*]epҋh?Ai i'3d U,r{|_sjj " [$:Wk2<HriJ&:?PZoUβ Ec( xQ,g X 2A%LN0ʜrǬXV%'rᯟ60b*.W` 02Eq~XwaYB")\1}<(1r\jXqa,>J;D,a3v.\`@`@`@`@`@`aeLD"8 =kFuu5KxC@NE%bZ U>ԉ;V)?,[}x;8*`DOm Uw-:=X\Ŝ{,E5j4'HI3~:tHGaWҋʯ`K >,m:_Bw3}:=V}lڗgouyuwOSqW?1&W;O[>P$.?Xu )Mxс=%`Y`B*u'Eʝ!j/9ѴkH5KUvA"i6n8>K$/D{_W6'4h/7^|~dZq9Uk`xBΨiMC6MO ~H>ϋk>:DAPWWVݕW\?x:N1ZQLp%1:0zFڼ%!!d39:>k{[Iv50#{4~q&ذd>zMw!=wB?kOoGx՗ΟFMiYۘVs`p_{ʦ{w$Oիq޽gϔ+qr޽a/9zr] Px(Yz<{զ*䁂ɨ]|%12|/ فj5kKH/aM)VZ}v0Gx/>hP} >3~+>k1ƨ$cdN&Z]ѾSwo'/7= kK՝z|&&|EMW&+GX&;yXnKrStEjS,'?A{ 4I3B[!aѨ"w_z^{(bB >EFY薶I 8ImTMn\}-ml?c%8 E zUjmݩ.jg #SHGB4wnyrbg1?I~MP47a\pKxjOF^>Ofg /'a!وabs"g!ӱ*,ٻWq6Ūtr_@A~`sٖIkcۘd]W7or\A%*Td[#j]~uZq65gr&f!Iܽ}z5;ΨI{YfG9ИA<.xƫV[Y۸Dua:6X8ꗞW8S~Aد7GD?5  |lB-WIk13i.J\*W𔳵vy3ͪACJCv[%/=g;bn3,m!LA3./Fl?֦MH *Ρ} `ߐ7TFgʜ)O`>þT*K]54w6EA>{nZ$ DY,nu^5?rL02|;vdFN!{pR{',&Ym:, ],OڝJP4$>+%/ľ\ D?ciӶ1twIWu=EOa1\ZpaGqOx9`>Al!HFd~)>CI^2J ]\DX>&@0KLf|iku:JK;xBa#S _蚷ihvӆIvw'9gh%s$ N6m[9?G xm`i?&'9lD7ߏ,ڣsǯ0ˌdX^3-\8qݫtZK;ggl|o5'LGiq>Dk}%{V_=q_׬o_´!{1407*"rNCGy1:`\B}#eUۧۦ1Ψ0xzQsʱX4KPaUw2X+WVk#L:qJ[1cwY9qh%.jhYdt[ ns|I\̞S$ sK^}0፯و]^s$v\O~iB$ *$$ L8Q,gm_>o"!^XvEٿU$öV9kk9Sڛ2A~y1Í{xlW\̞.'N҈QQ0oXϛGvC!`XqPoZ:˭Tʍ{8խRиGG7J,aSq`1JH37_u7r4z]c}OYuHG%OG>+uX/'hP4!vpvx6 bߵ%ʤ"G| F+z/2R!-IZ%وT0B]vJ1wX0$c/&&}2$''ry3Ϯ=U_@Kј-8Q®&]{jԞѲp; vٯ>E$M@IigbM'P;ݶ뿛޻#g&N6M,G_ۗ&gOiS>jc$BіZ ' ~Dx$و/OxSF :4Xۈ5Y,Xh.ڎ46LVGy1'}'m:61ğ{e`UU2ןR5Fl!PfAܗGo${y{JQT +:PwO4NQ~Ǝ-x=Akj[o~/FP7HTVpD<avyQ˒FrHۓr rX@"#32tg{bϧ2#rɼiF7W{ֳ4/݋(ωL/ B_Di?ptu1{D-%1NlY~=n^ND}*cܯ31qHZK-.G#9gcRZ>r 鑣 _Q^^Qo%cW$,nR5/AE!d\GrY fYFy:Hlc9<|VݻTS ГbFxH,mc`[^^"MqnWʋƿ}r#j~ex,>QM߯IYJ; ;&{f$,i+~c޾msS>˹NOR{7#5/Ϝ3|wZaxTuIKHV'h l>&Q8` 8,ej$u2ޘ& Ecuj0 KaaNy>]1,g(gԁ+N"0k#o_Yp RZcupuGݾįƘb>cf'}':nкȰ\L,A#!E\>겑KV'w-7{k)Kh99mZ8G wmEqȴ'84F8u9,gG_΍u ]~||ڔ퍠;w'b9_NXrFlc ^ֱugN>Ob<Š4۾,>a4KթX8ld%3|Xlŕ'Q11/6>B<2ձ͞p;ȋAe_@Gs˴Q27D,x޴:(A\Ƽ%Z1$E~ :b13Cai&5~1="1v)漅ugNF}k}?Z$$07Zֲ}¾ikIp$tf]Sn.,vṕmVg gYaS4=. /e}K=iLwlS3]MsW vٙ]v;қzlm$HQtLw缔ƿ^H%(*q'׆QZz.C_A/IPhT?'ۆtӗ.EzWiLd:؃[;bEWIof8m_>˜Un6q^~LKfO Q`@`@`@`@`@`@`@`@`3В+5A`@`@`@`@`@`@`@`@`@`A3#㧸Ģl*D3@J,D-} ϿB% 3QTˣYoj9BnS߉r3ԺR+w^[slf%L>,lE{w@^ϼ7_NnI7|?ަ0!ßdS1R|E/8u3PU{nA-ڵNQbjէZ6G( KV,\^ٮ9yj dLJ'mnob-zēTd\r6eC &@0(I}@DJ'+c4 Lg /f\4ʏFHß7^ne{޽{G+7Ey<έcve\" k ` Tt1~%.XBnx'?ffƻ*fћWD1}ȧ>GTe7\PvaMɇ`*Q9cݙƼ|8/3f!0Nrdc[hm~XWf& 9X4ʦI{ (~zߖL7k<=|i2twm<WDbggMB`E/Tp?_m`A'*Dмt|?Ƞ죒K.o*-$jQ|Hc'z.:t"mWMa[n'*/Ql 5ac'#^ HR/:nجC׵ B/-ܸ}K!rnK\DblL~5֬YS6qsKS \X$~N@_ںŔO7V]6{З m~,Z_SibS'J}\€j.  (JOOS_l|yEf4s]ANwH;'$= ;]S{277fP/>[s@nŕr$Qǒ{gS];wu7vQ;B>~]3/Ј0%q #4UR&Lg죄חo}r?W4}g.u 4mp7nZ fŪ]֮OFGlںG}KZD?Z/W~v~ ~v7!#sO1.U;8upv}ηRյ>}|ɾ Q;]E>..b`wMdedG?K-]{>}wS~ 1muPY(>W@~9^T{ ܙ Ϩ>^ߥb%ra)7BܗqIIھm%00#Zmean7 cGHoTRU,͝Q$qU) pC5ƙ PhtH%.+fՃܝ+Y9&"% rU7Δ__8!T9^c(FQW8=:Irڬ/'sʆ/;S){`$hٻDdfVIiW ٹzIlE`GbG{]sUkSԍƌ0L%:}u+~3dB Ͷ)jGxnP?QVKao* @ Jw QVK@sgSﳹLuA3/T#2qenu^5?B@熆D>#Uew5z*"i{i+ߛ~*d>=n4O='b}9yqѰ\LNp}U/Y.|ܟ|Ԉ^¬Ow<:xU|c`1L%B,}.vDϢL+`E @{G-M4bq"ڡLɰ^mi1 ~ ;TMg n0K-9~<_6>an2@<$x@% xmݩ5 zNGsiA/Q׈~urM:Mb*SU?҅uq[UzNOR7'z^ UГhhP/Ibˍ%뚽nFO0/ / 'm> ܺ(r+(,8xK~wy?d|={fͥh}f /N:ԅ~C^}߻?̄_U#?h£1GOqPиGGB^/{΃uGV0u0b|LA~MRO`bY?^6|(S&o<|2{S>wn,*/P K&)U/+Zcba~2%3/>?5ftg*F?X/[.vDε L)[=K=m(+s "m.xprqk%d[L2L̪+/MI[N)6N3Y$}joϰоk%es3'r71lI |U4ކ5/g鎟~>?ɪXiR LeZ^ \xM%MqbIѰ˴}G`U즗ϗN!      < p yE~#(dT-ZE!0xdkr5z<_[gOai訠Aȯ(/780F.Kc_WWUGi+˫n`xZTU?dYf٠XgNhA>U\/N>5X wCZhʂaM˺ҔSLxP7]FiÀ~(*faT~=n^NvdiϽ2*։SbH5VZK- L͵>(PZ֡YK7/F~9JjK$KCWs]ْ%oҩ5۟|y篪\|+:lWIkl4C“=W"Orb)މ7oРQ~FR7M|`7xv5 xGLX]Af 'N4[^ao( yrˤ2HrIr"Tֳ0Yβy( xQ,g X@0Y 2YUg9|tD洕|G8O->fළW%'rᯟ6m^l^-f.|ZaV߉kDe5{c3>Xa&rLgI*]NEvDc/١P"0 0 0 0 0 01PVV&F"ϥg-6s>%翺J.em"cb UEe6%66[zL ;kV;DTby~=X1:8}еY?.l͛6Vۿٗrx_B9 M9m|4& yPMn 8] [7qSpS- EQ;6ڇbm3KmJ`@`@`@`@`<,[`@`@`@`@`@`@`@`@`a%|%E"0 0 0 0 0 0 0 0 0 0~   ږx hWډ ER\.^x? ۖ:bT\ہ Oee/Ou'nf]}D;83/sŁ'[oͨ7$3jǓγ'El? жKwO"մ'YUK0aRO߼]u[ҋ ;WJ'}}^J[[۾7jP&m.G>Gu}-upDXS/(뫪kڞ2 "eܺ;_7nΊ#7YUAin?-iXm;|pҔzVy}Ɠ=i G/+P[e"bZ U>ԉ;V)?,[}x;8*#k3fHliֿvB?azOfvXp1z`rf3&홙9Ϡ-g"Y2,OcsN>||=~T9ca Q󝎪GI > ԦQ|XAV;~2;_dS^w}H敫}gfS6v]`\EYYFۮflK('WqҏtDڮvw~qKX!YR/f vMeYf{;ldīISG6I/hk+4,/N럐6mw__LJ߷9`$V$΁ga|B%8݄#w5͌ń'7H7/dW%+%ty^>{x{!jG_ -B̖0ot0;զO;6nt_}'W T9>}$Q2}P3-$Bk󖄼7cLSL[I./ffx9|ٛo7 !,D|0HEOkKXR6H?܇gf2'Hb/ ٝ?l[Gp:<ְVh+Viuã9e*r\ٴu~rU4ۻ{7U߻׽?%GSfcޛ3SU~9y 9!qx~ ~ɨ$Fv-'^㡃l(C{=xe7-N1.k@IDATBfdZ fŪ]֮HqNGaEi꫗!{7Y_ع~gSywmb{-ü1*S?ؑZ]ѾSwo'/|{{I}oz*/U]ז>vt[-qqױh>\_Si"<_U:tk ǣbLVLv$~T02[ϗLs#զX3N87www˷u2gTܰdpX$X4jGݗ=c+ P OQV)m!3{lA5> f~JpM{Ujmݩ.v?{!8ocL.^h\ugJqIH8iXH>XQԔF-oٟþ_\,Ӓ,F>Z'Y(0.s%[OGq[~ߗlĠ9gm ÐXr?ݫ8bO: / Y41mÉX䟎vulKt4Y(i͛e++~3dBY LT3{kD˯Nk?`.Ng//h]&!୒B{IОauإ'n" 6іp>;cᘏ?֦MH $U,͝Q$qU) pC5mϤmBC*q\GL: l77ÆJaeRxgԤ>9l3Szh]4gixy<[_W,m\:\ALX'|~\9UCnKcGHoTg '?LvYfG99ttzw1%%םke/4 Rkw$jս0:Œ_239,q2#/b9\?`U,˝K{/LَIXmx=5"h珮/پH}&wbjyYm,F藌ok0*rqqہ P$ }8 Y^hg~7ɫr:ӲbgTp9?:{ïtY9&"D ?I~F]VݩS Y&IuF YF̉/ż>7Uc+IfpAb_.ME[9Bh+ 9>ԥ{L$Z5)zz C3B##ޑoK"pt̻>~FH0XtuCq[[XX?]zW]z`iͶTwzFoᄤQ3pҁ}N];ѳ4a6B?/4en2@<$:yotB6^,F\r\O'|zlLM^Q\y /84ϣkޮ1醣]8m'-/\QGf 89Q,L| y8MRbX@6p=6ʱu=pw[ayXd1qڏg**-M#+˻F+L;1rkay͈H: `;Eq[D9|@ࡣ_0.vy^o&|=1iiíUގg,m>_2{Pel6@3"ٜ{(xqI툑507^T""F[a2G6:΁v I8Mzf\` |}ru #N{ `T~\|ƮC]Ҕ{0$9pRۖ)j|%QOj_Giď >O~iB$ *$$ L8Q,gm_>o"!^XvEٿUֿ2-ɂL6 FMszcTPۚWmKZaq moL ko6ʜ y1Í{xlW\̞.yےB}9H0~@qL xYYtR2 XBф YG$<&Ɗ^lytTڑiK8u7Xaxڸw»,S(b;CY!w͈s̏Y~+/ݾ-e};9I~11_36ȍ)˓MKxU/_q'pB2$''ry3Ϯ=K8 n<nG.=5bjhY蝄g;yZt9-"dՏaΰ"dRYyppX`o% 'ÎCM|,T`(#I1*OHM/=GO0g$0C3.Z\hŒiK3lduCyξhwzݟl(ο}LgW1\Mۑ=dx5ͯ?j*YC~K;̂/SzI6I?өq5/ѦqB%GJ}>NV6y%XD,EG /r>(MWۘ>A'KG8Lm'XQNf?.ja_\Ќ(@K ?`.CMd\4K/$ w̝3 Pػ׏̽;;{YX[w'+b~ӏdW:'jƒ~p-sߕ<\PK gNr2CZ=|Iʰڢh,GON!X ss k\( E|ˆGNn&ѭS7-A?wk6_mIѦMG.nXxC=>w'5ؗQ\\Awb $"3gʼnz8ߙPn:dm652n!Ӳem %j4!uϱ:%/ !<8Eywm"W}A2Z_YAs N\zPZDTRsesV,5X}PhBu5 د:OTS`kR}v}odA}f_־&|8|BBF5Vk3AU_T=m\3ٝPP%/*+U~uG*'m̼{鶭I[?:UKQ B[Hqn~H 2BK2:'k/PQp«Reͷ;Iǜ8i u 렡{&.R a 6tYzK$u-jaDP 8f,(GPmd9YŐ cwL,R-H_+'~IH(|Y~])O~l|ڔ}CIz1=tq|qܒ4bcR3 'o^giZ~X6K A}%?AhWWF͜e i͒ZBN-`#=, :c2c15/jN"]kjI""L8k ~ik?yזqݾ: oI UYe5_{JxaV!O NC!'EFMNkzex ]mmiA醶/QPD?+t59]; !W)z ۝/rS Cڔ!%mU7bEUfаV zܬaL%rۏu@=bCx>Z Mk>)8 pw888888888XZWRjP3`ߎbgRjzر9]s-&9CQӅ4.}suljՕVKqan /rţ==Rɪ4UF.HEu:y{w?v=J/d,I;v0evFc}G?n.111111@f`0aݤe2%%kYкίύ0|XObW5g::hw:hx}FLKٳ,<=]88nc5"3Dwj~޻O9wolu6 TM@|׺r/hcT65oؑ\(qir*u_L(Ge˵m^7Fs#&N,>)Z?X:~|w~_ehصr+^+ rTԽ~6eo3K/SEְzrF`1F>GD1~E>^vmͺuݺtlkHD([u}ƕ% ŷnYKx?VOeRb|׮]݉)rEev)M]ꆬY3e LFccccccc(, jsr;wsTōFcƒO$$l=WU2i|V;Bn^u!H3^Ӕ75#R*=LX㸙wVlWẋ}{unnt9w`N\Q}͒`~Tsm?JފjXOaZR^gcÄx 4k7>rc(n5Ώ/uyG $*::_:{]E~9zUG<7[[5zd̤+3 '}/M=k q\osŠR9ftRyAvG~&tžڮIII~aogvV4/r~F~9888888ce ~ڗN) ?E H>l΍G3S:lll,?Z%TpeR~謯 ;R/? %9^ z^嵀%܃ ,{U!5w|IZP |)fgzv_h5?ʝs p p p p p p K_KJG;Ryzk~%oj1+nZox;PhG&.yP˙?_L?Z'U)L%QN&聵Fa(9 Lr˚jk4_U=|Df'ȫCp:uJ~m:+lTl^ؘ=Aeﯟ|[ǣeH^-E[}mݩ5 \N%upRQB 2-܆F :>l˳P8Ӭf@z)0f&°/36 T&~+4VFG & rGљk!݃FD㙞Sl2"W,.>|'،.(e=#$TCC0]]dz!o> sehQ~z0[%lw[:!yA+U;ڙQ~ b -/ޠ/}|y~"S$?S `‚-|5Nz%ہ3O(G-GR_hX/.8888888ږ0LH⻢[=qͻQ?flTa~^]gwzqcѭ۶z47skk^y~!,Ml$2"Zvv{(`?D}Ǐt_,  K-L,*O;V,ztA,O%/6kZH(5*\nȗ(~C?_9H?% }z3O. Q,+g%rp:R~W KAot|'rZs^ja2㩯3sdvb|uWR?\z5GtÜ0Ch/]qmW,05('Z&Igd1jS0b .Pg`cccccccOax_գ-*@soF8r"gH;U#YeYZF9P[{{)4gw  |(@GkU;4ef yIr9?*ԯJZ keuak1%L>t~ƪܺ8Y]uFv́U3V ~HVYC~~$k p :6eˋW艳k`Zj>s:HOWKJu-AhZ 'I,C^~GdwVΩ[@glB>Gs>UAL߀: 2*s ~-A[xCNoDh_?C;  ov뫱`ukɆxWO^-ER% vY AZ;;+sڪn]˚v5II!DsRRS` 02Iq|Xfu "E!Rq1lWАhw{؏N :⭩+cDÛXX$_gysw88888881PVV&ruu5i|`jj acj1¬ޚDޖs/{^X "D)ŢCcݰ'j2+׆`-5|zh7~n`r@888888 Z B#x^.v1 |<1u[$™bHL}>ok1mX8Q4̔&Go̹ ;0Ckė"[ŧEsCa2`: ~lk|Ʃ~&9!n a{,@'𗦮 ĢS}-H)ڰLqL6f@oO胂h75/qvQ"X!,k|g'VEovm*[kp(+3A f{% m^L %ꆘn+,1Mm.1Bk 6}!\TlV-Q8=)|`'w=tǖpceY.8QK0nRgܽu[ӊ{ &5v/>U|4 YxXR;am sSKdKLKu*ټk9Zb03JrNaz#/gmo]!m\@brTcdz/&`!)c;qrƳ{[;Qc z# ©;`oMٖƁ$aWO@=layl ذ734 7p2D5㖉iĖFkZLJ&z3&ΰO {*{"dF}`teIѿGæIpD̷:)>)W?>9ۥMذ l_Fa}~f&\_99&?'Ct=dӽ%vycGwwsg b}޼j,o U!&mж%3}صr+/AGS۴;_w}Aؕv?g@}~ .>"ZhY83f?̛е;UO6.`+c:YIw*[~$Q2}?fzGzkޒfL 6Xt=V薽N=8c)!?= )LKKܺpwf~}`= [ϥ>,Ѷ%+b8Zsq&T9uhZr>.{Ι׫J}ݍ`,K<7[[u4;7(IyU%!zan]%IW"g,O_4Ff`%M:ߩCm=P:{mD 4'.uסnM8<,_8arh v 1,OV̟OlPOZ . =Ia4b&Z?-++v>HϠ{ynm\4sR;~C*8Xjfo mպLR^{ʦ򫊫~720sTܘnAKe7i1K$!D]|=l ;i)i5s%~T$]J\pc^Jfjzc^LƖDmJD^m))3$קc =p"Mt& ZfT#MCЁx43 |6AOu@C7je9MKw߁K_uHS* 7~8dHLQ~|I+ٕGM.BIO |ļݐqI6<HT$hd}ޒB hZ}4A>N3œzjɫhw+0 nI O= vq2r9 KJQk 4OgW3r:a;iLwJJS!54(zNHtrGN:j+m:+{Ua6Tt|6ll݃$_?[ʑmmyX4o,k?xac|VxJ!;:fj2Jfd|6_Rfhc0/'ܽG.|,U&4JQlb, Ngb!?LS#!d'kc$v^dd*N* ,>o LmL#0 k^.+=zvr7痛t9QsMe‰ullznojN:jli~,>R5%['ɯj׭|: [(F,p_at0fZ?ou~\Zlh xR´pꟶ'S=o Lw^bn;lFud׿l V̱qv0pVp-9={N|y9YŌhHۮc~\uO-UԂ|4iCk{Ј軙7V( 1ݟ92V岝0r m'ݶ(rg5* d>oD,C`k8 _ڱpfNci`%UW_ r*͚hZ6gu8 MrD˥иW2)"" HY(YPn!! ٥A_H\|!!Xlɍk#:XTg8kOBy ig%ɠ.0bwTYe|g-i)N-S#8Y}ЈaႈiVGuy =`6 n1T^:&"F S㫮w{z7m̞I϶dSZR(ރ:Ɠ9O|MHOχ( " 4.zۡp/SAN㢣mLZ/ S)t'DݕͶNVt -F5č^ݖ'fa;S,&_gʛͯH臗N| xϼYV J.RqIi/**EaxqhQ.U%7>ALxhBxAza5qQ}^L]HsU^) bg'Tn^,C$Z1#,Fy$TT*1~f):ZnI~F (X ?L |0TRtPc,,S<\VH Qbur/Eu|1m!iKu7OI#N""Ubd#H~Wxn}>#f\C&`i%/f؆j)/uʶs}F8بÄBѓ nvуy7VX-ģi~;"=y}rI13>FSG9Rzv>M;E+bF-> +?^ce\SǙ0Գ$7"c+ /|X&)2}O 5{Lm?8[lHz.NVįuj{OԜ-^'Z+)xϜNd4{aE5?h1X'>ByֺP ۅ#'H*LUO[9nn[rG~l1C_—ےrueM\ܰ 2x{x}Nj/'#FQHDgΊcaq3Ct:v? l8kd Be5*)J6%Ii^CLCcuJ^:BpypN eE苯"<efSb rws )5#mYy9ʃIwl4%Xjzױфj_u Vפ J=?ǭ}M3߅p$,.+ ~\kׄg@mzB۸.g;?I=yK_TVdUO6ۘym[3~t">L,/TkQ&@CeT%Yd udSO6%1^ԡ$|ḅW)ovLɏ95p&-lAC Lh].,_.!?!@l80ŗ&I<[ԋ8p 'YP38N%rf?!Y8[Nb><)|ei6خ@6Ɇ'Y|DEp& ԗ8+-} uޒѣ >zkz.Bs |CNaD709A(+(5-  m_⣠~VjZsvv,AB{(JS>A;_ P)EkC@K8k 'n:'6 a=Yv_J\!*zŎ|2}Rp5 9p p p p p p p p p < ^՞1111111111fx>;Τ bI'xLH˟0܍ , H'DdraF~.iMklz%^2iˊbRQ:QYw!n̼;s-3^6Wƫ|3B/@{`JHK|XtXX$Z-i_~rnBCwjʾsWa3{=dH5}>qYW[e>=e_k>[;9{n$q:v(jpf}"cTњ/9y<!>9ts[j:MIOyu;y9\yءj[ %/>۴9>ܰr _}E(u;D^vmͺuݺtlkHHg~xg_n38́Ĉj۳ 7Jly6j_kC?1s2F9?ߟx)9-7α};GUh4?&.{Ι׫J}ݍ<:жp( v#g&e_\x<~єnJ_'=rJ??fm Ј>BFx<{p/uhQ(h#޽ 0<'|bz_ kI8OktcccccccTX} c1(rdF4q˦VVYӴ$qǯgˆv(pjt!H|„#0fI%&K i7jc/uC!6H dw?#^,+h^n˻pkzPĥ9x~LK}QMz|1[r$)%z=vG$0rh7љTkkeR7A>s̔N2[[=ˏV 4\_0b0:1}7CN4~RtNrd؁c' Pybk'E@IDAT2tB45N!QΣÄ>o_ W+B -r2r$F֖EAOƢ6TFL.:8)(A ?HoDkIxS,QB!L?LUla OmeTp` {ٻ*$¤{Ј軙XUqFIQܮ߳+ G{NNNꌕ'~hKo0#n!Pƅ7>Fa>Ⱦzs |;wA1a|0ucԍWi*b6۴GVxr p p p p p p  oz=E|ˆGN0pSHVYV֢Q=(]/)סB~q# Wanna"ٝ4sָ%w1йmХg6γ:l<%~zxB{z@wTE ZOۗ2àP_6iٞ ?iuY)MMl~F~9888888 p1`78"'ڵ:σa+(#?aPzO|xjMXpVuwş$_ִNONOB>05&Ɯ"(̧aRF`nAdкH5D0.B~0_ vgʉg'̬FR&GB:IL,bipg2PVV&ruu5i|`jj\acj1Y¬ޚDޖs/{^X ;"D)ŢCcݰ'j2+׆`-5|zh7~n`r@888888 Z B#x^.v9e)$. <1 |<1u[񍣴N]n{R(ھ}h{Xc4W*vI=) ;ᘩ Z0c3h&Y͌h)Kt{z~ϟs}b3Ƕu‘Sfƿ7PPNhLѪh_K6pPx!;OxV9xi30KӢ؃~nM0&6Nݶ!8S}-4.P` ˴Ѽ-` *I{,DD~ОJ{},ZZO U9}Apm* h(mW[  ltpaӥv-䧦O,tR5ԄWhتT'UגT[tb`z"Kٸtvd:-seP%,ٶd䴚Cdox$vznCюcK8ޱ߲,LaBEm c'wl. )MċI U_잻nkZrwis] &5v/RjN})fĠ.ͲByh}C[:8ϴDQ-Ctp,LSp룽ވ|pmY{c˴Ÿ OObP{,$4el>U.?xsok?jzֵ d+779g n; nop~;V/Ewf)|WlQF6s.ȀμNXTP/ITx|!Cb$?^_5˻X%v,Q? j|ssҢo*Qw/0OMd =tx^xm'kM x| `DwZ&/RI-a9bW-RSsSÆs߸U(W(_|HYI:nm=T|pkEHr𲚼w{\xD3~ia9f$Lbc\sy%z|-Ym1׆xٵTcx8}AͧiR;]2K048ٷKZs̖`'M@HW |~.xB u7ȩBu^/&n=XCΏٗoqxjVH/ _%Xq)ӬLsMϳb!1bC>:D3ٹѾ,燛onsd;{cT8tת~uL]Pc2fG-kD[gv^G̗YS? @ݕ9y0.$?AZLoqVi#9on ^8EMtqy˕mfKp{>kk 2gj׀erL-~+|h4Urz_Bd\<;ǎU<D \W峵gTCB;ڿiOB¹O 3eRC?,ا0-)|V8;I’g\6gnDoAm)r 4k7Iz.-aH͋D ymVN |7D'IwVvS&Bh>&ܐ$tHϫ*  Ì 6JЏ9 |IA6G*CNП@pK-&A[};QPsz9ӻ"M=FiiP!1?Jh*߳!leZ 2MEl(Zi_ձ!՗j?I'!?mI'ZCQB~|M"rѪ}\3Wzxc?v_"|Q" Y~%rrES536_Ҥ:ǓLF*:!{GG[G˽?sr;vw{yd$X,Cq!:W?8IeX_92igS=h-yvGH BqsVضGRu~Ar}ĽХ:5p;+7WTGb9{JB tP+|}/­͛πb_*zo(Bg2k3Pma5mZ5[nʯʔR9 ?Kޞ`D"ۗN?E d% =%Ww/_U\=۽Ǣ4zA&gߺ߶$J(Vem3 \xE-RҜx%*o`Lo`_~_ fC`+,z,t` a,SA.)%zQP_>3 S|R\9mm1E*sg]iD3ACDC] iI;p9hWPݫھQ Dm8H= .>IN41+׃B{яB};5n3 lZu20d?MvGӚ9uggR~*]Z~\  7W94D L* F2|G҇‡͹hfJw_'-?U~j | ϔ#_0b0:1}7CʗsD6_Ҋ9zx nvQE+𔄓+|팏K22= .#뮄X?z ,CA}$j "rF(t/LLyv,>OB(cEMy3Ƀgܕw*^(`2t2|oKnk8%@U:cũH9VznUa ua{EʂOlvjg]%v̉ZN-[IXSz6nz:OM+*[E2'zQG囔#5UiLe O=\}S=8]gUo6Z2#D+D,S'%3 3SS"` )S͆wCvCnnpB;ނ_V?˃_ɛ6gp ]_6}zǔ!C"Fbv݌kJܹQ7Ƚ3vF0h +F5+׺9ueLټ ^UX~Ac2_ӨT2['i`%:|䑻ӁkN#IKF+.r*P hy'd3Kz?oTIBE!E_c.k6I?s2GՃ`aI#0 k^.+=zvr7痛AͭJ5-Z 'ֽJ.uFꉬ8騱A~d\ gKՔVlu:#m0e8m u>F|BόԭX#׌0ZfZ̭7zhOud׿lzꋷqCr zllk"{o൶<ɶN9ƛ*7qYåMszR5HO=Zw#mxRTcA1j.'ޑ+Ic*~>&z߫3gÂHA:u7ɫn֜/t?x?Fm~#3' 1Z0gTnCaZp6p"cP>)cUڜ/TůKLo`dVV5:FsCѐط] @zJJqfL3Z3=,>dD/_X\| )ukL|Fy y)[s⭯y)x}n[&݋hz3QO ԇUX#T bǂ9.pjL4',&>٥A_H\|!!Xl|5iM;S6b9XS Ħ{MB?w/\Paj|UuaO/ٳ"?+P<7>\+R{wdҋn4"ge~]DFb]`<G}I p7`<$'QtsS{&}PXoAhMgEWНO@w#-,>O h+Q`_w<$ś3*1Lex):O{xΚ}Fn3Ep&G-4]{婞~?N exkҏ?q0[ ɤTa3Kʃ1!|B:8(ftg\%x2Lʴ*3% Q`k{OUur/Eu -,ed[HR SeIBJwCY"Y,|lD mq]<^(cT3]_uFv́U3V ȗNH+Cڬ!g{ߤp|̌Q΅̨$8ڝe7=ޕ F_!G%a)AU MLyCv@戠Gx{NjL *,vaȉ~#'RZc?όL>ARbYN:v)+gp ecJ1t8~ȫ07E;f;hd;Fgsˋvū(b9{C=Kr3qYӁ3 t8~F#ʴP¥J7B١3V}Ɋ#춥9c(Z~}2CZ=|IJE5?!/ V?n场5n} ^ }_&oKM6m:rqÂBaY#S*l5*)J6%I'Ha41 `/XQ)zP苑ZuDgڄgkb VzPZ_mYy9\͏Iw* ?esV,5Xc: 54`?X,>Im}odѸ_־&X, 5,?=3r)>S͊ -jWj8ۄ-4% Hu|gG(kך<V9&ZL' d =xL0VRutRjl'$,li4u(Vy=0>@*$RmZ'Zku4` V?9}.a,&z#NgO跴pf;@0wzÄ\:k/PQp«RelDZ'w/Lʋɹh"&AC Lh]d0:OB~D_"EK$u-jaDP, l'0:0fq*%0X4L=3'lA6-cF{YӢk6d~٦Lm '>:'6 xr6\M1111111110ВB\9888888888,cDN3  -y;ŎZb!\3vi`r+Z 'd8,ŗ,Ud `"V;ǰ-N\彑~~=+< 嶟.k#H3V`_faM1#uiʳ,mc;H.*o([Ϟ>;n4%^W\u-`ISv^g+:v %$ 3lylآbğӔq;=9FиFږG rzo+&p=LeS_bzun}F{_{!/g)ר֕ҫq:~LFk&^e%re~ A4=Uu[/C@&u~=tBwFN[vxlCſB Pjzq/wf{M=h&K/xvиomz a#|&O=pC 3 6wccccaAuұ_NbIѿG;Ů9#k0IR X! TT0Af`ܙ;g 's=<s}ge>18opo] tTkIGa,ĉ(Svov\-Iw_cAHϖ`iHH{zav|MpƜ' 7ұ=ʼnO %)L Q&z߿[{ЎK?dX[0젺bƇ2Kl\Ko]~pT% B9  I}C,-!aOvԤC[v1X:Ֆ=2;Nr*h1LZ]!n+R˵ucjBUW54iJʖَSO+J)7o\y-m{\ۘU%?Ӓ4i Y58~BGwޥ4vwX]cxX|tQ??}(bXܺ/?|dvŭё (o(-a~*ݓ[U27_meU}`w;GU<7[[uY0aKzރBdUp8ԇ68dRtD$>kվ -G(lI:zG-sdGORyQ:@(ʡZ oH&ֳF3G$i/U5p֔7]<~oGO5KV `k<\'<, F 'x۽ۣ!!ޅI'{^ $,hQ$P#)920MP<˾D/ ^]ꀻݩURLCyw>܀1C>v9߾[m9ywG06FR~NڽFG'o{DЅf4OLKu˞Tǜtj#b}8ꎗ;ٖHmaW9xqkw Vh'KG%5O\tBJQ9iSQUJ"W[+ksż^.O?Ҵ#DzҲ޳V^I}wi) Bglu 5!Me3-^cccc1ƟXUyZjPcv8#|FMEOMl7;rf3 .Tް) N8k@඘[8=&Y=on<()9y,O5nPruW}PiC} Q'~B42hLĉkFRkJ݇/ 0GѲ 5qʃIMHaj25M6C}F^CBPZv1#XGJEwPyi4ZzȐeO[Rl[)-lK6C[smީMJBA%upO _YKmBkyx ۝0i]ֹO?ǣ '7'ܪr @#}=~w8a=" T`^Ar 2+6!hя.nN "mA{ٙ^cccc1`Q:+yػ+T"u]Uţ9uj8I˳DWկUU!@& 4UheDnyy\!45֞|{zit⧲q2)LΩ\VӃ@4"-g`xNf \E ΟN:ҩEq)Q xf42yi+Nxw\aVo@v}FHC5U>>Ȝo(vW|"3fJ֜-SkB۪0l0{TmJ}[KDc#?w檸c#~.޵neYH9u~>ұ↗_'|M&1zHՋh|Vnjc!G%Aֻ|: &6ݿVo:_[?5CρsJO{iKφH4u-TxAKyڿLX|"|y㗃dџ0^-oF~O=J!AppG1K OMzrL&*qy5y =]ɚ!ͧD>}ΉK7oՠodI=_ƿ=ШgJGfD#B6>(n݊M'* @S"6nmp/aNS"<*4'K{*tXÈXz3(h(241ͻ^]U|֍R'+v7$94-gJN|#[ڈ`+/T;^dq)Dæ<ulRxyrD0]qq_bf:#&D'52~m[Szskk^yX,ULJ6ʧϧ.%/"º?8igh?[{ɮy?Mq0cy&PrbawZp|ɏP^3oz$pM 񣭲ʕF|HuB5C:K]1ag}Ss]'7A~!P>%-9jO^w_Mc35?fE;e6n'.o9 ~r\/9{xp=V9?LCjE":VyֹӃPU̓4dH_K `{QS2gapb>N Kkσ0z^4݌ZkFUΧ{z"OZrVutRGQxtĹ_PDBVn|/׾N5:bAVb -_m{' uAs,04dN{| 4 ܑAOfVfz?Qh`^N7xHs8ũ#^k7AP |\,E~SQI;}{)db*Cўڧ4a|: rqz ]~U06﷟eC@O9%H:j>MJLcuEnx셭 A ξpkO̪lLR~jqf&G]6A%r޳3u$A:V;^pH+ó uK@xz4ӁZ"sCnsBxcZ磍2B;::KDa2-ct* Bh-NmJK?AWP 6jhMEU0@~®^ˌkv;Ӗ;\ "GgB_]]M eÙ7K)SvN]mx], n_vrkΜM,]iʌk$^c>?}gO ͌R`@2RBM*(ͥ74MxaQ! NQY&^_ R91M>6Xg]()YRRa6>(wax۰A۾?;@"R$ _~jvȯmeoLRJ+$%hq0LWσ=l_C}ݞu8);΄f:̝+\TT %k$H|ذ#65'Qisomgk3w&^BAA$:+ mmjvSKm> 3P"}:ζ d6z`8;^X +8yNy% m^j %ꇘ~+,1Ϳm}/1Jۊ"آNBbQhC;޵rg|>ʸRӳ '/ 5W]ÔsI.RI s&6Mswfſ+V;4Ӷ5vXy"KVjf DéV;EJwٰtFv Hk=j> 礅`?H:Nǧbcv&^B3'w^;.Vtogm]gT{9c_AMQꆙXC[ fH{a@{~?A;*x1a1ogFindڊ[fg+$5jq,얋w_P+_*$Mmkkk#9jS QT”_r9b#eâa'5sqqpFN(v<EdX[W|UɏXiͲ3@o !Nts.*WgFx͔3<}sa-bˇqP@ QYa&b=pϳv.%3!-?Nԟ0CMհĠeXtW|.`ly7`H3ꊜ /Z C욚ph]ף?[1%'6f;c5EA׳IR7VVْp4^u˸"Ċ'}+z_t~SeW*L\'di,BDtEBޜyReE֘`//^|6xlg@IDATT/*(Y=HSYqӬLi}NAu;xC͵5T@JyV,xf|uٹѾ4[o쩽{*ujLe'LEcϏgd,6ȏXϘU57_-UY>:Al׬azW@{aM-3\Ivf:bՃQ`IqC- ЖѧK9 $<ఄSm9IadjםG>m,"䭝{Hތ Wg^G\.)o,Zyߎ8k\x;ؼ .LMF8+D@,ֽ*7_<]qktB(C((2{qXʘ~bW ˱`Ⱦ^٧n:D,ɷ[`_QBjGS~z 4g!lTQ-KٶBw%=ңJ9⏁Or`ycd&<, =]Y|q+.?j ܐJtj#b}8ꎗ;)?'`QU<\ynDKB~*U%#_xmNj˯]+<kP$e1fKh>FzFt\|.' dh|_윮=kվ + hQ'O#ݗ(rZBTI4`4>q;2̻t " [3em$;gdi g:R)޷!e?9^2xQd*; '- + [gܣ}Ź 'zFfѹ_cd= @b&χ56HJN. $?0egm+ IG4 =em>; iQLѣ+ FeRE 32X$_2Хkу/KGqxnݐ%sR;*HO)7{Cjf%v\^RQU/@GɳOCj5I~7?sa#?_ X_;uݺB  xX2-܏\ "HKF0^=T9M$[~԰Wۿsv9i/E2ؔ=)e)3&4b>~V)GJOB֨E.S}${3t:%q"2Zvpq/oc} y蛻pںlfVadƮQn *S/?t_6[҉~cYVisp`n*6$ #'pYrrU` q5B]!`ARXn_Ò^R8APT=itzfEv} m~tb$,:V[`N{'ۊ(_+g6|:|Tv~/+WMTDP<[[Gs oh+NweRϸAU/|XllQbmtc35D~M|xoչr|*'M{zu ZضHN td&5Yfid'X:DaϾ:E[Pn;Iz>e_C$Pg*4>oIvf!Nhs8PAI*Wm\\YTty  B׎㟎v}/g(ak-,zvU;:d&M˹;y {+~9gweJfzP'ڦZ! R~E0^snmԽ:s1tr~Af ~o[[9?*z鏧;+d:Du\_|vWoLmRPPl ͖dzGΡSSY8MاJ$-) [<é(M ce'd3Km{K*D`q6|9dd*5 CG͛$FGG`3 ֕mc*=Q-hU0E2eRmlf"+v77']4ʏ0kl)KDB`k4$5^\ݶU c/hjyxމaFl]QJ٭큦erݧcYl&ZWν`I!N,¨+t.սZ nAxO- 4NJZ} in]!AGSC5ҟ:6>l^D`hJ '/NK,:ˮ[%|FV`ˏS# +& 6OviB$ fHl6iscD,ju&{!ڼ43xёd;N2~3Ҵdթ 6hΰpAlx ;`D?Mot1֔\w7Ph=!7~_uU}WSga;sp϶EW+6u--PIak㉞xIO"|Є]lvKPw4ӕt?Ƃ]Cw te!XԼC_h'4%r[poaNS"#mLkKI,+YrEK<{`IA#͍tu7K/|:  E!ZG/""UM0Ie7OE#N"Pm $E&=qʓOѶg$+C+.\`i#c/ R^Im9cE RTW^{P~hS_=.Ъйxo?%*#~OJýߟ 8j4/(RL#kKm56:4',ڹ?(k]؀qc=q`y޹# W3wܳ)r$rmQ"F {S^U`Χ{z"OZՃ*^ÃC~`K":VyֹP /9{ԭR3Sv[{bV5`5-AWxetYhS- \m95G5kR(ZZ5O,R!'dg,cA}>Շuv@+LjW*.K\8841 `gU0'tv5=Nd?3:HaFHz0l/$H2;"I&11111111`rLYGQ,mdBMK~4{M1CL 3I?}C3qI.='9Xc.IVoRdw~V_{kq@hCډ,z'$5Ƒ +T2wB2vrX888888j=iٝsI#4mySO/Srg5g==a2d8Ey[񬫭29'=e_kZO<9t$)KW;w)jtv}"ST3Ц/=Y:!Ġ_/vO].q8Wd!$lK6gߖY?Xgs~Υ%go<]vO3<d.]&L$d-n5-m1 ctvg2p6x Kw8!,` _!ұ=ʼnOܭ)LQ&z߿[{ЎK?dX[mRta̺r/bT:)wqCzP<(7Baߨ`>^6MSvov\wF~h6}N'ڴuGSaKCܥa|Ǡ S]\ɠRnycg,8ha5acgCzIN5ƖnQ$0mlNn]wߋ++R8 I2՘Z7_2^$R8p@(QỲFccccccc$,~5)>zTt%!9'α};GuH4*41戮=U%#_:޳3#ٿ'=ɾD/^]ꀷT4շE` K3݇(2=Bi)F06FR~NqG'o{DЅf4OX;pMѐ@$gBx4=9 "GQX%n^Z LoHUN]Zuutq1_>E~Y_uT~NkWꚠwJ=In`gSEB<-W&.C[ͬ*ص4jmaX& ݌p~=D}kT[kбȤ sMz`z!RZL f(ޑֆa%~Q*͵MZWuon$HUe!NA>É*~m캫lԽ:s1tr}G~A`x)aQpxb3NŬmR *j0ꏤzp![벜iwƼKc T'm5Y ڜǔc?펇i'i38888888Z̀iAQ{_Gd; 90u4F:"ZWTo*?->ՠC۪R5d2*n؈w[Y|DNyݿ_mt, lG/=ӅzB5ƳjȔ ߓjzFD L;]WsQ/4H~+.@1ƸN }^tZվ2į?|CڧMVGk?l0$SX ^ )j- p! pW@|rJnHT}VY F]4'N=ݳI}T=ve;wK >vaR$3#lŎ #Z""~1!}ߚG/WE Ecy&PrbawZp|ɏP^3oz$ɛ~G[e+5|inG3~% 'q#[ڈP27W]?Nx苂y"#HNG1%'u6ɈwgG>RQI0GBLhkbN'$]qKCrLvBgldKD,4;>i=׵0)QQN`X9L' w1111111 v=iKa6u g/Ýjpܑ* pQh="M-N,2ʄqzvU"F3- lT$$g`^*Y,  ^ 0=gu8&h~#/s7|t7V(DYŐ1?sNgz9AgAY`ʍ/Y ApLΧ{z"OZbXZjx,":VyֹR!OnYu;6,M_YqXmH,GzuDa6o>X~"["aMOy'$t`xI.Եypwp p p p p p p U t 'ƍ'_v^Ü  u{N0(Zd'#V[-AxȜۜާ7+DgB$L @ y'oe9EχrcN"(̧qR8z˲tкB=D8.B~0_y#)'%zPTdgZwbyv;k-2.>BAf,R]]Mg6va8F2CYUQћKoғhM3C/ܭڡ%+Ou55VUh䟾3'2)`S@@p p p p p p ׶XyiKJct4%-3b |a6zh3 j/,$'r|?j^Sf~v!fp'K̿v=<:66uvsX;޷3/աTQ,zevjFo.YosᅩWm݊/=6?l5r'# ;mt[Ġe?Rj+;;/\(kGߟnf94^*.߯%ذk$Aևx9)8Ђ7.Y6{6dw7VVْp4^use YH$ ); eKAO ys~KvƆܽU""^Tv3Q{8|!XqӬNszP:򐆌OwUZgNvIXLUF2~ܒ6KyV-4Orh'T;yIxa /r%8I>`[;G8|&[}E[;>t;=ϼcG^\RSXvѣ=q,Yi#ɷ[%vbGS{V| Jih>ŽOft9YBLQx066HJN.zK @,ֽ*7_<]qktB(C-IT+O=q7JDKaƼJbcdV|F5H_^׫"-]d^pY3UgKbRYBw%=ңJ9F_0v{7$$л09>7Iz;d!"_0ah<䜇A銀:lg/rŰVTZԥUWGW`O{;^^sUÕ/kPxqZܵsERecэm6[F55⫵w8I I!N LDǒsrwuE ;N:U[Jjf Uy2i7dwxG" [3ee 1h4uڥRVoAi!䡬#Kq[^hLtTv:/)?NZ 96 IkXcpnrh z 1,}vN{VlGEWIx!dd 1n-iAciу/KGqxnݐrR;*HO)7{Cjf%vWyEO@yOGGtkT%#Aȏnps?.ɂ;r?z G$,ˇH@!*8B?#\rMRvp}pwUac!@anWd7}sY7)Ƚ@/2 %4Y΋^.]tna#D؈M~WæE- Rg?R~jWDƦ#~TKh!7U) E{bLD80&4b;{[9j[(= Ec;)>=:|G{8mOCp-O9?n/2ůȌ]K.&9v9^~4BNlI'ceY4qp?>ˮdԆ_cib2lC `$^dKDuNՓFgk}^^G5,͓XnQ9&>yPV@\BX?~0^w1 {Yjo&)y֏~?y/ғd+ND2fEi&3gmt`35D~M<7UOީm+ |0Бadըɒ6K#>1Y'r m-*uI.3 -?SyBVZh+~;{{u'ޟƮ*Wlܳi9w';~eү4!gB/p*JS)x6vU=]uB)' KvykH^) N8km159 zvU ;SXƋ~V\պBFS jjMR~8Vs]0uo*{:\-_t9ti(Y8Mا*KZNMNF; ͋ 7Ulg8Z):z7NH9>ꃃ5 C ͛$S|fºҗ qLeG=ʲE" L8q٫r[kkdy0`~s#pU[qotb83Yٌ|l/Xn۪DŽMh1ȔWFD=ݩ+qbs3sM@Jn%d-'PLٻ"r/Gj7rԐqޓ"g!'NYʦz * ,m㥉zPɂ\[[A46Ly}g16]VgF0]ՠ`$; *g`xNf #7HA80!ۋ|:-yAkUsY 7f%uW_ p*Pnm4-C3|>E+eskꊦlVB‰ٙXT[WhY$ںy"0N:m*kH.uTM HL|Dnyy\5Ԟ|{;=/J,n^E iTX-?"N v,0Um2ibSd/$I69ڀMGl6Q,g^6%"^t$&> 4mũYuJim7:|kʹj( ?Z+ް`C'VFSde/ o4MÌp_jR`JdDD3WGZ,&=9ֹ=񒒟D6C0 MNIA;Ww*Q޼UV#wqҔ]'i5t@M/$Kx @S"ؼx?iJdum"E+gO*^鰤3Z8h 暔bqE_94-`@W'o~#[ڈ$:/v,/Pd$i;[MR~:SYHqM }V*ښ=z;9f9#-Qh+'P?lt﹗g ޏyLNupꔏ%I&.YSCtpTu+fst̻/U&qib:B`8 Bbu%Ab3G§K'lll n{]೻.Fu[Hֲʈ?uU? ufI^幩W E;`1k][f4Ƣ*~:C-E-- ]1gZҺH7;Eo QGSb蝝?Tq:* 銉s?F>/%9I{c90_BRQ`;NN7.w/,)su!E;e6n'SwHUg6= /9{8*t"z# ])/o _vV4VRxNMv'kSyTauE,":V`dg${?ng_'f]C _ ~_&Ov[>sכgB(7@+B|kPm !&3Ϫ-0 rА!}UBm{M%u tyD5LeW/{&QSŠ= jdg"k'S5=ksSSv`&ل+ v\w6 πNg/цiz;;-g;>I=蟱⺢=p$6j**Rô"B-Yqu%Csc eif#ЃJJN3U6Q0KIZ)˯KUXb^ ̑)t { N8>BYoG7&05J'B~0wDvltz[qbK7w_쇁oS/1`Y XI8!i*vf)c6L1'Kq!a+U;L;>2>XwJmvBi=xgttfĥh5XIV6{꽮vp#[%k)r,ᴐ'\ъx`;^3?!<|e{7!8I!Y|DvDp.mʮ;Zņk˸\B`$jwWŒҏ\Y=e먐'w+:'!v0+,?Z M{589hoz`\cq[3L.hvY?3:HaF,; x0 1D7떥8EȀydWj !̌ 'r|?rM^di&lz%^bk70fd:w,ҧƘKrs* }8d:ɸӿs3ks_6I*.K\lGzN ~t{!"?3Ve8;Y~988888Zˀ=x[X ݼ(o$lkۜ{Tp1Z|yƮ+_;cdL # G;?>@"ZqyYwu.Nɷ3sW#V!" (lfƢ,:" ib7k6bs>kF Ş/S-ω_׳S`5,\LEN[/ZDnwXG_㯰3s888888;XH<*%.B ;.m?7KK8|q<1Åxzݙ8\|+;JbbK]wuvrF0UQ&z߿[{ЎK?dX[g4젺bƇ2KQ~pT% BF` I}D=4Y{ʦ䚤ru 9/uN y+BVa@IDATc6EGqc/N^YݼJ]5ǯJGt)SI.œz{eMIV}j0*SW>ռۊFp]ܨa:JhoD 6-lI]U8qxn݀8w|G!DƑVg/ě^E{ G.'mҟMI(ړQ&#=:|G{8mll*?Uo-O˕Ie3+ #3v-pd`B(V].0wR kflE}}ӀC赱a=^ ^B9^('_@R3R~2)V2b!Pyމb]ktȝr p p p p p `veaIC9h .T;a; OmS^ɝ2{p:]b>Ko1o]S>D}I?XyԈ\}>ܗڄ`[J ;888888_0;+)MTٙSw%s쓩fP%mXdlܗ ڻ"r/Gj7rԐqޓ"g*pA|C|>jFGd;M҂Ia82+٤o** Z6}=A釶U$@ Y&^3Wō} \G("xUZ1JD#JUQ՗j=*Xhmj=^hmR<m1 A r&&rNB}gw3gggg"|jYA29;οw3]>ZP iB"#F?8]]ӻKOdԕGaS9S6<-AxA̗1SǨuow~27mWLĨ?oJJz^nΜZ`og١{gܸ||yK{ΤWEe{08&,֠ <{tSULhgtL af_r]>V;dR׈E& B_C*}5"(tz3q'~"Q~䨉=Fz4*/LFrT_^}3;hU+Sm<\Oԣ][䈕O1q)$Nno -~}~!!׽#Ϟ?X33y*J.D|xI?VyúU9!@Q;*Dutkt4`[x#|q+SR })Fy8.Ν~?<5~"O ?|$Z{QRd-?]K9'ZFO'LDJҦiInU{Y~O{B˪-|a]PI,Я&3a0@ C|iґ Y<\}dy0cU耕;F{W+W(+C3}+ 凎y{TjKCe7ʬS7 $À2gDS:㠃OyQ2^APf,Yؠ,LHH;c|+JDНh[f&s.% I8|i\;9X]}^q9k~Lyî>*FC5UZ\{QH5њ+ϜT~8\4GRhX*Y%w6)0@ a0@h)RL9@fNA:sM"m% ahQ߱NMgy ,sJ PO6]_m, ࣏ǚ䩍l ' l%_zH88eBs9gӅh9>zh:*=pa wܷmXL.Nְ3bsEXuqBRm,](>}pǑe-*M?S+iZ,iim3`m %!AZ-B ZOb4Hֳm2b؊0;%6g Kef57`ɜIX3bV_.Q? 31dIi~if| Uڀ恄Z#~UZ-_$ڱBrxz\і fLMm&-^蚵z[LSrQ9ATW=K-3\ӼC4(ihg)2ݷm7ZNڙ(Rek20Lé3_#!<ގzhUި{c`Dm| 4?=>-b N1s?WӞlPڹÃ&i.So|jgo$YXCs!flM{a@qwN~2Ib/`bngFyp2$mBMfI78ңΧD_{Gh4kǁCH$N.iq$j#*Yqt>gި[iB/9rz}{Sڝh#>O>q?%qX~bj~MmlXyAQբc|8Qza+Q8euˡ4J?oX U!|^Y&P/';>6sP6ixGT <z mq ~1vp&W;ҏ k6[R7;)GY'j0Vp2BӔYtaZꦡ c uk ' CHnE[1] w&~CŠu%|ߦyV]퉛٠)gł̔oC_(L]T>w_}[Tw < N(6ȋ|NE?3Uww,}|bt h! e9LٙEX:Ĉ%}>iڋ`]7/5ul|d /ž-@[1Jsۆ_mNfy'N5ݳ4蝽zkhD ,Ϯd8و',"_Ẽ)YٶӺ`K#J* JlkӸ|Z0Lmt{ w,^QaL<9O[ >@ lNeҊJa;VɯWb-5Nӹϸp8ii Xp6XߐD=-iP G#fҭe8,5piY[kR1EGzǹ|w˖f_37"TP9{pe_?mڼ' _zwjPV8-S%k|^;cAǎ+˧\{+z~^6VT<1} O҄:Wy7Y"EQ-nAIk?\yWE+2c7(hvo JwJ-=(.)3$ԜC67Sو|Thsrǧ'CYp \Ɂ怎<孭Re/)搂KfD}8fK:iDžjf3g'>%$K[j8e.x V0XD{PctXjd5t Ct՗:a46a}^\nGP;r(^tb8,6&"1fS vW(^ -}7UFM/ӫnӋ`awQ}UiyX?~QA דdP+NL7RfԽo\fnO:ܸqڞ Y:E0:;uewVDz>p6!'pâSw@G{\*@%}V6}a؋w2.|ujߊuI]gx6Al_aM:[YBh+49 ֥i}j)+uMU4qH ~(As Od*Eg8W=F+v~!цJjDyuБg)^XiiʺJ#q|JjD^t}bW_sm;G5q\h*{>_. e~yŒsCC5T% QG[:mQCgȞLQMdm&閥O> 7I.&F Uţ~ =ĭg.3ܡ ma{:̄].W*6vrBN:h{Z^cyxtz3 6TO Ҧbgx{AruVm9&lBLH#ިuP:AZ ׆e7޷{)U6OW m }qq:8 /P7>qvf1ȩqٷԂ?g@ъ9\#҃ǵsFaS=ĹsPfsˣ 6ӹGTU𤪫QA0fg,)Վ&,h^NШLh$=Hё_>}FG)~ղd[P S֕;uQMs.+5o+Q5KʶxV~G;Ov䡒 4E ~eԐWuow~27m4uْ&ߛo8vhZ.g(Yc:Vyz}rn[aIN$L}ŢkZ{p6+ηSLdkӦgJhqVpu`FӤf;r5wp; <.A+w۝~c ژZ,n.K@M?1\<,N v,Uഘy/LYL|K18{q lf`aQci \E}d/Xo$"^t$&V3i.NK8YmЄ!YVR.=Ufggł[4K;kazT/? W!q ~铙̘?]8%H|YVJk|[gT tQr찲)kNz9%yw]SvaII)A}ۡѠ!"#&׵5 Kf] nzGP"3T?\yEQ`GـaSƒ8s|[Z0>s#pT)dCW""HIG+: U<|۵wcw?'Z9rYf9H-80 Os$P?LpߠQ3Ac^S~3L  N \F; fpv !Qh_fm0*|2Mca F3?ShP('FVQ[8,&9QTyxwȵqpvau4jc8¬ͭqyjqb`Ж} 8Er]?zG>?ل^pXuWK,X\{in褖`3n-ʨ=F OAs61myŵwCY*Lyî'a?$z<^0M9aGlK rT# ׋'^ZTyuJeCCZ꼖J f&k%ͻF1(5m&!xvlP L^gHdܦxiPE$ KsV [bH[SUA{hByɾ%#7WQJRiQ*Y%t{ Ly˱CF*W'J,\ʺ:=1QAPp*%p7m1ˋ 1n|fK0ef,|`W6, \a:>k5'k[ΊEysa{>赇SUvTLjP)"ل$g46ަռ0MgwgomE4TW"2Aeݮqyt$+cB}33=l~+bMH`FaEW!lך|F8}`E]s_@Lz'o̫fEPJ@QV"oY_Qh{CTH N@~ )oAT[t2<=0֣U]wYpz6PJ4.{G&b SK>Mz~: nP,QI5v: 7GsՃ+c=JPj:K5E"w|[&Ŗw/}cc K7Yg80QGq3ۙX0b.Nf9lF>6_1]x~d<6e?g?6>mN i~1:dڿ6iMJ1on3 '˃Pa4<$,k_ F~*AG:@1 uЦf$ Xښhpa]{V}7U OEB^4e`f* biRL28Dv?'R)c#ӂ(..:;;CF\8tT3|+**Вm?߷0o!g9 ޘ0>h.'q͌.p3ƴ$eU!ϛE^ZKKH30R:}?QߛD1-/lyNY$‘p}lhzС-W1Lv uolQ8b'5Z䷱5L˸n[!NoIoişX( {NxaZ1/ NߘV ბ=jjTܠvqLih=Rꛔj?#B{YI);$Mǿ_ɸνWRTMZ!^B.ت͆qw!FW[zyL$0@ g /)Q>*?.pjݻU~ZAA/w(:񇠁=cp~FzYr+~@/g#iW'L8!wlAe|KI'ܯ+ 1 # aŋb.f-ZΝe?1f˜~aChzԴ(^|ؐKo;fMb g= }ංTOkU\.N]$` Ǐ*ṫw8\kkMBKкlobԈ tg1](YXo>QA< )\4 hzVeu! o?oX؍F17>/ʗ~J;T>^bS0PFa`7hicC%Yyw${H.v pl8\]2ƹuE?]levm8vlM"K֮^lڵ6n֥C}uvm"ڰ hgD alX )>^pjBJV}`qTH@m]<-/>WGx^}Gnh(ҭ`T`8!vʺg Kuw =j:ʢ:̢5*V}=;P9, nfy'NY݆*k#Qp[ܡ}v.*]9]9s=<]MylG͙bcUcR-Rp"TԵGgJA 9rǙN+%N%sBqIq><99a tz)>y:: '7a0@ fe ߸N) / hy@VW)2뗋[_{q!xw' ^8Xnv0Œ((.e-Z]e-t\T)M f."oq %H9c-[jP.{g oy4WE+2cf3(hvoM/8JwJ-=7&c>IB͹ T6b8:w$A5hPH;>>2 ςO&vvPճu4reRR~ɌȴGݐ>| )zYǪw>Xh@Y=a&G%SB^姟<0-|4PR$æA-fgő+a0@ MfבVl:F ^qM|ܱI͆pq!2 T֫a-<}ہfyC7*Kin4a%=S*:j~oH4q\(:{>_.HEv_w^8l%PV`cA/EZ{oީu*RIei砞#ѻ6\:mrT_^}3;hOcG_W兝Qe~o;,b3GCng)+bR$j'I&:ʻ-ǻ[G'gEDXz_d?{`#6bLb$?\6+@%1[) W=X:ؑV%*k$_*Mq u^7;:2%їiC^7(i 2Sʇ+OLa;eCgEBSw1X9o7z:aҟM Ӓ6ݤ{Y~O{, }^AS;BWA_s4q_RE\6;%ga0@ |͈2rȩC.e KC*5EY\ J8j B> ~J49:(NX^?dI`ⶲ0!" 鮔K+}w@wP0lLdΥ$aS; /YKw'k+3X{y2QZG >ƨ: 6f./[;*xD_EMg·Rp*Uz?sK9B:T*zκ:/qpqm3`m %!AZ-U(%4'VGzmvo.3V-8[^X*+0èKLŒ=v1fp'KJ͵O%6;oM<Վ nP_`g ߁Ev[?*x"%aS6'V:h&-^蚵z[L,e,:geR*hږFҠWuᒪXutt֕2z8uD6tDQ-[k..\a*{=>72?دVJl&ĴrnҟfK5Hؖx1 ͘عi6](AeE4mGW+P;S叙XCsflM{a@qwN~2Ib/`bngFyp2$mBM|fopGO' RF\ьipg؎#SSSHY'U_8QVqn1x z er3_cCA;8gݑlZ</O,m&@GFi{\_ ]~{;@^;ҏ k 6[R7;)GYޖ'j0nV/OCMJ9+ Lu W); e´MC 82F8Qz@zt3M/ڪywRߐdAݾ5oguў yV,L>u8IsOAo]1LTw < N(6ȋ|NE?3Uww,}|bt h!\o7 e9LٙEX:Ĉ%}>iڋ`]OM]' Y‹w8n-iahK-V Wp3#w6oUĉnTT9\RᵲCy?2&|т!U[‘;##crAF(!wý M]`Â[P:{fWo]6SwV@Y&z[ժg?Graʃ;78+?%>;Ir7`g?KuNލ.d=ҺAW!6X p:ޒH;Xuwv!WωQ+j<h lm͙bcUGpڜ!s}u$d"8[/.>gD"!d6[j=sNW4]apBYggoocrG2:tu5SXp2qۙXHy0%+־]{ZW c8ZYౢARݲ18q}.] o71#!^y⥨Fm͔ͳ띝3zGumکLZs^I>J~_2xQd;+ƀg IoӒcC qVgѥ1:KX_\طn٬l$_c(arh z1,}M{j 7z5(лS25)#,f̒>De_)Kіpip4E$piH*Zl5E_E{}kn$}w{HB(ڃE;e|sH~C?·p> N rǧ'CYp 괒<yVW)2뗋[_sH%3J "Ӿ_?vCpGbNtf%y3ʎ3]kNv[vsб=~%]  oa4 (vo"~sLKҸ9!ƜWZCc9̰ϫ jGKXld[D5L|r`qjC ūʨez5mcz7Lu=J|Oߺ:-׏<9z cũF lP,I7V7Nۓ>K&>Q4]OWOuX66G]&vqXtN]0Z{Cʦ/ {\e~߸N[@n?} φ6!쿩_{3 qUhmF2úv>/]-azCF<~!³zrjV9#$NH3wVflc8MսzFJTi뭹)QxA]}͵5q58~!xb+%?瞇C5T% QĢNξ=3x*U0:U޴:Bٴs0 -FnY^{YDkf4ajQ Od* 6Yw NF; ]o=lg4RY&p=&閥O>  7I.&F Uţ~ =ĭg.3ܡۉ[ {Z '\TpmY[kt-?thԥQyxݳ JgC?,m*F>qv$WoՖc&/XDߊD1b6`xWsk no;«Sm^-Cm/H*s_A\Nfd'McaOn&x̭;r*wg|0?>kb`⠞;}E;Q:sFaS=ŹsPyXEUWmGU*((Oi^a=Hё_>}FG)~ղd[3ruj|vujDF]yT >pzcZl`9X ]#ݾ4l;Gl7|1^oG*@S1_8O y_|'svKS-ifcP niEržU=cřǵ#Z.}B^sʤ'adg& ].}ŢŒ8' Gm28SX뀳O Z\~4ə\Né)ϠKPyv'0XpmL-]Lu%|SNVV;*jpZL<,&>٥@Ld3騱4M> Y[7xe/:zGYut 4d 6hΐp~,Ft)*_3G5bA@ۘΚrs jp~cGjUȫk=_d;63oNmViIӜ3IDATv00}@E7 <ϲWB^Uߪ=i%LĝԷe0)2kz֝DCiK8uWnP6Y2X6q<!=4,&æqD:;2%^z/-S%}nk\y:"}pztpNvB;(V~{ԐD3G}?, `%ƾiι^G nB4j{ ak@spԏ!pI%ehgbSX-p8a>d8> :A̹ Ld{0ucl#ٙ)4(i+٨?<;t88p;j?|1naݸ<5i8X0SehK>Op"=I]u؟lBMi,:p}Lc,j.ڎ4A7tRKyg zWnF|NmeĈ#q'ns;!sl?O&JK}aדΉðO=/0#j6%y9Q*a#l%X5:`(]IΉ_>:_^K?_ؼ KmⲎEMpNlh~Za ̄;*'dk5a|vKO}k aYP!ՠ(S&nD -IϦ=|pj{ߓ\>@j7}1^쳻"Fwm|_mfSNN^ \]=cl,dmcPTTwui,M YTfAoG=hEvexY,|*] HV?DŽgfص!n{1."m3{*57ًBخ5o4#ܗ3c1V*u'nFi߶Y[>9TH N@~ )oATcN<q@D%$FE 8j(/L-d'7m9uoI2<ܐ3>|܂`nQzTu=?h].,0Sp`a=-M<_XǁQn p8abFƩFlgb1fT8X \Ԏ#m_(s (Yw{ҟoJҷ/S? g-͜Vyњ jO 2*^UDlPVɆc,v>q"[#N0v 6,@xqݶ:ޒWg'ӊ?}wv.b^'1'm<#zXg%Կfg/zR2@HP[ е%`n4di"8J *Y^YeJ aeWSͶk׎Ea9m^u~ɖ5r^hZ:Ei\osBBa0@ /,qԼ' a0@ -|pJ [Ԋ]h3gmT(_-YJ)s :v a0@ ρd &̴0YNI>Ak¯IhOg}V!ř~Bߞ՗jc&,ʦIF0DT<¶:&%&΢۰8Bz'wH?.v_lazY]ѽ~ovқ-TB?ںj0zՙ 7>Z$vF3F΄a0@ = 侤D\zDҮ'Gu TgkYrǯܩ>G!_}bge˱Jsɾ䏒^ 0q ܽZ#IW8_q}"STA]N]nmU+'9Smuݞ9z߮ w4.t F̵yu4;չ?.t.Ɇ/7\)t_|{{><1b&a0@ mXx;`ݬe2uI@KֲLu'_SS ]3/lXO#=6ŋOvug4_Q ~.>= |p[A"*юy(<U߷opzTN8/uE Ũk1Ϣc|8Q<賰ވI}x\-\ixyn47ȏ}QS¸qB[i4: _NvFKs@;-r.iϺ#ٛwDr剅Dkt ZOHMJ߳nrdGfP 0wv=:]C/l_mV4(_[kﭞǾv kX@9Ȑea$UgUpmBԽ‘s@vޭ^CQlE;3a0@0_2 ]MHʶ`^6, 9Yq㶋ǽHëpۍ[@1q›Cڡ4u 8Me%?[j1R+v]Bh9# 0DwZ@h$ ~TyJ8ލj A;蕟$G03X!ܥ:v/3%I02?ʞOr gTojD"whݭ J~N|G\}O/OWS9@Ѻvspíg%7~@$U7u_Fl[BUҟVz p" ^9L~cGk0b% ?}wlAu}\ȌE䯋=ہʾ5htJwJ-=7&c>IB͹ ߃T6b8:w$A5hPH;>>2 ςO&vvPճ*JN#W&.(]/L~qT b(U81HJ`[KNs׫=;\*_4~ eՇM0zkQ# 9:[~=z[Y&s 7ft8.XuލJye- a0@ X#-=Lξ=3x*U04ZobUuvl)ЁԊk7玕Ml6aW榲ZO_8"9mÍJlt~5Ev>/D)XIO A#zvV!q58~!xb+#~yŒsrCe@Y 'ujzrT֩J%ͦz`ԟzW0^`~Nx>=:=}f]X/=sM`7;N%qq:yZ'E[}͈ESĶ RvΛC P~:'YEkA-egb-a0@ 0`g}iTv;ohcގ}FG)~ղd;r*wg|0?>ӄDruꏉ|vuML*/=QWEOq\L=Vڬ ꁂi (xA̗1SC^=!ܴ]pè?3wZyh8.poJJz^n8uruvp@I;37;";^~*ÃZ8]**U@8x,hg:0@ @k3tNS9*@x/YS/Wܾv'L1գċԨ2r]Oԣ][䈕O1q)$hޖݭ3Z""BBBJ==o}TFmĘ@, \ թMT.\ quA9s EoH5.ɣ 6-{=rʔG_#R/?UNALKrPf\yg K!ow(Z>+rǸb3D31Izgm[}Դ`Dbņwz dIg%mA 6mޫ4˱p&,T;ۿd=fO݇n:N}#"?fw{/:$!a0@ ZfDY;+凎y{@KC*qby9]:%!Qa|Ut?sO%|Yd Gn{MUf,Yؠ,LHH;c|+JD> 2+ITNKsVk Y#@d7 v}Q1zQSUu l%X?\^5wIPJNJ{x4GRhX*Y%4;9I:;d4ʯr88^w3O]:06"Vͪ۠ihpeoA_0Kfca7 dHfg(=9a0@ U b4nt‘[껾s".2^G" 'WHuj+ Q:viYu,/5Հ V鋠)Ӧ!?`'2MyX}8+JgjnIxyAR)L!~>`+!VL%a|n,P_ЮQ?%8KT6ng5a0@ (..:;;JgHEE51Rj1A(Wxqf5f~t\uC0+*/7iažxvyNTܢ۹8S4gyytOa0@ Vcc flh >(+xИq(G@z@f?pR//U]܃q=RWWmA:p9kkdsӧ}vq`^ )e`8i` {v?KuNލ.d=FGQz[1+?%>;Ir7`gx':EneV>ֱKDSYs,lwZ\Ʊa[_W{g7N^7WyClj^^>[^y1@7`u܍jE@ߠ}P *VUR竾׽{ođ`5t+7+wFrE207Yl" a0@fgkɬu gEe)QQQ|V7j=s$E(O k{ qrfXK;h*R{9ySݯ>\^qH1|^{#СCz׫^>c=zOgfyjؑ#Fiڋq݆z:Q]5u|{v._F?6_SI^nň>j_5_?o*owuw 껆 ]_j){ӅXMg2yI,߾/.[8mZ:n{ke%o…Mm`u?98a5=|~E[7-6VsSLz~uw}tj[ ?poz |+^\4ʒY5ko[:iAߕ[Fto*_S(jsMO8w߮zR/m׭m @8AX Y V>ZE^=T[V̞s|+5sVk?y[~<_vdܭp?]aνT|೟s4ɳg;'mvj;W:şU7Om{Ʋ}>47l^+_qLW}ށrū07~ܒkv޼xx|e?ԅ|wݻ#㍎ N`WfqLs-V~aWίVy>|xŦSwO7iRw֏7=sۺb{F T?Nۦ57m^޽<T ū˽0o^y}_[_n\;<^Q4w~S.m5!cV^]M*O?  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H. ' @DZ @ @RK @ |@#@ #Zj  @$H{ @"~DK- @~i @@D@h%@ \@O>  @- @ = @? @@r?G @ " G @H.0쯩_=J @Y&0*g. @_o* }B= @H /F!,zZ%@ @`kU?}ߤ @8 VZx)/ς~H @ y5+W|Q[V^]^l @7o޾jŊmذamªLMIENDB`node-gulp-4.0.2+~cs38.20.35/docs/why-use-pump/pump-error.png000066400000000000000000002031671415667007300231770ustar00rootroot00000000000000PNG  IHDR!qsRGB@IDATx]`T>R6W@BR Ҕ.Fi*CA((>AhJO14HH'm{w7͆ dw3|S̙<?>8wwF0(E"@P(*tIII)~؅*yaꫯz ?JuAYP(E"@P<vzwynڴiL&(Q(E"@P(SD"<䓋ӦM7MP(E"@NOt{^VVV"@P(E"@{#P___C|4^UW d|Fr?F0&x.BCQʪ3NEU]F=bѫӵg4ocΣ`K;ge3d\HdglNk\ 3Ho" y aԛZpm(̀+uB ;5{}K?4r: p?eL!mFAEv&K4U'ۃ/h6~ɚ b@X/k}+NoA}" #FX4"@\/BRəPw( YzJX`\5=ߕ|f{7~\N`ceWc~Г䓕{];['75b1X 9-ט4+M#)-lA9{Ps9? |c%JT,C7@lk9 =8 -C@V{}Kѓ!^>?JO|L $Jq|1/dho(tѣT2?؁Q+04fB Xc-e$,̘8? ol*i(+,gHFOyub@y/C̘y~-8kφGX<+#GU0` Vdxo`J,q3FpYE:*IPFjm@<HXm> 7 TP77S(~|KYf0KX%4aZiHߪYBhE MIIӄiU> 7skK=@^waQI;ۋ.P\:y,1 R?9؁*y ҫI4,_ |NMAbVoztɣa9i sQqksd_KP:P/'$:T|l|,yʎO$g뽸=q/"9#'@QnX],ys)4UCFi^)\>sfP2AX=a֒GabGVG~X쏞LPk3j c1$.{x'!Epp:8e wWHτN9'w-Afnwߩ<xva #{aAv7,ノsTLvH\↲;CF"]> bz(G_r?df?Ȩr,Qj%jd !<Ȝ+z@CKKJA{|۬l(8X,( Î+V10¥ٽch)p0CZt x&5_?ͼ`݂0PV>X sAY!a[!;Ǐ/q6؋r,Z,rZ/@WS%ȳ6w* I;7/7 `_-gm0oi Lo9o ]a/i `Rm0%buRِߦ`ҬIpto53);O~KXO<7(CM~C8_Jxgh?Z^ 5u`Asm>*ܽ!O g gGpp X܅&<8eV *Q?wYaZ J<ƩxFJنa9/^2?  mWໍ%'a3rhVG-S7=UbE0f .w><'0YuG]dc=9凿Jl#j N}}#x}=;aQ+e7Ȁ N#/}anUy"Y'6;a<{? _*XLM#B:T5w_[&C@@-Y\'~On!i D$o(J%Z82%aȍ:LZd(rdgHx1}I*Q(Ŋq]nXeͣͅ8(zVm=pZmPy?ë+%+ 0'`Tq}=`xr @J*gqqY`Xى`z*8؛LHk?g~χpvo9{"(z{$j:.>*#xdga%تTM >?Fm"K^7rĬr088ʿ/qCq }]a2ǸrOO@?~n)tG e+=1)rVcDTB5=LLSg#a?`1)>%& 'nb#/~x`MbEVG<3l{c@+[P(WCC!օ 93 9.Ǝg~t8Yu m9֞g&"92U r m{rȁZbs(F2IZPG}X)۷I^dRU*91*rJe =3>GEn+3/Œ mA m?ٌjO-)$V Mrgy7`1 +'=#Yri /y%Ք{sX; 1bl8:\ ];B1s* ;zQBٕQ`nd'Vsz᩷p|sÝ1<KNdԓj+xvGA=u5wց61ss{eZg6b$7 %%q7fIE"@ K4o5 ee[OH?zJhYK;ȳ =Q mǣ0!i#т=f'tx?&0q$ I=oP\(.j@]=6)Z֕k9^(Y0o0G Ea /@j.0`&+!j*{X4 ,mC9 6\i?'XZ Mpvχ g6&$}8T×ǯ`߾s|_,b^{@.hC?b,m3'_V.h΄ 9̳Mxf >f=S>.iBn&3ĕ<(Иd@: |ф+{^G/`:f\<a>0B8+[>^8klкi= dcdo`SjY <;\̆5wtTp|9&NMa2 ENUTןj0Ӈȍ2z4k0?׏Y24cXz'<,i{V=bWfiбXG> }Ŭ.Dvy̆W߱OøO78x C@|} &0ᛰV9cm(m/77뀗˙hXȦ*$T6R$)o#56PP:S4,q~ܔ/Aa'˟/ٍhp6MR(wLRTh#]qJl +d2)NDx:BUxQ(23/.,J oY 5Iɔ|\'S\'^ Mř uE6Ac0L٠P()4{̎)y~)bu,Q(^vv6Uoڠ|P(E"@PnoѹhvE"@P(EC*ִ$E"@P(-G*bZE"@P(EC@x?4ZE"@P(E"pK :}KK)E"@P(!PUUooo/ėpp">kmmSi֔K)E"@P([uqBR(E"@P(7UoBJ"@.$Q0E3%(DP(/N-6[|] s EY~C1a^aKό(/II%r(L%I 9;!λXydYv=m'^}OSy"g`U>P(-@W^jA;FBf|Kid/@\0ۙ]GOϞ&7,H7Cщ !&r^eskJ<\lQb'+{e֤pUwϻޭ HjUI(?3eE"@"*~lSF <\WAB#:X!_'UbN=blTsҾ_Kםs 'US}0S7[0T֑ZntUZtWo ЖE'* Rv潷L#!Sk|Mcs 2Cn.,냅)긜.<|~{|H.L2eI9BnE:4xYf};R2ʂw7cф#4q9BzWXR:})?w #u*2?]kH'gOxx岛e LYudn1oȜ=1=u^?Nbx pݒp؀PV$;4/>1Frx;Y\*)bvcr dVVݝRyU^yhu`_=5ʰN܍;oXs8/y~J}kWkueMk}e!E"#@1nܵbrFv uSV6$}2/[4ŗ<?Z] {r]q7G+bABI.H x͗F`c)nnno 0'*,X j9wjUqMt腺 (IqٓoTϖUEeFtHoؔ|$(>qE` 95Gc>R7$^hg5iTK*KJ|$q9Ypyv43bb_$4u+<3. %#%L2ZRv'a =M5J"FlBR0qf*Y0xcq8C徽ܴ+Ք[%0OM6z/"w¹Z|\uUQr=.yXw&pX~" ~@t᯻2I_ w W2S`61િ˱6d~y{JUUKVO;V~{}&!(XdfH전yAKΌ;w{Rdm̩ǃ6nƵwڄiE"@VNc̮,zByqWvQ(]ZlMx>QYcS=hTtT Y8seDQ/7|E{ w$ꬭcydG2I1.o7<'8jk*@`DL4ѻwa++^ǿUw*@[uWf ߵ&+|R] R]UeΟ)C4gMcѼO. 5,}"" 0DX9e=~kъb]ː$ظc]H\Ȱ kMk/39W|Q*yҐҊ_>cZ1x7?)-yeʹk9%R"Nm5E<`qmp$X z!xSjC}6QT}ojpʪ&4Ieʷ$:;-Xh5sV_(g.$8IJYCaTN>,78cX$vml_18gʄm6t&E`D!^xXGחlxFm Rh^pyk:azm)u_ edu8kh{7_{{ 0,m޹JLC(E6C]TdCj6\^|Y #/?OFy)!4AF%1f3 ,*P$ T뺲";;n{~Dh*23 !p:vShN~l4)aX.S+8Nr:J1bFZYs$=Y$G'EӒbF ѬnVv x<>:-}|_̀ X:j^-u-~vwSh - Pޚ4Ixڡ;s3tG+tt{p^ x{7tuQuKuK׭w-?)o % Æ':Ib \rc4w [Pg5\2'&e?0;ob/1{"4`!oP=X-I0{.H1OA^RjoLiuvqN~֣`=tzI>m[TxTs#X_`chGT /RM ^ ]zcE"p;#`X>QAv{=m}X !~^SbNFW-<Юni_7mx+8o8D%majj Y'!MCb v(g|KLn/ѾÁh^2in݋G\ʒ,9$*͚_gÙ|nSx,7/҄ eanU0^?̡^ ›y/o/0߳vI/,kG󧆺4fo{{P:8X n1Q430LK>엙z_o1P;y 7YD-C?|= oHi>S7PU y}Ƹq')9sDzy6N/ ;?rj HGK֍lV7uh,3ࠣen %1=xG-O͋1o3OO?I߇aCvo0Gkp]xf=:ԵדbflG{Ac =19㣣g.?b, к`>)(9dnmzꈫnSTĢh蹮s<&Z+uq sW"WQߜ@7>zn\CZ ;h\T,'{d,CIg72ּLԛ[``Y f:,vɼO3kP$ %ؼQhj+0ìd&+C6 y݋c}ZbEw3 /.?/\/宷mʡE"p[!`D~s1anDX_ g醘1jЮ_& 8i谇>mÇ:p[QӖ\$ 杘] ]#suXcH@Gξf~D_2oF >͒Ym4'!RT Wȣi0l&:|w &ywpsbSCL`lWXPCHu#wvy:%QeiTe34ɀ#-rstS&"񖣣wehYb7\Gu LWQFFQS-K[oj[ڜ%;M܉(nǻz; M^~=67Svx,F]԰M$vUGRwڐ GFiiC#grW|;-=ÚD+CurIu2#hroeRfؖx$r6`#,Ć80}1[?+aS$\{ߩ463{8l/on\l) /w36/0}P( 76S - nW WfTxĠ޾uF}0A>Rgu\`]*N*fBf2ML^&5/jqjVƙ,:w_o0Fo MC|a!wyvC,Q0ď::a;|)晙.XyYtp4`#p-@SS|# D4}Zb;o/G; `oЧol &q#7LJ#dlxkABs垼R)O^n+/P6cZ̎׿Yn9T~wB[ņxkf5%w+EϰcɅiR 5fg9r øҌ0o sPI`:=қHx':0&Q 35iO/S6/Iyie;i-X5\-Ԅ6ON_֭~߼$'7/ s2cLں_^hP-O[uz\_>y̮ g7t/Q@j.-Keod"fsx[8N?rqm([d/wQu2EY=q;b/Qn- Z~q~MmA!hUFЉv Z4[FuX.^tө.}9me)α[7 `*:Y $>n|7 G4اo~v_h{dd[KƏL4 >B@_~LC^F\ x ڝ<)BMRQ\o&TUa?=ʽ<%-s86/|dʔbivNE\JU`J}|aRBhhҜIa8T5%J}BmF zgU~o͊hN,[0qJd@y;~}nU@RtS'Ey.jS0`ѽ~N-_:qEVN`yrQ.JU<(8%!X\S]M }f y+}SYbRx@ew0 qqB;ci,Q.&Z}鰤涾}zޠY~f-\UW?ƓnE&[Ǖ![?}A` X|&S) /\}`%`{]8]ߏ@ ~];Rt.lm+H:pItng u7jlWxg}~] ٕ ✔f ۃC\$4fN2g2D+e5+ib t{>O{fNV!*aՒ' opsGJr -䶶hܙzg%^Ų zx2[;_l&ݙ{_/C[uɥr"W/,fec#+nL+-HٙʏNJtUL񶵲 ,-ͫvO*x5oS{-gn}.y.I,߾KOw5W|Mu05׫լ?ˑf[ϧ"neFCB<'x޶Vxa?ܱ! K`Isܒ?_uKg>?GrU+u0Ug/ Pl lK_^?lQ|V /mq"\sxyl9/Zb/(+yy4N}Z)W_:i+jvgb$.)*q}NW{w᪦../ǦҬ*m/@ڮveYl7^aHhկ:-8-?cv ]km GQ=c#}I$m5Җ&;+A[-qv˷ʻF_s~˅5θ q+Fw7np=U< չo2Ϩp;Z~U\'cq>u1oK$hpM[xm8X;zݰXK+#r8qޔ.,{)VOfn*bo9=s&DZ7'BP]J69$_1 J p2ʹm%_ q&:e P5I*%Z;3 XXd@qgIt]DXoƕ+۰aS얲 عcG/G2,m̭6WϛCxBlPё]R DMfmlr"0UKVO;2s&lr3w BÃ=Q$j0a MTLg@|Ϻ"偟pV)ݻ;}\<J-FCEs+vnL6>qE`M!'E ]ƒ,{%v,&s ugv4B$"wl9j~b7Y+`Kі109g]>xV|k(x\2-EU`]rN Z!vLjl#Sec+fj?zR/uۅIlθ_G,sZd mOSep VKې煻q7vi(s^uE߻"Ts _-4z _m,9I4XDRҍi?p=l87Oke~ٵ$68_dw {#\ZKz(E֦)a~XJQcՌ^YRV5ݺ,LWI@6d?Yn.]'lA+\;WRk ;[\P *ZjҴ…Mv8nH5+wo\zRȭpt;&[Lض!$;e ;^I_Ir"!+חlV$M.!FVy.?W|>F m}x ˆ sH? &Uۥi36Ivgw^K@ʔLOMdԣ3%QK L%sKD*Mi8a~r+mIӆG^Ztk]\2>W.;pPO`g\C o&? Q05ŲKd'iKp|m0M%"֜O\ba}xd"N^4_OBhۏ3/.:h2l|%GCxPܚ %[KJdR%KH̡b`mАVwx*Sȵm4Zt%)Ы<|1! E6Z/[lqh\HFuC1".J" VݟO0Bg6!7Lsa3pM/]E]<31K!oOWZ]g2KaWkv!ɍ>֮vdYмXַ-A.c{(㒁ޡ!tt&z?VX4Ҷ_.P ujF OM>aw Ɖoe& ~({߼Cx*~#\/!?VO)TeY%=zrBV´ߺ ӀYaҦ!FT\-)p!LG $n6jrJY!-c ]mŭ]DໃSGdgP_px]b8,{OL~8avЛѳ/j1J5#+wҤBQQGՄFPR5-= >YN:Qz^2ͧؒ3?PO;R?e(A0x�L'W|:m#YI kK{>N,v\4q}ZZ3gxqYɥ' N +H"h{mLRoJ$8 B3@0Z`r,pb] b2V 0GŋI/h2J1 Uwl ۮ%ݦڶVMs2$d2R 9k鉂_f{4Ƈ6\Y#dTݾH}nDyH~#JēmT\tCSW.y3aݝ g8u ,O3 rP&&8:0Xs{ʊa /'[1%Jcq8|+Jrg=Jp@IDAT[9g#spdLFyEr_Lem7Tì\VNpk /ސ|q`~MF*>Kj f ]&WF2\Shq9Q8#cTo/2 UOhHF\: O+j<+?.r,7=ɜoUS^; ͖NN^C[ D2Cy%/HH5;.`:vʊQț,n 3㧏GM?aZ={kSt#LxO! 'oh҆r<_ɶc9YO+a5@]j3B]]bjqhjI[Ǜx2Y PTݕ}NL.of"O}(+nP)7yh&P̱䢥x J_^.-}$HpT _cy1'{PG䚃8bwmzq,^\)Nm*o h҆-BlE^eG#;HEͤ!ً+)赨 o0V'jÉ+N/!.'i/hpNCx6aLһ-!U--E/pw~A3զo1 RVf{9Ex´Tے1ٯnFehW)T0^м8m}1z`rqbk,ϸ $c,vO|wN7'Kק/cKl$)Om_> kg \(y>Ÿ[ڒ&m%Ao ໙ xVQ`HE򭄾웯6!vAo<}>*/kyiZNr!7ՑYN;ۂPn-61 HBР фZhŰ P'+5ִᡣǮJq.0; :^ᚇt9O:bÃg\w;xZ^o(Yv,/8CƾSiת !̭Ÿ s%BP!YݶMU6&)h$b;!yXٛk~Y[jn ~R U|{\4Tx4qa{& k'ҫh#8hd(1g?vIk/s b//VuPuW3V_#`%{t#DŽ(qV9Ax9>8O.h1 q:IUfJo=4 < ..PIOj-Y +x{ El`Q'+mR/ĺNQ&9H̓F1/x\&rZWVwo:ȬSMZ`ʹ]fuZy[/sQ?0B}(.`Tv.9c3䳃F7Q> Iu/sg*E*(iFlU<^Wz0j/L r5`f3FQTzT>{ ւ6pijJV4W*`3KԜnu:yHEf䴗=$q՟x>PN:[h;SIhm4lF֑3s㶣s70|Bv@YтX['\YGx_fO5ȧ`ӑ/ƍί_=#q ͌ele? ᏌҢFN9ZT7<ʰM*N2Բ5a1 L~:Smhʘ 'N ^ >EENcp<|jދ'0 !GG>-{S mD:ۥz?4*{Nܸ5>S2ՇWxPI~D^+9C/B"|sy0xÑפ|~ UQCն+Q96q˛O p!`.bYUcly% &r^nTˮ۞ $BqS5l.MS$D48vo1gI@]`FE.C]~` =Q\6hHN 8,(3ʋbHX>WaWP{]vt8䲣,bX61f[E'٠8/RT] hCn1\Taީ(/Yp:Qh[QwP۱KTbS+ dW[2*;ÁŜ2o FH58xQ3hbFXk؃JnC6eQEx:Qox,},#e H>vfݔ.e,'WԎY$q@DiFǂdGdm9۩w~ڵ&|ΡG7ǷZ`*bLu3vUUsi7x7"FryqWĮΈ>+$5Lq&&Zq&3$3#2Ƭ϶IcW {yL' `lP,@^ vAU/DRR'5>cSpD^\y CI 䳵ƥ,ЖGeo,zęVX-1<1ϮYڶt-'vB0 @y&i&Bq*#~PoZ^/2:߹%{MKL4wˋ>ecX6oMigpC(`V2~hD,Ar[f|1&I&c#Mr;3[ON#lp ]a=v}٧293#Ns[[[ =JZ|L4bR1  @4Zmӗ~be_<F դ3.,zb4m8&G9svau3e~+#{!?K'!)&$zD=WLj}A^/$0pZz1(Z2 K@8g..0qnBkY@xnPvħ)c>]cHƶ[i% f znM@LECoNM bzr#߀ 팓z|\4Mmq/SgG>C|ϤwS6؉֎sU{]Ц]jD4v8ݬ:r*E~4ILfχ.XXQbg#"̋u$5,d~zi1=n2OU|Du;d߾ar CQeVR+CF;O:z8LZ֮L~.B[QQ0Λo(5:Q$)-⺉ފvf-%0V/Ν/r54YP{P(E"@PN܈$."@P(E"@0mCx@Yy9d3Lu˻i8!45âђ!b)E"@P(d(G,ķ˲Nr}'/hg'.V^&=͡lج{<2;"^ng\:,{=qAC[ņxkf5%w+Eϰ5wΒ > ?Αc~MƕfL?x..`ݖC%?2Kg.YwbK'6,M^}!jsqo\8+2N ːT8 \XE3z" "F織OY[EfE?űQ)_%T}3h]h/w#'E"@PW0#D-O%z1A%f<`[5 4& zKiv^FYs@P2w3|B*򔴼"s+Sj9r+>VA+u^e/LJ7>[s65Lʽ$B^OͨaCO"w'UEsEux`قNu }ץojNt0/H]AW;G31)ݪ;o0N,D6i"eoK*E"@Pghܵ#EG킎4[wD"D{mܐyQ'OHq3Ɔxwu]2I(I)-lVA=8EbASaT!^Ьv sܕg3s˱ -%Owka(5ו?w$0P?Knk/lL=S.[W,kE{#wu{'O>GR!o ?_19-HSD¤oV=4Y_k.o=^=4ط;{V_hX7{YvS]<o'K2E^:YVNDmY_tl12aAμV~\MvgzdrUwgT`ii^õR)ɅBõP=gy6%r3gQ`M3"HO$m?3M8ט$:E"@P(&&,{)VO}=ms|p؃h+!(vprӮWMSI/ςY8{U\Ե71Hޒ/t/M:.×⫪R'M , _?{_?/ Q (DVK[jbV[^Zuvn]kmڪz(FPQB8jBrg$}Ю!<<ߙyg}f iuFMveC_8n<9eۦBN0GZѬr`߾ݭK_wqW.*F]CoݾG)\̂'paa. L CS!{  ye<\wto!ym(<*,nLqBOuP{$aN("'=+qut^%{<9tV,L%ʮ.EQ%Ξ CZE5&޸1a x@7).?`l Äi S7+Ye2o '5U=993? @dYO4@Y5,(AhF#`0a궩[Z%s' MLеW4n"7ձF:f$GF{[G˴qs7)۽$VMK̵ӦzCAb6ؠ*^}e„iys[ m*t w6&ic7v6i ~S$Swt&cZvc)4Psfg [UTh =?4;SQF'Q+dWNWsW41~t:;5GkuR}EGw/*̠gl@~a{>_'ɸzeIa3v[V.-H?_M\Fikn쁘N`Ȓ(?ӕ֫6w[sP~ZVdV4~XؿZ@#ALw;b0F#Q28r}+ VYm TŁgppB׮^kq$2psCgh l@aP[ԪD82lgz|vuv֤#ÂBj^$M*Om>$ӯ[8xtKneDrn v=YBӅl|BUKO"m ԁ2_+<│׃Q1ݠOBLno#74)m$(7 '-бe0τ¢bih6E$E'$xг vкNά # p-: N2>b0F#om gGK䄙칲e{v\ ֣fFn1Nc2}smGQY/<$!ܥ#;ΞEd!j81E-MdR=.[ N@:b!2 p>IpEw-y T7Ou&H"l2B]!` vSvpoǎqE:QN7O}B ^Wg/YJ&8W.tCtnuo4="6 6P54A8R_Ftz'fЅϖ6T^7 98')~88$oVrH偎ƂT4YGfob0F# 3e1D|14#kha3E̬஫]^Mrr(a-:PV]BC0lG*VƶUeI#8 բ܆xu+脝9͗SRDP pi`RZj& R[]!NoѴ{_AYY Su˝q&q:h5z(5/'5XE u|ѩXcd<ל>g:)Q̂䁌AEXT asBبw$$\ToR[Rܹdդ< {Aw=u6CO]Rs!$7STxُG3#; pn.WP`"w3tk^! 7s04\)\y,?Ma%yj- /1d)yeAv9caZ>:Xr-`in,)F#`0aG9prsm6Jj$MFKmϧK]Swmc EMS( 4d !3;+yԔC6,H vN~R@ ].}4O:eĶҩbb 2'I7[B,|*D[i׊>ݛpeAOS77}ZQ'ɖzIb|^vpLǗ.?`L|ԙ^jw;,<WNv~:HDWˏѣ^GRy )--aay8v?Z?R:N`ܔ0לlji_:Iڔh_S`S8ܪ_d+ G'?jйdIݳ,FlwW@BNTK&HɥQi-aު.h3DF#`@}`]N.Г~L8h95P:}lڭ֠Vg\QD;2[YNPP 9l{Kr*R8TUۨn$ EHd<}$G^'R;%?A]c [~ tCR6z9hP7,*0f\=d۰I/ 'b??:Yh.'| R0XZNF#`0 j:7880",8QVK#b3'-ݔYNN~,;au ~y[ΩyvfO:(k,#1n$Ej~!3T^@{)Oqte sn ׃;WAÞ*%,(t灚)`M\BG] c0F#p" W ]'9p(whpp&g, ΫGA/I"gdLJb~PX)rNgQ[?#Ne#`0 C1Kbb0F#`1bkp`0F#`2Mztњ-I r(ۜm3B@c\_ gH/`0F#0ɄuOP0k.<5O>GsF_WfSs=lw/OiE3Gqh[ן#˟靦Hr=M͜w)p}M"4T*?|Xvs̔S%Ng+uXgC1h=z"XkJ6^=ǯlVdgaѝ'G#]%oh~ ʢ Pah)@FS؏aИDy-FxⵑNv l?ٯ7^9y#F#`0?.>M5(Q A;\q`O3FGD++v蚆Ʈ6.ŰYzlJbyD @ 4mM:ވi/ݔU],fa3[qؐVͳȹƃR8g!ɲa܌ډhK+jR3&ޯ^/ͽ±KgfBN~rh&}7,od^W%,s-,Kd0v6 Kqߢ=DD-hjKR7^Y6`[YlѼQc-c, f`0m+Nv-Уj*ˌ!_5yRb[>9MMNӷ]o:>P'AU-%['M<թ4)W(9jj1^uG\W%8՗7O+ s0Gx?]4zl]Ȑ0PW~xc'Ѳ|o>>1&P(ݘ 0YzAzcZ()XlqܚvO2 ȅ:@MgpɸXn_V' MLеW47ձF:f$GF.{[GQ.iba@ nS#Μx Q+&%LAR)Pvt0AZo"bP/hs2Qb+Tߤn݋ 3(mg:7_*_'hƀW d2CfRo茝9tU &mwsrR$Ow~2$c^7׼z,`YgRzfb8}nBۋMu&򼥩ӛ4FD?d;idG> GzV2OrnhKa# A,bs6[RcB<+t=׷kMf9Q8<3,+)"h `QA,U˹lT^o{Wt+"x ,kȗ:}VF3]Hs 3͌x0dx~a}Any}e{ f?7+9@k@G#wM\9Oov n.tcZn7?tyg3PCq4ipJ]b/(0f6~ة@p1s2Ƽ$%T&6Gx0U?x~^z6mx3-E'?Uki#…F#`0CB>9@c3S(.1R)+U2j6SĎ Ϙ)foGď8.=5=ޑa<$0lG:a{O=2epGp`'V}@[A'\$7ʒ3+5\{ pi(0)-5sGYhnMO#!:RO]2m#t#ar, 4^Qtv07)v㧇39<ҡ>Wp͜7L ݃B^zO4 , Y ϞΕ1G4ڌ-DaHĤyebkG gbsOʶs _5[c<+ a'U:RY ϛ9Y;CɱB9nB[ٰ&e!Gt!_'mD^+|β 6t0s:( =`TɳB&1Z. 'VI S-d 'p՞NnI%lzgzF#`0CFHLAԜap4Ni6kYs%mQӥS5uVv^q9Z,p 2rRS~6,H vN~R@ ].}4O:eĶҩbb 2'I7[B,|*D[i>Z?R:N`ܔkN6DEmʋE4ϯtɁ ]PzEk/2yȕ{TtKcP,Fl⚫wW@UCNTK .'FDďlpKގ!v {(f3vp%f_9dO~Z!/\WkaquIDsݺ5]hfe3Nj}"T4rOӎHG2o:c# M>׺ShK:3!ɖ\l0?1 CA8`0F#B@VCt@dy昒hZWbptSf1ԳY~1mi yo+Nh{r_ޖsjwf2"^׃?aOFD83;$S'WQB' #\X Q!v4!2ɤJSN{‘u9pn~yG"#`0.~8pvH~0Ȓ,] WZKUB{:jvF#`0C1!*F#`0"bU+ `0F#]fIp.Z46A}mYF iɓOr^nl'NwXF#`!@L&\E(\EYsQIxpٟ<&676iX;ڗ"Mə#NIs8-O?^ϑNNS_qk9\Ӟ&fλ*O>WM,9fÂ驒 |{ſ ~( 5,Nהl(D OrZM]r:GuK3u5MTޱeJDsu۾F]жCwBwR?)x! )[HzwyekM,`$-Z3S':!-VB򠺏7J/J'mœ.#L`0F I~%6!h;0ibx+vЈ tMCUMecWb,=6%P'AU-%['M<թ4)W(9jj1^u+\ +L+8="0hrTxHۈkVv߽Uu ƣe_ D3n_u_4_!yew)]ޱ27d0&Ko^b0F#p'pnZV+O6=k/>h&>߬oTNJ7 x9jdD"cjluG-qNI`;#92H 0+&%LARAi1+FEDq 䰣 fX+@r;Ymf-Rh@hp!8X`Wzoך̐[cN0n<^bԝ4 ڬ Cy+ (_$pe☌<͸W/utdl cxtpTʉw3&׏Ng7S:uR}Sn(o}ZgM|Ό7 Y=8':N@~;oAX?Dn-ahJ9,땯[T@QɉRhۂ=넱S";B:l5>VN,ၿd };N:>b0F#p28r}+ M@Ym TŁgppܬB@IDATvZ{ŕ># $# -=C h*fwV5$Bc20IcG^jI: {>HF6`uKGsH6nG`69T8d\Q;_(sw] z3V=_FDD4wc'Y d!j?0U Y (=ޅ}M^lfҁuFeQLL2vCò ɋ萁m%4ꐧ'J@>\b^cB'YF#`0 !ٴV/S#rL\̲=K.Z`C-)pL,12B\QTVm7C"hz_:Y/O0SXM&CಕwJ89s.M@HSS51 $c#O oBo$f袱@/o?~7]Qbfޫ#EKk97cKtBJ&8W.tr>_eQuuu+( [5 +pEm˧G\:DyOU@?Z;p$L;Ds뺏Nh]Zs{7\D|`0Ac3#,F̳^c"v|fVp.qxamw[&99yDܧ { b#eÓ7=ݥ*CЁN?Dc ٨2,#^YG^gC>7sް͠3@HH6#t4;I@5еU !bFvbf 0@=3JY6j%hj6̼O Lu*Tp`0F? h35'ł@Znnf\Imit郣Zuk.xmS&XZ˗աIBfvV?TjʡOD$srA'?)ONJ.>'2uvLbxTE1dPzUR$I͛-!l}Z"-{ k!C4I(&!.t[ʡV$iFM-}[ƍEIWV,u:7ާzNf.&P]~Dp =zڮo>^((čNP=s̜%}%UVk;h!HJK`Y/R~ ep90q痜~g9˙ MA-5n{?0F#pg0=?GlG>?wIO f|FգRGf4!ﮌd6QI"gd~PX)#uebtQ! @zncݺrR4N)#Lc/d=31N١1~x5U=͟.uczp +ff7naɩ*Mc#'NCV%+ġTdukeڏ*\`\sϗp1}:YGDC"C/F#`0FE|fZMu-[6Ѧ5Յfp#|WmW2;cn2.Ђ^dL=veOnKwބ;^) nc7v6iGyq(5w{;wՙLGkajY^\8W.;ވx`0F# 7{mpӚnPVܒ=.;V]Y^=9鎙np*_|ɼe7Bʿn`ɹ!&895:步G=c߳`{kTLDDsw7JQD:YN}G1F#`02>Ԙ汮>k4 \)9f͏ \xRҟ FھaEv 93}N&3=gVOf'?Zeki%3Md'|E+f8v R=#D}Ձ ݀tnuDCG4sͬԈʼnt`0F#Gj9l6P} fss OR&Ǣ%5߂,_1Oh~ 2ii|QXzZ,12VNjXb>gKa#Ó7nx. ɂ0eG-N.?8`0F#`i(G&})hluغ3tYY1+[  l˟Dj' !#ϥ]253W^~.?`L@bAXX8#]7gFjYV5LjM`0F#ܳA=,r MVB/(O"YlDjgӖ~0;v~`E_gK' H![CF|`0F#;Pչ`dR" 6EjsGOR 6>w&V>{55F#`0F{G#3CY΂,RuU|`0F# pQɏTr1'n˂`0F#[pRs`0F#`6ݏR<$gLbIsIhZ0A G$PW.\_׉>$<0.xP\ݝ~/'s6 N':[ ׿}2Cӏw]NGk9}}B6{9ݪU$nP|x oLz@v\d']ɽ+ʍDO^ ?dЩ;r aYR?h R\uNx%w>G{+3wIRK+lWzeբwL2o<z?FIYf:L#7P=Ӿ(4 =<zY< =l 8 `=NG{~灯 Uy珄wW]6z~ T {@y/z?9U*ߡp{ɃN2T\w?̑E%8ys{:Ц5wòӃ8LEi,9MFkާ,x֪91bpps/6GO3mhgڪ#FO9ryh.bϷ E|cen`6M߼xJ.4U9S lz SNt rfoܼW'/$zJ9_fo~ܟQ 7'Y|)\)e:P >UjK <~d_~jnJMXF2rrw'Wz[b;fY@ (eu) e~WQBG OPW7}r;_*}m&)w|WΣkJ\htG2sݖAɂXp6 ;|$e^eב7@'٧C<=iSN{jPumڎ0LFψY"cr)l{ dKW|Y4)~ m?ݝ\GG'f:\.,gY)߿u_XKn=뮯rwaǷ?+ KֻY٧6)yvSn, C}R6\Ygf~4< *,zv9I{7ҵ?t}L )1&3&Ccn^~_̴M|yީtu |O:A#'ҟ= FώL*3 d][ N e{! .mN*huٿ,c<9ܱZZ^^13X}qKNUisYcF'paa. L Erj~ط|cwR]վ Aʢ=VVq:$%['#6p -pjm&fB4rjSebC@˥{i93;{tkˌW?w.UFvR&%+٫@-;' d yΞ12heƌ\J+w:]h:MsY=_B5߉uT0#v\[2\u.?:9Hd꬇:j5}__STr`]2GLkrgxqݣX'69YYG"KxG҆,t׫$/#mfpm;<5]%]Io-Ha$'Xh^cdOuGzyӁzfuEWϨeot<'+w~גּft޲3nV:h>14 zh*?|c=NDx8$it>HN" O6ľB9䈎ÓGGkt%>ׂ3߷b]KE|K f=A[?itG3d򣗅. 4t@SF~v׍?`\?"АGFQcjW[^/Gd錑pTJq֫^l17adLtUo7ϙl8KD Uo9UE?yE;? IdN 7ڬ Cr;(||(•c2xp$-exblKi)! hGbsKS*\K ٍ+2*NE_׍'cKjRw:s 8w>8ީ*wJ 0=GW8^8W.;ވv6M~]DzP}@z 6PӃQVg2t姢up6QaP?B>5yA/2gq¨_}@#DP/O>Pd䍲M%yo,/$o;fڣ\wx'R UE63dC#}ř_ ɨJb&F Y9щ20;RTys᪌)e o|p=/s^ln˄CcěL?P?49@(Ah[hx}B]&sF ųg{ֿloh.ӽ̅LNFc69| \Yf1BLʲ_~rz~9"qGL\z D}J.Q?9O{:їw}qa*m46}Li2lG|BDO%i^mP7glˏAuMut<sGEE⯫|qeg_OH Y]4 ̚fl99 ݏ>儑sAuN Hg\ejc^k{Rt.>NV>{#@|E =!:A5G3~zcNNc:я#Y2$s v^Ҷ2Cunu>R e!B>1.[2U`yl? Adx(v&(SR-dx:Hśb M+@aUyLULNh]C.Q>CzS@[P g@!HBU,D".'cIvƤ,a?|E+f8v t}T:9I-FG$B\lIrtPZ~gF9SS~<5wNw t4:8%My>xmlyaP@WNv>$\"M|GO葒=u.ԙlzv&-I b؞>wYpʢh@1:ȏEQ  1BBWѪNd) w%p "/? OMwSb AXX8#]7go/R<3sTWWYY*&$eK @*z^T~w#,=eZ,^@Din[#4 ]1|nv~j?\^}n4Vɦψg9AUp\<9%n*:h[# F`Jݑp4+M6TuɏQ["eӴ[B\5{lUZVފY 6c~/FpAŭcfJfSnrҵM3BYxҵ*ssݘ=g$ 0,#Ghܰ0`jo{죲8uޓ'h 6M~!iM{|dp=/(?rY9H\h=)U_^qژ$ACmkC9G}vP8 1? _kjD%NH(W@4hBj4Yx\-~5ByTBC0.`B:CiX{N}as^*!+[rw+=wQfOvJ~6mi aM?wr}^JpsX UwӮmNh;s~z%QTx2 fn.5KQ]Z8y:e>__rtHşzF+KT3<}c=@]*K8rŤ8%ӷ~t zΏ\N?yz?ibsUl ׮Y=Rs"ұ?>?Y yzj3%=G< 7v#[/iցL'}m?x7.Z  'h(l.OshjϑQ=ɍGh{*SHDs{!MW4p 鏜be/'99tGD0] V;̙26C/WHDDCԝ$?)"YSPo>t3 >;lS\aR:PI *I߀u~3ZY;փk* Ak٧ G[G4{ҥErBs/&WSwV}øGǓ^X-ywk\?+da:>d/?\: GNICf?M^I@V~\=j-|9Yc9HGu%|Fv|(ArH1Nܴ~'LSF2 Rxzq×w@Z:d'5;uN-{  J.Neg|pL?N҆2G`0F# =V #`0F#p! {HBF#`0k9}ߛO8F#`0FZq ԝ9Pp|F#`0$۔쿬ϟ\d29xe?&7]aբ]9mJgpig\nju'Ι2fɮ⟛>xދb0F#`0A`(lIwPm9O[/{0flld4A6&,"Z6ĦZ R-.jjN*[?"(@H$v$ D $=9$dfN /]?=3w̌jzB1     {`Dž!k}wngIS^&?x&;<!!x޿| ߴh^Eb @@NnҢJ.9ܫo'~0V]Bm뛋w<(!WNg؞O;kj^΄g)繿ƼE_:9fܯkDz92E)UG h+rO9"  :"*MӳEEEt1?B&d~M2!c}5Y ~TXfS߄ ^~S1ŎٳcHMBm(➙ݪ2WG~bϒ?>=7y, 9yc۰AnjX2Y<]뙳`M5 a}BgH<]s_JKlzYumks|_lh>&>hxl|G=3<.'௵5^V}~>yϯ 4#w<<{efeF6 <90mvxWYgS^Ӫn); î 3mfamկ:ؤCLƈ2$جe[cf|IeYf{I]1\1/c`Ѩ/(b<]IH+a#o̐Œk~6r&~W_jx=j@\jz<^Z{:#1^is8d/u zy\_@Ǻ1?k};D}cg5OfŤcgEucVdc ~'yC8*įx|`Hh`͋w.ײbۻO|)=CVoɘ GO~0vi4\B)a~* 1Mk#U˜ԇ^ u^O~݋^+h. 3Jg6ku}/|pЫOԡOy'2ҫ1>c׾+Տ葳 yk (d'Ψ׽/=ת_v {qҜrVcVT3Oe1C/FEbK޿SKLsp̛񋽝^ne5kW98%yBJW'?ܱI"yy(`ü_ Owl}a}lj|_\NXﻱz7rIr}X;&k&ɇmVO|]܆1rKJCC<݇ ߫+rx;uimWɱ޿g%dz1Uky{W3f{`pi[_O{ɏѱC7Ϳg۟v7y2O,koŘk1Uwૹ jj9ާ({ 2;zodO}xSh# ͬ\{;wd>YY}'Ho/w))bYBB6o,$K!ufnv{ xkr?wL992@lx`odܸ+cdU/[ses,KEDدf-Y桭ܲPy-ڞO:M>=ַ>|d+o1֡AcqupGQ"~C3Gǔ4{7mڛ=|t|ڥIhhpܶE;ڴ];osXy՘3}+=s{VejzbO&\|#cT7{jߗU;_YHemƈS8ݓL}\}97h_Y~Ȍww>-OW3. r6[Mhƈ{6K/X`IJ=gw9B^n뎭lm䋾aL]ZUbZ1۲8{w5 ru[#hߟ.+w@DL?[?с}z;V>Ҟzxﶫ9Yj,5WP~;՘իVwc+{[2uu{3&{Ƿ%{u gÞr>/cZb_)AoY;>VyfZrHK{%\QkG_Hgg߯WΟ_yE"bf T+;vĸ]5D׿MwE?S0ҀrO,.m?śB]#"T.SY^^=L|ç^):,XX˭9D7i[gxysl蒢²QGڜGSmf);U>h7Pl$?\sL gVbs:-_G."}bgߨkf9pTy$؝j<ݷ{U,VnwcFtvZ%Ӿ'ܫ7*Z}wǚ~#!\$e%̊wؙwFmch?1eP^瑴7O܆^9̲~cv|'L^Vc:k:۶GwJJ] a yHtk~<2` ɻzxlרw:QE|ݿ'Ə\jJri\.H^3CZ74>}$;WއEw]*f@IDATky:<[|p6j%׶G?ԠYm6:m?kYc_x~p))U֩6ȃ_˞lOr?g_=5y̟<_yؾZx>vnk<<7&>>Ȗ\.=K4>)JѶ㮍I{ ԳspIyޖ}m{C u)"OoQ̲uL"nx#C w˕G,MZ"4y̕U^yYYg<]}Ω_5/W^uj9-Q/f_sw=W ?i/糟o@y#O uD~ˈaS;a-dOnoj^}#-unEJsB6PMO'*l=cm)D 1`Hk+?7iKGx\N޿Qbu}z޷ 4qkg\>!v{.L~D䤸8Elᯏ幀yvf Vc:cE=Fu~di:A\C> WCZ?>˩Fٹ z?wvo-?o|QUo+iyG6QM|>r9mp-kح'a=kh04@9/z̈1{]y`MVk~}xi2(8,,]Q=f1eOɓg}7 яs&5OrsLܗCQKxYFYh|x/dz0jqͻjStΛ;w!C~n"~dpt^[x>#!ޟ7Sy:P}sڹ1 n/h#Q!*Ζ8wNһp5}[T/y΄g)ƼuE-K7sl̟T'}rtي"*uSݺB$횞ysA"T~{s叞Xէs_v|qYge+]{Z'|Z_ o+rO^ʣ|,XfHxw2kKof/v3}c Kdgiyyee:eY)|XxkoV>i/D>HmdqaQUTuAWgjsCey.djxqCb7z\9w_J:ϼ}bXv׮ߎӷYe:UͿ!j+K<>m`oWeޛӹGcѼ^߾s=j\]?QKUԺ> |K!|oclfo}s*w^?bů>?YiuߴzUkƴhӮc^9/nP=:#Wu|>YszLju_p{_zd= %VW#Ih9)vߓIQ.\DȏeXb(9nArӞ_nN\ɕ$ sMuO͓/vxy(&{:o6Xv,=nS᭶޳w\K׮/{^[}Ӷ9^哚|,Df\Wm>ȏAˇ(_o׶G=VYFp4K8׺jsZ:R 뀻z7yzK rc?e.YU]g5bzYjkwerڏז3j <1'.־wgz3䬩ܫ>l{wxl"fLq`}e˶%{<ޞ~ GĎ FqLgMXb۽{.\s1bLe!Ě0ڳ89ri\g<Z[[3w5}_B'2J>G^+tF"B1Gi/ʓ;  E)c|o((@@.^ o6cF .ޚ4▩2F4   ` !x{?3#Ùt7wع%]^kʗc{)49/{3˜@I q .[[}s[J@@ K); î 3mfamz"Jygrz&L T+h!ucD@zQd lֲ^՘v_Yqc'[j~cG-c&vuo߿- @@0_SD̲jYpᬸe%e}MYTy27~a=IYv_>-.zO߷KĦi#4j@sݴ6b\u^~HH^LDXtΐKޱ_!Œ홁' m{yz*jVwU'zWsXrikUЯGw8i^ЫOԡOy'2|~5Eum-+<:Q~Ehb)SbENx  pqNg; )bYBB6o,$#D>]rSzU?#v{ xkr?wLy*_6n<72nܕ1r5o M&88H]kZr7 ~$448T׶hG[ym[uRd+oi֡ZQ}SڡC?qÜMOݖZb>  &,zx{W?mڙǴy%?;^(G5lɣ8yg_ujHls@yoi@I\YvʲO(5Oxw~iuN ?g.Mcɥp _gqZ zw˭9G}?x噴1A:6iZܠ3٩'?t<}8" \TUM[}jթ5j򌑍ػmю׋@QvMNax2{y+v_zPEy6cKӰ@qVfZܽT1Ge%Vشh^Ebs-~?bx?ḎNw'}?iGyKQ?!@@0/uvXnCɋL}`Q}wXǥ0;ە1~Ș"HQLJe:xr/p+<*/c'V7jvĘ;SNmeyaDJ.{dԖ]/~q  E'`H#G&[F ߵtFrvzה I9V7~nqì7|]Ot. [M93cuՌ{,79ow?et|?^[ m&LK))|b}4iҔɗ6r@Vo=بMԋ6=o zie4vr_R[&@@V?*Z9wy@1}[T/yZ΄g-_M5m(,R T":y3yH}]"i̛ 2jөwp_kWfa۾-0NZSWMgz弸{7wuzb,-/,:]r֐<,/'W;\~6Py_dv&|&|o@@D@u\c;DN=]}_SX.q!=yeW"mAz78@@rrrZj%l6㟷<5'h|v?@@.__yԁD@@84$  @ 7%#!  ph{ H@@oڻe{߼ƌ;KEu;OЧD ϛ}\}CݥEP")a~WÅ27~a=IYv_>c,W\/;qv[^^?͔wf;ٗ?{Ft)wH^sUˮj?.lVYVy~*2<{,Vy7??V݌NjZ.eBԞݩǦ.]"/=~vva;;扨x$~<{΄  pT?e.n;&Vzll;m^njDH}4+&ᱠ~7^zs܋˄jKݑOvT7Z*uph;`jؼUQgτI&ύ_uC{gbjOVyVv{lXl;c[}]̹q%EJs]?d83JŇLm'skR"vJQ^R1$;VPrCˮ[ms^`P@"CBuMHHPٲsOe/ ) ,8ө]Gif5f׺[,18bO=V[<UAy1%WǼ!scZ_~s:#ų?[ٿٲ{vΎ J%Guy.yu}|sYp @@ޛ9w/=lVKEjeԌU#Z{e:#~زW~jcfF=w|{XR'uY| '}'Qa}^x=y2+eiK8='*Z\&Xo$Sg>.a!vL;6/?g E9p:@֖=W.Đ"sW♣*_[*Y꘼y㵓sᆱ_=嵝,#홺acu|znrKf(*>U d#vc.^GҬyV[F޶,%Э/l|w @@ xo~p6a}GU7;2Wi~"DA;}S2yٹ`d8!DPPk߾<Ԟaa"Dr q⧹zJLn\_|Q sz6J$SI*3u1, T5M^/, 7tE媂|漪wdDwk+t/_ձh]wyK򝇦O:۪bԜzbAlLe<ƭu1Ks͸<ęTQ@%Ρ M!UvۘW6K  뫝K=y>vz$GL^V=hbGn}yl8"q =C ]ϭݠm-܀  PGyK,5Lj؉^8Med|mpSg8GloJ6a_~zU4N1!`q]lyN7^i:7}[;הV?ͦ1 )ߋٳ=$/U=O25M#vԍV[Ι8ZA7 .y< .(g#Uuqfyo?\-s0S+B' @W]gpmѱ}ߝ:r,~HsyKK"SzSV{|;~mk/M8yjb *VXǮ/ ϘU^.\U.׷䈗yS'*yjNj]KNNv7t$os  pĵjJ~InW}SAAu+gY6EK unscgK;w{5fHr{FW14˛scLټyv@@oUYj=[/i=gbf8*rv61ϯkG@hzNi50  \4ƈ 8+" 1޿&ӘH@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@MrIDAT@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@|-b@@0\  :4:Z"  ` "=@@thuE@@p| Dz  h  4@@"@@h /!  #@E,   ^ C@@@G_GX@@ 7@    .@oxH@@ lXq   p >}φE@@-|wS{^i   \@V_@A   pXN*y6H!   vժ"%E@@!e˖-:PR @@.Zje˖}{viIENDB`node-gulp-4.0.2+~cs38.20.35/docs/writing-a-plugin/000077500000000000000000000000001415667007300211655ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/docs/writing-a-plugin/README.md000066400000000000000000000172671415667007300224610ustar00rootroot00000000000000# Writing a plugin If you plan to create your own Gulp plugin, you will save time by reading the full documentation. * [Guidelines](guidelines.md) (a MUST read) * [Using buffers](using-buffers.md) * [Dealing with streams](dealing-with-streams.md) * [Testing](testing.md) ## What it does ### Streaming file objects A gulp plugin always returns a stream in [object mode](https://nodejs.org/api/stream.html#stream_object_mode) that does the following: 1. Takes in [vinyl File objects](https://github.com/gulpjs/vinyl) 2. Outputs [vinyl File objects](https://github.com/gulpjs/vinyl) (via `transform.push()` and/or the plugin's callback function) These are known as [transform streams](https://nodejs.org/api/stream.html#stream_class_stream_transform_1) (also sometimes called through streams). Transform streams are streams that are readable and writable; they manipulate objects as they're being passed through. All gulp plugins essentially boil down to this: ```js var Transform = require('stream').Transform; module.exports = function() { // Monkey patch Transform or create your own subclass, // implementing `_transform()` and optionally `_flush()` var transformStream = new Transform({objectMode: true}); /** * @param {Buffer|string} file * @param {string=} encoding - ignored if file contains a Buffer * @param {function(Error, object)} callback - Call this function (optionally with an * error argument and data) when you are done processing the supplied chunk. */ transformStream._transform = function(file, encoding, callback) { var error = null, output = doSomethingWithTheFile(file); callback(error, output); }; return transformStream; }; ``` Alternatively you could pass your transform and flush functions to the `Transform` constructor or even extend `Transform` with ES6 classes, as described by the [Node.js docs](https://nodejs.org/docs/latest/api/stream.html#stream_implementing_a_transform_stream). However, many plugins prefer to use the [through2](https://github.com/rvagg/through2/) module to simplify their code: ```js var through = require('through2'); // npm install --save through2 module.exports = function() { return through.obj(function(file, encoding, callback) { callback(null, doSomethingWithTheFile(file)); }); }; ``` The stream returned from `through()` (and `this` within your transform function) is an instance of the [Transform](https://github.com/iojs/readable-stream/blob/master/lib/_stream_transform.js) class, which extends [Duplex](https://github.com/iojs/readable-stream/blob/master/lib/_stream_duplex.js), [Readable](https://github.com/iojs/readable-stream/blob/master/lib/_stream_readable.js) (and parasitically from Writable) and ultimately [Stream](https://nodejs.org/api/stream.html). If you need to parse additional options, you can call the `through()` function directly: ```js return through({objectMode: true /* other options... */}, function(file, encoding, callback) { ... ``` Supported options include: * highWaterMark (defaults to 16) * defaultEncoding (defaults to 'utf8') * encoding - 'utf8', 'base64', 'utf16le', 'ucs2' etc. If specified, a [StringDecoder](https://github.com/rvagg/string_decoder/blob/master/index.js) `decoder` will be attached to the stream. * readable {boolean} * writable {boolean} * allowHalfOpen {boolean} If set to false, then the stream will automatically end the readable side when the writable side ends and vice versa. ### Modifying file content The function parameter that you pass to `through.obj()` is a [_transform](https://nodejs.org/api/stream.html#stream_transform_transform_chunk_encoding_callback) function which will operate on the input `file`. You may also provide an optional [_flush](https://nodejs.org/api/stream.html#stream_transform_flush_callback) function if you need to emit a bit more data at the end of the stream. From within your transform function call `this.push(file)` 0 or more times to pass along transformed/cloned files. You don't need to call `this.push(file)` if you provide all output to the `callback()` function. Call the `callback` function only when the current file (stream/buffer) is completely consumed. If an error is encountered, pass it as the first argument to the callback, otherwise set it to null. If you have passed all output data to `this.push()` you can omit the second argument to the callback. Generally, a gulp plugin would update `file.contents` and then choose to either: - call `callback(null, file)` _or_ - make one call to `this.push(file)` If a plugin creates multiple files from a single input file, it would make multiple calls to `this.push()` - eg: ```js module.exports = function() { /** * @this {Transform} */ var transform = function(file, encoding, callback) { var files = splitFile(file); this.push(files[0]); this.push(files[1]); callback(); }; return through.obj(transform); }; ``` The [gulp-unzip](https://github.com/suisho/gulp-unzip/blob/master/index.js) plugin provides a good example of making multiple calls to `push()`. It also uses a chunk transform stream with a `_flush()` function _within_ the Vinyl transform function. Vinyl files can have 3 possible forms for the contents attribute: - [Streams](dealing-with-streams.md) - [Buffers](using-buffers.md) - Empty (null) - Useful for things like rimraf, clean, where contents is not needed. A simple example showing how to detect & handle each form is provided below, for a more detailed explanation of each approach follow the links above. ```js var PluginError = require('plugin-error'); // consts var PLUGIN_NAME = 'gulp-example'; module.exports = function() { return through.obj(function(file, encoding, callback) { if (file.isNull()) { // nothing to do return callback(null, file); } if (file.isStream()) { // file.contents is a Stream - https://nodejs.org/api/stream.html this.emit('error', new PluginError(PLUGIN_NAME, 'Streams not supported!')); // or, if you can handle Streams: //file.contents = file.contents.pipe(... //return callback(null, file); } else if (file.isBuffer()) { // file.contents is a Buffer - https://nodejs.org/api/buffer.html this.emit('error', new PluginError(PLUGIN_NAME, 'Buffers not supported!')); // or, if you can handle Buffers: //file.contents = ... //return callback(null, file); } }); }; ``` Note: When looking through the code of other gulp plugins (and the example above), you may notice that the transform functions will return the result of the callback: ```js return callback(null, file); ``` ...don't be confused - gulp ignores any return value of your transform function. The code above is simply a short-hand form of: ```js if (someCondition) { callback(null, file); return; } // further execution... ``` ## Useful resources * [File object](https://github.com/gulpjs/vinyl) * [PluginError](https://github.com/gulpjs/plugin-error) * [through2](https://www.npmjs.com/package/through2) * [bufferstreams](https://www.npmjs.com/package/bufferstreams) ## Sample plugins * [sindresorhus' gulp plugins](https://github.com/search?q=%40sindresorhus+gulp-) * [contra's gulp plugins](https://github.com/search?q=%40contra+gulp-) * [gulp-replace](https://github.com/lazd/gulp-replace) ## About streams If you're unfamiliar with streams, you will need to read up on them: * https://github.com/substack/stream-handbook (a MUST read) * https://nodejs.org/api/stream.html Other libraries that are not file manipulating through streams but are made for use with gulp are tagged with the [gulpfriendly](https://npmjs.org/browse/keyword/gulpfriendly) keyword on npm. node-gulp-4.0.2+~cs38.20.35/docs/writing-a-plugin/dealing-with-streams.md000066400000000000000000000043451415667007300255450ustar00rootroot00000000000000# Dealing with streams > It is highly recommended to write plugins supporting streams. Here is some information on creating a gulp plugin that supports streams. > Make sure to follow the best practices regarding error handling and add a line that makes the gulp plugin re-emit the first error caught during the transformation of the content. [Writing a Plugin](README.md) > Writing stream based plugins ## Dealing with streams Let's implement a plugin prepending some text to files. This plugin supports all possible forms of `file.contents`. ```js var through = require('through2'); var PluginError = require('plugin-error'); // consts const PLUGIN_NAME = 'gulp-prefixer'; function prefixStream(prefixText) { var stream = through(); stream.write(prefixText); return stream; } // plugin level function (dealing with files) function gulpPrefixer(prefixText) { if (!prefixText) { throw new PluginError(PLUGIN_NAME, 'Missing prefix text!'); } prefixText = new Buffer(prefixText); // allocate ahead of time // creating a stream through which each file will pass var stream = through.obj(function(file, enc, cb) { if (file.isBuffer()) { this.emit('error', new PluginError(PLUGIN_NAME, 'Buffers not supported!')); return cb(); } if (file.isStream()) { // define the streamer that will transform the content var streamer = prefixStream(prefixText); // catch errors from the streamer and emit a gulp plugin error streamer.on('error', this.emit.bind(this, 'error')); // start the transformation file.contents = file.contents.pipe(streamer); } // make sure the file goes through the next gulp plugin this.push(file); // tell the stream engine that we are done with this file cb(); }); // returning the file stream return stream; } // exporting the plugin main function module.exports = gulpPrefixer; ``` The above plugin can be used like this: ```js var gulp = require('gulp'); var gulpPrefixer = require('gulp-prefixer'); gulp.src('files/**/*.js', { buffer: false }) .pipe(gulpPrefixer('prepended string')) .pipe(gulp.dest('modified-files')); ``` ## Some plugins using streams * [gulp-svgicons2svgfont](https://github.com/nfroidure/gulp-svgiconstosvgfont) node-gulp-4.0.2+~cs38.20.35/docs/writing-a-plugin/guidelines.md000066400000000000000000000135021415667007300236400ustar00rootroot00000000000000# Guidelines > While these guidelines are totally optional, we **HIGHLY** recommend that everyone follows them. Nobody wants to use a bad plugin. These guidelines will actually help make your life easier by giving you assurance that your plugin fits well within gulp. [Writing a Plugin](README.md) > Guidelines 1. Your plugin should not do something that can be done easily with an existing node module - For example: deleting a folder does not need to be a gulp plugin. Use a module like [del](https://github.com/sindresorhus/del) within a task instead. - Wrapping every possible thing just for the sake of wrapping it will pollute the ecosystem with low quality plugins that don't make sense within the gulp paradigm. - gulp plugins are for file-based operations! If you find yourself shoehorning a complex process into streams just make a normal node module instead. - A good example of a gulp plugin would be something like gulp-coffee. The coffee-script module does not work with Vinyl out of the box, so we wrap it to add this functionality and abstract away pain points to make it work well within gulp. 1. Your plugin should only do **one thing**, and do it well. - Avoid config options that make your plugin do completely different tasks - For example: A JS minification plugin should not have an option that adds a header as well 1. Your plugin shouldn't do things that other plugins are responsible for - It should not concat, [gulp-concat](https://github.com/contra/gulp-concat) does that - It should not add headers, [gulp-header](https://www.npmjs.com/package/gulp-header) does that - It should not add footers, [gulp-footer](https://www.npmjs.com/package/gulp-footer) does that - If it's a common but optional use case, document that your plugin is often used with another plugin - Make use of other plugins within your plugin! This reduces the amount of code you have to write and ensures a stable ecosystem. 1. Your plugin **must be tested** - Testing a gulp plugin is easy, you don't even need gulp to test it - Look at other plugins for examples 1. Add `gulpplugin` as a keyword in your `package.json` so you show up on our search 1. Your plugin API should be a function that returns a stream - If you need to store state somewhere, do it internally - If you need to pass state/options between plugins, tack it on the file object 1. Do not throw errors inside a stream - Instead, you should emit it as an **error** event. - If you encounter an error **outside** the stream, such as invalid configuration while creating the stream, you may throw it. 1. Prefix any errors with the name of your plugin - For example: `gulp-replace: Cannot do regexp replace on a stream` - Use [PluginError](https://github.com/gulpjs/plugin-error) module to make this easy 1. Name your plugin appropriately: it should begin with "gulp-" if it is a gulp plugin - If it is not a gulp plugin, it should not begin with "gulp-" 1. The type of `file.contents` should always be the same going out as it was when it came in - If file.contents is null (non-read) just ignore the file and pass it along - If file.contents is a Stream and you don't support that just emit an error - Do not buffer a stream to shoehorn your plugin to work with streams. This will cause horrible things to happen. 1. Do not pass the `file` object downstream until you are done with it 1. Use [`file.clone()`](https://github.com/gulpjs/vinyl#clone) when cloning a file or creating a new one based on a file. 1. Use modules from our [recommended modules page](recommended-modules.md) to make your life easier 1. Do NOT require `gulp` as a dependency or peerDependency in your plugin - Using gulp to test or automate your plugin workflow is totally cool, just make sure you put it as a devDependency - Requiring gulp as a dependency of your plugin means that anyone who installs your plugin is also installing a new gulp and its entire dependency tree. - There is no reason you should be using gulp within your actual plugin code. If you find yourself doing this open an issue so we can help you out. ## Why are these guidelines so strict? gulp aims to be simple for users. By providing strict guidelines we are able to provide a consistent and high-quality ecosystem for everyone. While this does add a little more work and thought for plugin authors, it removes a lot of problems later down the road. ### What happens if I don't follow them? npm is open for everyone, and you are free to make whatever you want but these guidelines were prescribed for a reason. There are acceptance tests coming soon that will be integrated into the plugin search. If you fail to adhere to the plugin guidelines it will be publicly visible/sortable via a scoring system. People will always prefer to use plugins that match "the gulp way". ### What does a good plugin look like? ```js // through2 is a thin wrapper around node transform streams var through = require('through2'); var PluginError = require('plugin-error'); // Consts const PLUGIN_NAME = 'gulp-prefixer'; function prefixStream(prefixText) { var stream = through(); stream.write(prefixText); return stream; } // Plugin level function(dealing with files) function gulpPrefixer(prefixText) { if (!prefixText) { throw new PluginError(PLUGIN_NAME, 'Missing prefix text!'); } prefixText = new Buffer(prefixText); // allocate ahead of time // Creating a stream through which each file will pass return through.obj(function(file, enc, cb) { if (file.isNull()) { // return empty file return cb(null, file); } if (file.isBuffer()) { file.contents = Buffer.concat([prefixText, file.contents]); } if (file.isStream()) { file.contents = file.contents.pipe(prefixStream(prefixText)); } cb(null, file); }); } // Exporting the plugin main function module.exports = gulpPrefixer; ``` node-gulp-4.0.2+~cs38.20.35/docs/writing-a-plugin/recommended-modules.md000066400000000000000000000010761415667007300254430ustar00rootroot00000000000000# Recommended Modules > Sticking to this curated list of recommended modules will make sure you don't violate the plugin guidelines and ensure consistency across plugins. [Writing a Plugin](README.md) > Recommended Modules #### Replacing a file extension Use [replace-ext](https://github.com/wearefractal/replace-ext) #### Errors Use [plugin-error](https://github.com/gulpjs/plugin-error) #### String colors Use [chalk](https://github.com/sindresorhus/chalk) #### Date formatting Use [dateformat](https://github.com/felixge/node-dateformat) Display as `HH:MM:ss` node-gulp-4.0.2+~cs38.20.35/docs/writing-a-plugin/testing.md000066400000000000000000000051161415667007300231670ustar00rootroot00000000000000# Testing > Testing your plugin is the only way to ensure quality. It brings confidence to your users and makes your life easier. [Writing a Plugin](README.md) > Testing ## Tooling Most plugins use [mocha](https://github.com/mochajs/mocha), [should](https://github.com/shouldjs/should.js) and [event-stream](https://github.com/dominictarr/event-stream) to help them test. The following examples will use these tools. ## Testing plugins for streaming mode ```js var assert = require('assert'); var es = require('event-stream'); var File = require('vinyl'); var prefixer = require('../'); describe('gulp-prefixer', function() { describe('in streaming mode', function() { it('should prepend text', function(done) { // create the fake file var fakeFile = new File({ contents: es.readArray(['stream', 'with', 'those', 'contents']) }); // Create a prefixer plugin stream var myPrefixer = prefixer('prependthis'); // write the fake file to it myPrefixer.write(fakeFile); // wait for the file to come back out myPrefixer.once('data', function(file) { // make sure it came out the same way it went in assert(file.isStream()); // buffer the contents to make sure it got prepended to file.contents.pipe(es.wait(function(err, data) { // check the contents assert.equal(data, 'prependthisstreamwiththosecontents'); done(); })); }); }); }); }); ``` ## Testing plugins for buffer mode ```js var assert = require('assert'); var es = require('event-stream'); var File = require('vinyl'); var prefixer = require('../'); describe('gulp-prefixer', function() { describe('in buffer mode', function() { it('should prepend text', function(done) { // create the fake file var fakeFile = new File({ contents: new Buffer('abufferwiththiscontent') }); // Create a prefixer plugin stream var myPrefixer = prefixer('prependthis'); // write the fake file to it myPrefixer.write(fakeFile); // wait for the file to come back out myPrefixer.once('data', function(file) { // make sure it came out the same way it went in assert(file.isBuffer()); // check the contents assert.equal(file.contents.toString('utf8'), 'prependthisabufferwiththiscontent'); done(); }); }); }); }); ``` ## Some plugins with high-quality Testing * [gulp-cat](https://github.com/ben-eb/gulp-cat/blob/master/test.js) * [gulp-concat](https://github.com/contra/gulp-concat/blob/master/test/main.js) node-gulp-4.0.2+~cs38.20.35/docs/writing-a-plugin/using-buffers.md000066400000000000000000000040421415667007300242660ustar00rootroot00000000000000# Using buffers > Here is some information on creating gulp plugin that manipulates buffers. [Writing a Plugin](README.md) > Using buffers ## Using buffers If your plugin is relying on a buffer based library, you will probably choose to base your plugin around file.contents as a buffer. Let's implement a plugin prepending some text to files: ```js var through = require('through2'); var PluginError = require('plugin-error'); // consts const PLUGIN_NAME = 'gulp-prefixer'; // plugin level function (dealing with files) function gulpPrefixer(prefixText) { if (!prefixText) { throw new PluginError(PLUGIN_NAME, 'Missing prefix text!'); } prefixText = new Buffer(prefixText); // allocate ahead of time // creating a stream through which each file will pass var stream = through.obj(function(file, enc, cb) { if (file.isStream()) { this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!')); return cb(); } if (file.isBuffer()) { file.contents = Buffer.concat([prefixText, file.contents]); } // make sure the file goes through the next gulp plugin this.push(file); // tell the stream engine that we are done with this file cb(); }); // returning the file stream return stream; }; // exporting the plugin main function module.exports = gulpPrefixer; ``` The above plugin can be used like this: ```js var gulp = require('gulp'); var gulpPrefixer = require('gulp-prefixer'); gulp.src('files/**/*.js') .pipe(gulpPrefixer('prepended string')) .pipe(gulp.dest('modified-files')); ``` ## Handling streams Unfortunately, the above plugin will error when using gulp.src in non-buffered (streaming) mode. You should support streams too if possible. See [Dealing with streams](dealing-with-streams.md) for more information. ## Some plugins based on buffers * [gulp-coffee](https://github.com/contra/gulp-coffee) * [gulp-svgmin](https://github.com/ben-eb/gulp-svgmin) * [gulp-marked](https://github.com/lmtm/gulp-marked) * [gulp-svg2ttf](https://github.com/nfroidure/gulp-svg2ttf) node-gulp-4.0.2+~cs38.20.35/index.js000066400000000000000000000026161415667007300165120ustar00rootroot00000000000000'use strict'; var util = require('util'); var Undertaker = require('undertaker'); var vfs = require('vinyl-fs'); var watch = require('glob-watcher'); function Gulp() { Undertaker.call(this); // Bind the functions for destructuring this.watch = this.watch.bind(this); this.task = this.task.bind(this); this.series = this.series.bind(this); this.parallel = this.parallel.bind(this); this.registry = this.registry.bind(this); this.tree = this.tree.bind(this); this.lastRun = this.lastRun.bind(this); this.src = this.src.bind(this); this.dest = this.dest.bind(this); this.symlink = this.symlink.bind(this); } util.inherits(Gulp, Undertaker); Gulp.prototype.src = vfs.src; Gulp.prototype.dest = vfs.dest; Gulp.prototype.symlink = vfs.symlink; Gulp.prototype.watch = function(glob, opt, task) { if (typeof opt === 'string' || typeof task === 'string' || Array.isArray(opt) || Array.isArray(task)) { throw new Error('watching ' + glob + ': watch task has to be ' + 'a function (optionally generated by using gulp.parallel ' + 'or gulp.series)'); } if (typeof opt === 'function') { task = opt; opt = {}; } opt = opt || {}; var fn; if (typeof task === 'function') { fn = this.parallel(task); } return watch(glob, opt, fn); }; // Let people use this class from our instance Gulp.prototype.Gulp = Gulp; var inst = new Gulp(); module.exports = inst; node-gulp-4.0.2+~cs38.20.35/package.json000066400000000000000000000024731415667007300173340ustar00rootroot00000000000000{ "name": "gulp", "version": "4.0.2", "description": "The streaming build system.", "homepage": "https://gulpjs.com", "author": "Gulp Team (https://gulpjs.com/)", "contributors": [ "Eric Schoffstall ", "Blaine Bublitz " ], "repository": "gulpjs/gulp", "license": "MIT", "engines": { "node": ">= 0.10" }, "main": "index.js", "files": [ "LICENSE", "index.js", "bin" ], "bin": { "gulp": "./bin/gulp.js" }, "scripts": { "lint": "eslint .", "pretest": "npm run lint", "test": "nyc mocha --async-only", "azure-pipelines": "nyc mocha --async-only --reporter xunit -O output=test.xunit", "coveralls": "nyc report --reporter=text-lcov | coveralls" }, "dependencies": { "glob-watcher": "^5.0.3", "gulp-cli": "^2.2.0", "undertaker": "^1.2.1", "vinyl-fs": "^3.0.0" }, "devDependencies": { "coveralls": "github:phated/node-coveralls#2.x", "eslint": "^2.13.1", "eslint-config-gulp": "^3.0.1", "expect": "^1.20.2", "mkdirp": "^0.5.1", "mocha": "^3.0.0", "nyc": "^10.3.2", "rimraf": "^2.6.3" }, "keywords": [ "build", "stream", "system", "make", "tool", "asset", "pipeline", "series", "parallel", "streaming" ] } node-gulp-4.0.2+~cs38.20.35/test/000077500000000000000000000000001415667007300160175ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/test/.eslintrc000066400000000000000000000000351415667007300176410ustar00rootroot00000000000000{ "extends": "gulp/test" } node-gulp-4.0.2+~cs38.20.35/test/dest.js000066400000000000000000000103431415667007300173150ustar00rootroot00000000000000'use strict'; var fs = require('fs'); var path = require('path'); var expect = require('expect'); var rimraf = require('rimraf'); var gulp = require('../'); var outpath = path.join(__dirname, './out-fixtures'); describe('gulp.dest()', function() { beforeEach(rimraf.bind(null, outpath)); afterEach(rimraf.bind(null, outpath)); it('should return a stream', function(done) { var stream = gulp.dest(path.join(__dirname, './fixtures/')); expect(stream).toExist(); expect(stream.on).toExist(); done(); }); it('should return a output stream that writes files', function(done) { var instream = gulp.src('./fixtures/**/*.txt', { cwd: __dirname }); var outstream = gulp.dest(outpath); instream.pipe(outstream); outstream.on('error', done); outstream.on('data', function(file) { // Data should be re-emitted right expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toExist(); expect(file.path).toEqual(path.join(outpath, './copy/example.txt')); expect(file.contents).toEqual('this is a test'); }); outstream.on('end', function() { fs.readFile(path.join(outpath, 'copy', 'example.txt'), function(err, contents) { expect(err).toNotExist(); expect(contents).toExist(); expect(contents).toEqual('this is a test'); done(); }); }); }); it('should return a output stream that does not write non-read files', function(done) { var instream = gulp.src('./fixtures/**/*.txt', { read: false, cwd: __dirname }); var outstream = gulp.dest(outpath); instream.pipe(outstream); outstream.on('error', done); outstream.on('data', function(file) { // Data should be re-emitted right expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toNotExist(); expect(file.path).toEqual(path.join(outpath, './copy/example.txt')); }); outstream.on('end', function() { fs.readFile(path.join(outpath, 'copy', 'example.txt'), function(err, contents) { expect(err).toExist(); expect(contents).toNotExist(); done(); }); }); }); it('should return a output stream that writes streaming files', function(done) { var instream = gulp.src('./fixtures/**/*.txt', { buffer: false, cwd: __dirname }); var outstream = instream.pipe(gulp.dest(outpath)); outstream.on('error', done); outstream.on('data', function(file) { // Data should be re-emitted right expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toExist(); expect(file.path).toEqual(path.join(outpath, './copy/example.txt')); }); outstream.on('end', function() { fs.readFile(path.join(outpath, 'copy', 'example.txt'), function(err, contents) { expect(err).toNotExist(); expect(contents).toExist(); expect(contents).toEqual('this is a test'); done(); }); }); }); it('should return a output stream that writes streaming files into new directories', function(done) { testWriteDir({ cwd: __dirname }, done); }); it('should return a output stream that writes streaming files into new directories (buffer: false)', function(done) { testWriteDir({ buffer: false, cwd: __dirname }, done); }); it('should return a output stream that writes streaming files into new directories (read: false)', function(done) { testWriteDir({ read: false, cwd: __dirname }, done); }); it('should return a output stream that writes streaming files into new directories (read: false, buffer: false)', function(done) { testWriteDir({ buffer: false, read: false, cwd: __dirname }, done); }); function testWriteDir(srcOptions, done) { var instream = gulp.src('./fixtures/stuff', srcOptions); var outstream = instream.pipe(gulp.dest(outpath)); outstream.on('error', done); outstream.on('data', function(file) { // Data should be re-emitted right expect(file).toExist(); expect(file.path).toExist(); expect(file.path).toEqual(path.join(outpath, './stuff')); }); outstream.on('end', function() { fs.exists(path.join(outpath, 'stuff'), function(exists) { expect(exists).toExist(); done(); }); }); } }); node-gulp-4.0.2+~cs38.20.35/test/fixtures/000077500000000000000000000000001415667007300176705ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/test/fixtures/copy/000077500000000000000000000000001415667007300206425ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/test/fixtures/copy/example.txt000066400000000000000000000000161415667007300230330ustar00rootroot00000000000000this is a testnode-gulp-4.0.2+~cs38.20.35/test/fixtures/stuff/000077500000000000000000000000001415667007300210175ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/test/fixtures/stuff/run.dmc000066400000000000000000000000001415667007300222760ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/test/fixtures/stuff/test.dmc000066400000000000000000000000001415667007300224510ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/test/fixtures/test.coffee000066400000000000000000000000161415667007300220150ustar00rootroot00000000000000this is a testnode-gulp-4.0.2+~cs38.20.35/test/fixtures/test/000077500000000000000000000000001415667007300206475ustar00rootroot00000000000000node-gulp-4.0.2+~cs38.20.35/test/fixtures/test/run.jade000066400000000000000000000000151415667007300222740ustar00rootroot00000000000000test templatenode-gulp-4.0.2+~cs38.20.35/test/index.test.js000066400000000000000000000024361415667007300204470ustar00rootroot00000000000000'use strict'; var expect = require('expect'); var gulp = require('../'); describe('gulp', function() { describe('hasOwnProperty', function() { it('src', function(done) { expect(gulp.hasOwnProperty('src')).toEqual(true); done(); }); it('dest', function(done) { expect(gulp.hasOwnProperty('dest')).toEqual(true); done(); }); it('symlink', function(done) { expect(gulp.hasOwnProperty('symlink')).toEqual(true); done(); }); it('watch', function(done) { expect(gulp.hasOwnProperty('watch')).toEqual(true); done(); }); it('task', function(done) { expect(gulp.hasOwnProperty('task')).toEqual(true); done(); }); it('series', function(done) { expect(gulp.hasOwnProperty('series')).toEqual(true); done(); }); it('parallel', function(done) { expect(gulp.hasOwnProperty('parallel')).toEqual(true); done(); }); it('tree', function(done) { expect(gulp.hasOwnProperty('tree')).toEqual(true); done(); }); it('lastRun', function(done) { expect(gulp.hasOwnProperty('lastRun')).toEqual(true); done(); }); it('registry', function(done) { expect(gulp.hasOwnProperty('registry')).toEqual(true); done(); }); }); }); node-gulp-4.0.2+~cs38.20.35/test/src.js000066400000000000000000000112511415667007300171440ustar00rootroot00000000000000'use strict'; var path = require('path'); var expect = require('expect'); var gulp = require('../'); describe('gulp.src()', function() { it('should return a stream', function(done) { var stream = gulp.src('./fixtures/*.coffee', { cwd: __dirname }); expect(stream).toExist(); expect(stream.on).toExist(); done(); }); it('should return a input stream from a flat glob', function(done) { var stream = gulp.src('./fixtures/*.coffee', { cwd: __dirname }); stream.on('error', done); stream.on('data', function(file) { expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toExist(); expect(file.path).toEqual(path.join(__dirname, './fixtures/test.coffee')); expect(file.contents).toEqual('this is a test'); }); stream.on('end', function() { done(); }); }); it('should return a input stream for multiple globs', function(done) { var globArray = [ './fixtures/stuff/run.dmc', './fixtures/stuff/test.dmc', ]; var stream = gulp.src(globArray, { cwd: __dirname }); var files = []; stream.on('error', done); stream.on('data', function(file) { expect(file).toExist(); expect(file.path).toExist(); files.push(file); }); stream.on('end', function() { expect(files.length).toEqual(2); expect(files[0].path).toEqual(path.join(__dirname, globArray[0])); expect(files[1].path).toEqual(path.join(__dirname, globArray[1])); done(); }); }); it('should return a input stream for multiple globs, with negation', function(done) { var expectedPath = path.join(__dirname, './fixtures/stuff/run.dmc'); var globArray = [ './fixtures/stuff/*.dmc', '!fixtures/stuff/test.dmc', ]; var stream = gulp.src(globArray, { cwd: __dirname }); var files = []; stream.on('error', done); stream.on('data', function(file) { expect(file).toExist(); expect(file.path).toExist(); files.push(file); }); stream.on('end', function() { expect(files.length).toEqual(1); expect(files[0].path).toEqual(expectedPath); done(); }); }); it('should return a input stream with no contents when read is false', function(done) { var stream = gulp.src('./fixtures/*.coffee', { read: false, cwd: __dirname }); stream.on('error', done); stream.on('data', function(file) { expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toNotExist(); expect(file.path).toEqual(path.join(__dirname, './fixtures/test.coffee')); }); stream.on('end', function() { done(); }); }); it('should return a input stream with contents as stream when buffer is false', function(done) { var stream = gulp.src('./fixtures/*.coffee', { buffer: false, cwd: __dirname }); stream.on('error', done); stream.on('data', function(file) { expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toExist(); var buf = ''; file.contents.on('data', function(d) { buf += d; }); file.contents.on('end', function() { expect(buf).toEqual('this is a test'); done(); }); expect(file.path).toEqual(path.join(__dirname, './fixtures/test.coffee')); }); }); it('should return a input stream from a deep glob', function(done) { var stream = gulp.src('./fixtures/**/*.jade', { cwd: __dirname }); stream.on('error', done); stream.on('data', function(file) { expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toExist(); expect(file.path).toEqual(path.join(__dirname, './fixtures/test/run.jade')); expect(file.contents).toEqual('test template'); }); stream.on('end', function() { done(); }); }); it('should return a input stream from a deeper glob', function(done) { var stream = gulp.src('./fixtures/**/*.dmc', { cwd: __dirname }); var a = 0; stream.on('error', done); stream.on('data', function() { ++a; }); stream.on('end', function() { expect(a).toEqual(2); done(); }); }); it('should return a file stream from a flat path', function(done) { var a = 0; var stream = gulp.src(path.join(__dirname, './fixtures/test.coffee')); stream.on('error', done); stream.on('data', function(file) { ++a; expect(file).toExist(); expect(file.path).toExist(); expect(file.contents).toExist(); expect(file.path).toEqual(path.join(__dirname, './fixtures/test.coffee')); expect(file.contents).toEqual('this is a test'); }); stream.on('end', function() { expect(a).toEqual(1); done(); }); }); }); node-gulp-4.0.2+~cs38.20.35/test/watch.js000066400000000000000000000125371415667007300174730ustar00rootroot00000000000000'use strict'; /* eslint-disable no-use-before-define */ var fs = require('fs'); var path = require('path'); var expect = require('expect'); var rimraf = require('rimraf'); var mkdirp = require('mkdirp'); var gulp = require('../'); var outpath = path.join(__dirname, './out-fixtures'); var tempFileContent = 'A test generated this file and it is safe to delete'; function createTempFile(path) { fs.writeFileSync(path, tempFileContent); } function updateTempFile(path) { setTimeout(function() { fs.appendFileSync(path, ' changed'); }, 125); } describe('gulp.watch()', function() { beforeEach(rimraf.bind(null, outpath)); beforeEach(mkdirp.bind(null, outpath)); afterEach(rimraf.bind(null, outpath)); it('should call the function when file changes: no options', function(done) { var tempFile = path.join(outpath, 'watch-func.txt'); createTempFile(tempFile); var watcher = gulp.watch('watch-func.txt', { cwd: outpath }, function(cb) { watcher.close(); cb(); done(); }); updateTempFile(tempFile); }); it('should execute the gulp.parallel tasks', function(done) { var tempFile = path.join(outpath, 'watch-func.txt'); createTempFile(tempFile); gulp.task('test', function(cb) { watcher.close(); cb(); done(); }); var watcher = gulp.watch('watch-func.txt', { cwd: outpath }, gulp.parallel('test')); updateTempFile(tempFile); }); it('should work with destructuring', function(done) { var tempFile = path.join(outpath, 'watch-func.txt'); var watch = gulp.watch; var parallel = gulp.parallel; var task = gulp.task; createTempFile(tempFile); task('test', function(cb) { watcher.close(); cb(); done(); }); var watcher = watch('watch-func.txt', { cwd: outpath }, parallel('test')); updateTempFile(tempFile); }); it('should not call the function when no file changes: no options', function(done) { var tempFile = path.join(outpath, 'watch-func.txt'); createTempFile(tempFile); var watcher = gulp.watch('watch-func.txt', { cwd: outpath }, function() { // TODO: proper fail here expect('Watcher erroneously called'); }); setTimeout(function() { watcher.close(); done(); }, 10); }); it('should call the function when file changes: w/ options', function(done) { var tempFile = path.join(outpath, 'watch-func-options.txt'); createTempFile(tempFile); var watcher = gulp.watch('watch-func-options.txt', { cwd: outpath }, function(cb) { watcher.close(); cb(); done(); }); updateTempFile(tempFile); }); it('should not drop options when no callback specified', function(done) { var tempFile = path.join(outpath, 'watch-func-nodrop-options.txt'); // By passing a cwd option, ensure options are not lost to gaze var relFile = '../watch-func-nodrop-options.txt'; var cwd = path.join(outpath, '/subdir'); createTempFile(tempFile); var watcher = gulp.watch(relFile, { cwd: cwd }) .on('change', function(filepath) { expect(filepath).toExist(); expect(path.resolve(cwd, filepath)).toEqual(path.resolve(tempFile)); watcher.close(); done(); }); updateTempFile(tempFile); }); it('should work without options or callback', function(done) { // TODO: check we return watcher? gulp.watch('x'); done(); }); it('should run many tasks: w/ options', function(done) { var tempFile = path.join(outpath, 'watch-task-options.txt'); var a = 0; createTempFile(tempFile); gulp.task('task1', function(cb) { a++; cb(); }); gulp.task('task2', function(cb) { a += 10; expect(a).toEqual(11); watcher.close(); cb(); done(); }); var watcher = gulp.watch('watch-task-options.txt', { cwd: outpath }, gulp.series('task1', 'task2')); updateTempFile(tempFile); }); it('should run many tasks: no options', function(done) { var tempFile = path.join(outpath, 'watch-many-tasks-no-options.txt'); var a = 0; createTempFile(tempFile); gulp.task('task1', function(cb) { a++; cb(); }); gulp.task('task2', function(cb) { a += 10; expect(a).toEqual(11); watcher.close(); cb(); done(); }); var watcher = gulp.watch('./test/out-fixtures/watch-many-tasks-no-options.txt', gulp.series('task1', 'task2')); updateTempFile(tempFile); }); it('should throw an error: passed parameter (string) is not a function', function(done) { var filename = 'empty.txt'; var tempFile = path.join(outpath, filename); createTempFile(tempFile); try { gulp.watch(filename, { cwd: outpath }, 'task1'); } catch (err) { expect(err.message).toEqual('watching ' + filename + ': watch task has to be a function (optionally generated by using gulp.parallel or gulp.series)'); done(); } }); it('should throw an error: passed parameter (array) is not a function', function(done) { var filename = 'empty.txt'; var tempFile = path.join(outpath, filename); createTempFile(tempFile); try { gulp.watch(filename, { cwd: outpath }, ['task1']); } catch (err) { expect(err.message).toEqual('watching ' + filename + ': watch task has to be a function (optionally generated by using gulp.parallel or gulp.series)'); done(); } }); });