diff --git a/app.js b/app.js new file mode 100644 index 0000000..8b7b178 --- /dev/null +++ b/app.js @@ -0,0 +1,115 @@ +var appEnv = process.env.APP_ENV; +if (appEnv == undefined) { + appEnv = 'development'; +} +require('dotenv').config({ path: `.env.${appEnv}` }); +const { promisify } = require('util'), + bodyParser = require('body-parser'), + chalk = require('chalk'), + utils = require('./routes/utils'), + exceptionHandler = require('./middlewares/exceptions.handler.js'); +var express = require('express'), + session = require('express-session'), + cors = require('cors'), + errorhandler = require('errorhandler'), + mongoose = require('mongoose'), + morgan = require('morgan'); + +var isProduction = appEnv === 'production'; + +// Create global app object +var app = express(); + +app.use(cors()); + +// Normal express config defaults +//app.use(morgan('combined')); +morgan.token('statusColor', (req, res) => { + let status = (typeof res.headersSent !== 'boolean' ? Boolean(res.header) : res.headersSent) + ? res.statusCode + : undefined + + return status >= 500 ? chalk.red(status) + : status >= 429 ? chalk.magenta(status) + : status >= 400 ? chalk.yellow(status) + : status >= 300 ? chalk.cyan(status) + : status >= 200 ? chalk.green(status) + : chalk.underline(status); +}); +app.use(morgan('[:date[iso]] ":method :url HTTP/:http-version" :statusColor :res[content-length] ":referrer" ":user-agent" :remote-addr')); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); + +app.use(require('method-override')()); +app.use(express.static(__dirname + '/public')); + +app.use(session({ secret: 'acapisecret', cookie: { maxAge: 60000 }, resave: false, saveUninitialized: false })); + +if (!isProduction) { + app.use(errorhandler()); +} + +if(isProduction){ + mongoose.connect(process.env.MONGODB_URI); +} else { + mongoose.set('strictQuery', true); + mongoose.connect(process.env.MONGODB_URI).then(() => { + console.log(`${utils.getDateTimeISOString()}`, chalk.green('MongoDB connection has been established successfully')); + }).catch(() => { + console.log(`${utils.getDateTimeISOString()}`, chalk.red('Unable to connect to the MongoDB database')); + }); + mongoose.set('debug', process.env.DEBUG); + console.log(`${utils.getDateTimeISOString()}`, chalk.red('debug :'), chalk.yellow(process.env.DEBUG)); +} + +require('./models/mongo'); +require('./config/passport'); + +app.use(require('./routes')); + +app.use(exceptionHandler.notFoundErrorHandler); +app.use(exceptionHandler.logErrorHandler); +app.use(exceptionHandler.clientErrorHandler); +app.use(exceptionHandler.fianlErrorHandler); + +/* +// catch 404 and forward to error handler +app.use(function(req, res, next) { + let err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handler +app.use(function(err, req, res, next) { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`error handler : ${err.message} ${err.err}`)); + if (res.headersSent) { + return next(err) + } + res.status(err.status || 500); + if (!isProduction) { + // development error handler will print stacktrace + res.json({errors: { + message: err.message, + error: err.err, + stack: err.stack + }}); + } else { + // production error handler no stacktraces leaked to user + res.json({errors: { + message: err.message, + error: {}, + stack: {} + }}); + } +}); +*/ + +const startServer = async () => { + const port = process.env.SERVER_PORT || 3200; + await promisify(app.listen).bind(app)(port); + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`${process.env.APP_ENV} API server listening on port ${port}`)); +} + +// finally, let's start our server... +startServer(); \ No newline at end of file diff --git a/config/db.js b/config/db.js new file mode 100644 index 0000000..72587fe --- /dev/null +++ b/config/db.js @@ -0,0 +1,26 @@ +module.exports = { + "development": { + "username": 'c4adastracomu1', + "password": 'kbrnrt5jPK12', + "database": 'c4adastracomdb1', + "host": '176.31.255.24', + "port": 3306, + "dialect": 'mysql' + }, + "test": { + "username": 'c4adastracomu1', + "password": 'kbrnrt5jPK12', + "database": 'c4adastracomdb1', + "host": '176.31.255.24', + "port": 3306, + "dialect": 'mysql' + }, + "production": { + "username": 'c4adastracomu1', + "password": 'kbrnrt5jPK12', + "database": 'c4adastracomdb1', + "host": '176.31.255.24', + "port": 3306, + "dialect": 'mysql' + } +} \ No newline at end of file diff --git a/config/index.js b/config/index.js new file mode 100644 index 0000000..3346025 --- /dev/null +++ b/config/index.js @@ -0,0 +1,6 @@ + +const config = { + secret: process.env.SECRET || 'acapisecret', + session_lifetime: process.env.SESSION_LIFETIME || 21600 // 21600 secondes = 6 heures +}; +module.exports = config; diff --git a/config/passport.js b/config/passport.js new file mode 100644 index 0000000..9000db4 --- /dev/null +++ b/config/passport.js @@ -0,0 +1,61 @@ +var secret = require('../config').secret, +bcrypt = require('bcrypt'); +const passport = require('passport'); +var LocalStrategy = require('passport-local').Strategy; +var HeaderAPIKeyStrategy = require('passport-headerapikey').HeaderAPIKeyStrategy; +var mongoose = require('mongoose'); +var Application = mongoose.model('Application'); +var User = mongoose.model('User'); + +passport.use('headerapikey', new HeaderAPIKeyStrategy( + { header: 'Authorization', prefix: `${process.env.AUTHORIZATION_PREFIX} ` }, + false, + function (apikey, done) { + const salt = secret; + Promise.resolve(bcrypt.hash(apikey, salt)).then(function (encryptedKey) { + Application.findOne({ encryptedKey: encryptedKey }) + .populate('author') + .then(function (application) { + if (!application) { + return done({message: "Application can't be found.", status: 404}, false, false); + } + console.log('encryptedKey: ', encryptedKey); + return done(null, application); + }); + }).catch(done); + /* + const salt = secret; + Promise.resolve(bcrypt.hash(apikey, salt)).then(function (encryptedKey) { + Application.findOne({ encryptedKey: encryptedKey }) + .populate('author') + .then(function (application) { + if (!application) { + return done({message: "Application can't be found.", status: 404}, false, false); + } + console.log('encryptedKey: ', encryptedKey); + return done(null, application); + return {app: application, prom: Promise.resolve(bcrypt.compare(apikey, application.apikey))}; + }).then(function (res) { + res.prom.then(function (valid) { + if (!valid) { + return done(null, false, {app: res.app, valid: valid}); + } + return done(null, res.app, valid); + }); + }); + }).catch(done); + */ + } +)); + +passport.use('local', new LocalStrategy({ + usernameField: 'user[email]', + passwordField: 'user[password]' +}, function (email, password, done) { + User.findOne({ email: email }).then(function (user) { + if (!user || !user.validPassword(password)) { + return done(null, false, { errors: { 'email ou mot de passe': 'invalide' } }); + } + return done(null, user); + }).catch(done); +})); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..a75b2a6 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,9 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; + + +export default [ + {files: ["**/*.js"], languageOptions: {sourceType: "commonjs"}}, + {languageOptions: { globals: globals.node }}, + pluginJs.configs.recommended, +]; \ No newline at end of file diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..7bbdb28 --- /dev/null +++ b/models/index.js @@ -0,0 +1,15 @@ +exports.User = require('./mongo/User'); +exports.Application = require('./mongo/Application'); +exports.Aeronef = require('./mongo/Aeronef'); +exports.Canopy = require('./mongo/Canopy'); +exports.Dropzone = require('./mongo/Dropzone'); +exports.JumpFile = require('./mongo/JumpFile'); +exports.Jump = require('./mongo/Jump'); +exports.Qcm = require('./mongo/Qcm'); +exports.QcmCategory = require('./mongo/QcmCategory'); +exports.QcmQuestion = require('./mongo/QcmQuestion'); +exports.QcmChoice = require('./mongo/QcmChoice'); +exports.X2DataLog = require('./mongo/X2DataLog'); +exports.Article = require('./mongo/Article'); +exports.Comment = require('./mongo/Comment'); +exports.Tag = require('./mongo/Tag'); \ No newline at end of file diff --git a/models/mongo/Aeronef.js b/models/mongo/Aeronef.js new file mode 100644 index 0000000..7f261b1 --- /dev/null +++ b/models/mongo/Aeronef.js @@ -0,0 +1,33 @@ +var mongoose = require('mongoose'); +var slug = require('slug'); + +var AeronefSchema = new mongoose.Schema({ + slug: { type: String, lowercase: true, unique: true }, + aeronef: String, + imat: String, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, {timestamps: true, toJSON: {virtuals: true}}); + +AeronefSchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +AeronefSchema.methods.slugify = function () { + this.slug = slug(`${this.aeronef} ${this.imat}`) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +AeronefSchema.methods.toJSONFor = function(user){ + return { + slug: this.slug, + aeronef: this.aeronef, + imat: this.imat, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Aeronef', AeronefSchema); diff --git a/models/mongo/Application.js b/models/mongo/Application.js new file mode 100644 index 0000000..794e04c --- /dev/null +++ b/models/mongo/Application.js @@ -0,0 +1,51 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var slug = require('slug'); + +var ApplicationSchema = new mongoose.Schema({ + apikey: String, + maskedkey: String, + slug: { type: String, lowercase: true, unique: true }, + title: String, + description: String, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, { timestamps: true, toJSON: { virtuals: true } }); + +ApplicationSchema.plugin(uniqueValidator, { message: 'is already taken' }); + +ApplicationSchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +ApplicationSchema.methods.slugify = function () { + this.slug = slug(this.title) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +ApplicationSchema.methods.toJSONFor = function (user) { + return { + maskedkey: this.maskedkey, + slug: this.slug, + title: this.title, + description: this.description, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +ApplicationSchema.methods.toAuthJSON = function () { + return { + maskedkey: this.maskedkey, + slug: this.slug, + title: this.title, + description: this.description, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toJSONFor() + }; +}; + +mongoose.model('Application', ApplicationSchema); \ No newline at end of file diff --git a/models/mongo/Article.js b/models/mongo/Article.js new file mode 100755 index 0000000..c7e8ce3 --- /dev/null +++ b/models/mongo/Article.js @@ -0,0 +1,60 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var slug = require('slug'); +var User = mongoose.model('User'); +//var Membre = mongoose.model('Membre'); + +var ArticleSchema = new mongoose.Schema({ + slug: { type: String, lowercase: true, unique: true }, + title: String, + description: String, + body: String, + membre: String, + // membre: Membre.schema, + // membre: { type: mongoose.Schema.Types.ObjectId, ref: 'Membre' }, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, + comments: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Comment' }], + favoritesCount: { type: Number, default: 0 }, + tagList: [{ type: String }] +}, { timestamps: true, toJSON: { virtuals: true } }); + +ArticleSchema.plugin(uniqueValidator, { message: 'is already taken' }); + +ArticleSchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +ArticleSchema.methods.slugify = function () { + this.slug = slug(this.title) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +ArticleSchema.methods.updateFavoriteCount = function () { + var article = this; + + return User.count({ favorites: { $in: [article._id] } }).then(function (count) { + article.favoritesCount = count; + + return article.save(); + }); +}; + +ArticleSchema.methods.toJSONFor = function (user) { + return { + slug: this.slug, + title: this.title, + description: this.description, + body: this.body, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + tagList: this.tagList, + membre: this.membre, + favorited: user ? user.isFavorite(this._id) : false, + favoritesCount: this.favoritesCount, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Article', ArticleSchema); diff --git a/models/mongo/Canopy.js b/models/mongo/Canopy.js new file mode 100644 index 0000000..312fb6c --- /dev/null +++ b/models/mongo/Canopy.js @@ -0,0 +1,33 @@ +var mongoose = require('mongoose'); +var slug = require('slug'); + +var CanopySchema = new mongoose.Schema({ + slug: { type: String, lowercase: true, unique: true }, + voile: String, + taille: Number, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, {timestamps: true, toJSON: {virtuals: true}}); + +CanopySchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +CanopySchema.methods.slugify = function () { + this.slug = slug(`${this.voile} ${this.taille}`) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +CanopySchema.methods.toJSONFor = function(user){ + return { + slug: this.slug, + voile: this.voile, + taille: this.taille, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Canopy', CanopySchema); diff --git a/models/mongo/Comment.js b/models/mongo/Comment.js new file mode 100755 index 0000000..10db85d --- /dev/null +++ b/models/mongo/Comment.js @@ -0,0 +1,19 @@ +var mongoose = require('mongoose'); + +var CommentSchema = new mongoose.Schema({ + body: String, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }, + article: { type: mongoose.Schema.Types.ObjectId, ref: 'Article' } +}, { timestamps: true, toJSON: { virtuals: true } }); + +// Requires population of author +CommentSchema.methods.toJSONFor = function (user) { + return { + id: this._id, + body: this.body, + createdAt: this.createdAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Comment', CommentSchema); diff --git a/models/mongo/Dropzone.js b/models/mongo/Dropzone.js new file mode 100644 index 0000000..2591fa2 --- /dev/null +++ b/models/mongo/Dropzone.js @@ -0,0 +1,33 @@ +var mongoose = require('mongoose'); +var slug = require('slug'); + +var DropzoneSchema = new mongoose.Schema({ + slug: { type: String, lowercase: true, unique: true }, + lieu: String, + oaci: String, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, {timestamps: true, toJSON: {virtuals: true}}); + +DropzoneSchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +DropzoneSchema.methods.slugify = function () { + this.slug = slug(`${this.lieu} ${this.oaci}`) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +DropzoneSchema.methods.toJSONFor = function(user){ + return { + slug: this.slug, + lieu: this.lieu, + oaci: this.oaci, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Dropzone', DropzoneSchema); diff --git a/models/mongo/Jump.js b/models/mongo/Jump.js new file mode 100644 index 0000000..714c709 --- /dev/null +++ b/models/mongo/Jump.js @@ -0,0 +1,86 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var slug = require('slug'); + +var JumpSchema = new mongoose.Schema({ + slug: { type: String, lowercase: true, unique: true }, + date: { type: Date, default: Date.now }, + numero: { type: Number, unique: true }, + lieu: String, + oaci: String, + aeronef: String, + imat: String, + hauteur: Number, + deploiement: Number, + voile: String, + taille: Number, + categorie: String, + module: String, + participants: Number, + sautants: [String], + programme: String, + accessoires: String, + zone: String, + dossier: String, + video: String, + files: [{ type: mongoose.Schema.Types.ObjectId, ref: 'JumpFile' }], + x2data: { type: mongoose.Schema.Types.ObjectId, ref: 'X2DataLog' }, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, {timestamps: true, toJSON: {virtuals: true}}); + +JumpSchema.plugin(uniqueValidator, { message: 'is already taken' }); + +JumpSchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +JumpSchema.methods.slugify = function () { + this.slug = slug(`${this.numero} ${this.lieu}`) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +JumpSchema.methods.addFile = function (id) { + if (this.files.indexOf(id) === -1) { + this.files.push(id); + } + return this.save(); +}; + +JumpSchema.methods.removeFile = function (id) { + this.files.remove(id); + return this.save(); +}; + +JumpSchema.methods.toJSONFor = function(user) { + return { + slug: this.slug, + date: this.date, + numero: this.numero, + lieu: this.lieu, + oaci: this.oaci, + aeronef: this.aeronef, + imat: this.imat, + hauteur: this.hauteur, + deploiement: this.deploiement, + voile: this.voile, + taille: this.taille, + categorie: this.categorie, + module: this.module, + participants: this.participants, + sautants: this.sautants, + programme: this.programme, + accessoires: this.accessoires, + zone: this.zone, + dossier: this.dossier, + video: this.video, + files: this.files.map(file => file ? file.toJSONForJump() : null), + x2data: this.x2data ? this.x2data.toJSONFor() : null, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('Jump', JumpSchema); diff --git a/models/mongo/JumpFile.js b/models/mongo/JumpFile.js new file mode 100644 index 0000000..7985a89 --- /dev/null +++ b/models/mongo/JumpFile.js @@ -0,0 +1,51 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var slug = require('slug'); + +var JumpFileSchema = new mongoose.Schema({ + slug: { type: String, lowercase: true, unique: true }, + name: String, + path: String, + type: { + type: String, + enum : ['csv', 'image', 'kml', 'video'], + default: 'video' + }, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, {timestamps: true, toJSON: {virtuals: true}}); + +JumpFileSchema.plugin(uniqueValidator, { message: 'is already taken' }); + +JumpFileSchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +JumpFileSchema.methods.slugify = function () { + this.slug = slug(`${this.type}`) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36) + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +JumpFileSchema.methods.toJSONFor = function(user){ + return { + slug: this.slug, + name: this.name, + path: this.path, + type: this.type, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +JumpFileSchema.methods.toJSONForJump = function(){ + return { + slug: this.slug, + name: this.name, + path: this.path, + type: this.type + }; +}; + +mongoose.model('JumpFile', JumpFileSchema); diff --git a/models/mongo/Qcm.js b/models/mongo/Qcm.js new file mode 100644 index 0000000..1b413db --- /dev/null +++ b/models/mongo/Qcm.js @@ -0,0 +1,46 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var slug = require('slug'); + +var QcmSchema = new mongoose.Schema({ + name: { type: String, lowercase: true, unique: true }, + slug: { type: String, lowercase: true, unique: true }, + categories: [ + { type: mongoose.Schema.Types.ObjectId, ref: 'QcmCategory' } + ] +}, {timestamps: true, toJSON: {virtuals: true}}); + +QcmSchema.plugin(uniqueValidator, { message: 'is already taken' }); + +QcmSchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +QcmSchema.methods.slugify = function () { +this.slug = slug(`${this.name}-`) + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +QcmSchema.methods.addCategory = function (id) { + if (this.categories.indexOf(id) === -1) { + this.categories.push(id); + } + return this.save(); +}; + +QcmSchema.methods.removeCategory = function (id) { + this.categories.remove(id); + return this.save(); +}; + +QcmSchema.methods.toJSONFor = function() { + return { + name: this.name, + slug: this.slug, + categories: this.categories.map(category => category.toJSONFor()) + }; +}; + +mongoose.model('Qcm', QcmSchema); diff --git a/models/mongo/QcmCategory.js b/models/mongo/QcmCategory.js new file mode 100644 index 0000000..1a45db4 --- /dev/null +++ b/models/mongo/QcmCategory.js @@ -0,0 +1,48 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var slug = require('slug'); + +var QcmCategorySchema = new mongoose.Schema({ + num: Number, + name: { type: String, unique: true }, + slug: { type: String, lowercase: true, unique: true }, + questions: [ + { type: mongoose.Schema.Types.ObjectId, ref: 'QcmQuestion' } + ] +}, {timestamps: true, toJSON: {virtuals: true}}); + +QcmCategorySchema.plugin(uniqueValidator, { message: 'is already taken' }); + +QcmCategorySchema.pre('validate', function (next) { + if (!this.slug) { + this.slugify(); + } + next(); +}); + +QcmCategorySchema.methods.slugify = function () { +this.slug = slug(`${this.name}-${this.num}-`) + (Math.random() * Math.pow(36, 6) | 0).toString(36); +}; + +QcmCategorySchema.methods.addQuestion = function (id) { + if (this.questions.indexOf(id) === -1) { + this.questions.push(id); + } + return this.save(); +}; + +QcmCategorySchema.methods.removeQuestion = function (id) { + this.questions.remove(id); + return this.save(); +}; + +QcmCategorySchema.methods.toJSONFor = function() { + return { + num: this.num, + name: this.name, + slug: this.slug, + questions: this.questions.map(question => question.toJSONFor()) + }; +}; + +mongoose.model('QcmCategory', QcmCategorySchema); \ No newline at end of file diff --git a/models/mongo/QcmChoice.js b/models/mongo/QcmChoice.js new file mode 100644 index 0000000..38e9c8e --- /dev/null +++ b/models/mongo/QcmChoice.js @@ -0,0 +1,17 @@ +var mongoose = require('mongoose'); + +var QcmChoiceSchema = new mongoose.Schema({ + index: String, + libelle: String, + correct: Boolean +}, {timestamps: true, toJSON: {virtuals: true}}); + +QcmChoiceSchema.methods.toJSONFor = function() { + return { + index: this.index, + libelle: this.libelle, + correct: this.correct + }; +}; + +mongoose.model('QcmChoice', QcmChoiceSchema); \ No newline at end of file diff --git a/models/mongo/QcmQuestion.js b/models/mongo/QcmQuestion.js new file mode 100644 index 0000000..b1a92ab --- /dev/null +++ b/models/mongo/QcmQuestion.js @@ -0,0 +1,31 @@ +var mongoose = require('mongoose'); + +var QcmQuestionSchema = new mongoose.Schema({ + num: Number, + libelle: String, + choices: [ + { type: mongoose.Schema.Types.ObjectId, ref: 'QcmChoice' } + ] +}, {timestamps: true, toJSON: {virtuals: true}}); + +QcmQuestionSchema.methods.addChoice = function (id) { + if (this.choices.indexOf(id) === -1) { + this.choices.push(id); + } + return this.save(); +}; + +QcmQuestionSchema.methods.removeChoice = function (id) { + this.choices.remove(id); + return this.save(); +}; + +QcmQuestionSchema.methods.toJSONFor = function() { + return { + num: this.num, + libelle: this.libelle, + choices: this.choices.map(choice => choice.toJSONFor()) + }; +}; + +mongoose.model('QcmQuestion', QcmQuestionSchema); \ No newline at end of file diff --git a/models/mongo/Tag.js b/models/mongo/Tag.js new file mode 100644 index 0000000..10a40f6 --- /dev/null +++ b/models/mongo/Tag.js @@ -0,0 +1,18 @@ +const mongoose = require('mongoose'); +const uniqueValidator = require('mongoose-unique-validator'); + +const TagSchema = new mongoose.Schema({ + tagName: { + type: String, + required: true, + unique: true + }, + articles: [{ + type: mongoose.Schema.Types.ObjectId, + ref: 'Article' + }] +}) + +TagSchema.plugin(uniqueValidator); + +module.exports = mongoose.model('Tag', TagSchema); \ No newline at end of file diff --git a/models/mongo/User.js b/models/mongo/User.js new file mode 100644 index 0000000..cf4538a --- /dev/null +++ b/models/mongo/User.js @@ -0,0 +1,136 @@ +var mongoose = require('mongoose'); +var uniqueValidator = require('mongoose-unique-validator'); +var crypto = require('crypto'); +var jwt = require('jsonwebtoken'), + secret = require('../../config').secret, + session_lifetime = require('../../config').session_lifetime; + +var UserSchema = new mongoose.Schema({ + email: { type: String, lowercase: true, unique: true, required: [true, "email can't be blank"], match: [/\S+@\S+\.\S+/, 'is invalid'], index: true }, + username: { type: String, lowercase: true, unique: true, required: [true, "username can't be blank"], match: [/^[a-zA-Z0-9_]+$/, 'is invalid'], index: true }, + role: String, + firstname: { type: String, required: [true, "firstname can't be blank"] }, + lastname: { type: String, required: [true, "lastname can't be blank"] }, + phone: String, + licence: Number, + poids: Number, + image: String, + bg_image: String, + favorites: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Product' }], + following: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }], + hash: String, + salt: String +}, { timestamps: true, toJSON: { virtuals: true } }); + +UserSchema.plugin(uniqueValidator, { message: 'is already taken.' }); + +UserSchema.methods.validPassword = function (password) { + let hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); + return this.hash === hash; +}; + +UserSchema.methods.setPassword = function (password) { + this.salt = crypto.randomBytes(16).toString('hex'); + this.hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); +}; + +UserSchema.methods.generateJWT = function () { + var today = new Date(); + var exp = new Date(today.getTime() + (session_lifetime * 1000)); + console.log('Now date :', today.toISOString()); + console.log('Expiracy date :', exp.toISOString()); + console.log('Session lifetime :', session_lifetime); + + return jwt.sign({ + id: this._id, + username: this.username, + exp: parseInt(exp.getTime() / 1000) + }, secret, { algorithm: 'HS256' }); +}; + +UserSchema.methods.toAuthJSON = function () { + return { + id: this._id, + email: this.email, + role: this.role, + token: this.generateJWT(), + firstname: this.firstname, + lastname: this.lastname, + phone: this.phone, + licence: this.licence, + poids: this.poids, + username: this.username, + image: this.image || '/assets/images/users/user.jpg', + bg_image: this.bg_image || '/assets/images/users/bg_user.jpg' + }; +}; + +UserSchema.methods.toJSONFor = function () { + return { + email: this.email, + role: this.role, + firstname: this.firstname, + lastname: this.lastname, + phone: this.phone, + licence: this.licence, + poids: this.poids, + username: this.username, + image: this.image || '/assets/images/users/user.jpg', + bg_image: this.bg_image || '/assets/images/users/bg_user.jpg' + }; +}; + +UserSchema.methods.toProfileJSONFor = function (user) { + return { + email: this.email, + firstname: this.firstname, + lastname: this.lastname, + phone: this.phone, + licence: this.licence, + poids: this.poids, + username: this.username, + image: this.image || '/assets/images/users/user.jpg', + bg_image: this.bg_image || '/assets/images/users/bg_user.jpg', + following: user ? user.isFollowing(this._id) : false + }; +}; + +UserSchema.methods.favorite = function (id) { + if (this.favorites.indexOf(id) === -1) { + this.favorites.push(id); + } + + return this.save(); +}; + +UserSchema.methods.unfavorite = function (id) { + this.favorites.remove(id); + return this.save(); +}; + +UserSchema.methods.isFavorite = function (id) { + return this.favorites.some(function (favoriteId) { + return favoriteId.toString() === id.toString(); + }); +}; + +UserSchema.methods.follow = function (id) { + if (this.following.indexOf(id) === -1) { + this.following.push(id); + } + + return this.save(); +}; + +UserSchema.methods.unfollow = function (id) { + this.following.remove(id); + return this.save(); +}; + +UserSchema.methods.isFollowing = function (id) { + return this.following.some(function (followId) { + return followId.toString() === id.toString(); + }); +}; + +mongoose.model('User', UserSchema); diff --git a/models/mongo/X2DataLog.js b/models/mongo/X2DataLog.js new file mode 100644 index 0000000..7a626d9 --- /dev/null +++ b/models/mongo/X2DataLog.js @@ -0,0 +1,107 @@ +var mongoose = require('mongoose'); + +var X2DataLogSchema = new mongoose.Schema({ + id: String, + name: String, + type: String, + description: String, + landingZone: String, + speed: { + freeFall: { + vertical: { + max: Number, + avg: Number + }, + horizontal: { + max: Number, + avg: Number + } + }, + underCanopy: { + vertical: { + max: Number, + avg: Number + }, + horizontal: { + max: Number, + avg: Number + } + } + }, + glideRatio: { + freeFall: { + max: Number, + avg: Number + }, + underCanopy: { + max: Number, + avg: Number + } + }, + duration: { + freeFall: Number, + underCanopy: Number + }, + distance: { + exitFromLandingZone: Number, + totalFlying: Number, + totalHorizontal: Number + }, + altitude: { + exit: Number, + deployment: Number + }, + cutaway: String, + malfunctions: [ + { + name: String, + type: String + } + ], + date: String, + createdOn: String, + author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' } +}, {timestamps: true, toJSON: {virtuals: true}}); + +X2DataLogSchema.methods.toJSONFor = function() { + return { + id: this.id, + name: this.name, + type: this.type, + description: this.description, + landingZone: this.landingZone, + speed: this.speed, + glideRatio: this.glideRatio, + duration: this.duration, + distance: this.distance, + altitude: this.altitude, + cutaway: this.cutaway, + malfunctions: this.malfunctions, + date: this.date, + createdOn: this.createdOn + }; +}; + +X2DataLogSchema.methods.toJSONForUser = function(user) { + return { + id: this.id, + name: this.name, + type: this.type, + description: this.description, + landingZone: this.landingZone, + speed: this.speed, + glideRatio: this.glideRatio, + duration: this.duration, + distance: this.distance, + altitude: this.altitude, + cutaway: this.cutaway, + malfunctions: this.malfunctions, + date: this.date, + createdOn: this.createdOn, + createdAt: this.createdAt, + updatedAt: this.updatedAt, + author: this.author.toProfileJSONFor(user) + }; +}; + +mongoose.model('X2DataLog', X2DataLogSchema); diff --git a/models/mongo/index.js b/models/mongo/index.js new file mode 100644 index 0000000..c15d084 --- /dev/null +++ b/models/mongo/index.js @@ -0,0 +1,16 @@ +exports.User = require('./User'); +exports.Application = require('./Application'); +exports.Aeronef = require('./Aeronef'); +exports.Canopy = require('./Canopy'); +exports.Dropzone = require('./Dropzone'); +exports.JumpFile = require('./JumpFile'); +exports.Jump = require('./Jump'); +exports.Qcm = require('./Qcm'); +exports.QcmCategory = require('./QcmCategory'); +exports.QcmQuestion = require('./QcmQuestion'); +exports.QcmChoice = require('./QcmChoice'); +exports.X2DataLog = require('./X2DataLog'); +exports.Article = require('./Article'); +exports.Comment = require('./Comment'); +exports.Tag = require('./Tag'); + diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 0000000..89a1986 --- /dev/null +++ b/nodemon.json @@ -0,0 +1,21 @@ +{ + "env" : { + "APP_ENV": "local", + "NODE_ENV" : "development", + "DEBUG": false, + "SERVER_PORT": "3200", + "SECRET": "$2b$10$aEsAUG7Dy8dcTORi1vaQle", + "SESSION_LIFETIME": "3600", + "MONGODB_URI": "mongodb://localhost:27017/adastradb", + "SENDGRID_API_KEY": "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", + "SENDGRID_FROM_MAIL": "contact@rampeur.fr", + "SENDGRID_TO_MAIL": "rampeur@gmail.com", + "AUTHORIZATION_PREFIX": "Api-Key", + "COUCHDB_URL": "http://couchdb.unespace.com", + "COUCHDB_DATABASE": "adastradb", + "COUCHDB_DESIGN": "adastra_app", + "COUCHDB_CREDENTIAL": "cmFtcGV1cjpES3hwMjRQUw==", + "SKYDIVERID_API_URL": "https://skydiver.id/api", + "SKYDIVERID_API_TOKEN": "xmqzgnGYMD.OJgFw1pCXCpJFGmZfSjmWK8lrpqAQNnu" + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f97aa65 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5938 @@ +{ + "name": "hu-api", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "hu-api", + "version": "1.0.0", + "license": "UNLICENSED", + "dependencies": { + "@sendgrid/mail": "^7.7.0", + "bcrypt": "^5.1.1", + "body-parser": "^1.20.2", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "ejs": "^3.1.9", + "errorhandler": "^1.5.1", + "express": "^4.18.2", + "express-jwt": "^8.4.1", + "express-session": "^1.18.0", + "jsonwebtoken": "^9.0.2", + "method-override": "3.0.0", + "methods": "1.1.2", + "mongoose": "^6.12.6", + "mongoose-unique-validator": "^3.1.0", + "morgan": "^1.10.0", + "node-fetch": "^3.3.2", + "passport": "^0.6.0", + "passport-headerapikey": "^1.2.2", + "passport-local": "^1.0.0", + "request": "^2.88.2", + "slug": "^8.2.3", + "underscore": "^1.13.6", + "uuid": "^9.0.1" + }, + "devDependencies": { + "@eslint/js": "^9.0.0", + "eslint": "^9.0.0", + "globals": "^15.0.0", + "newman": "^5.3.2", + "nodemon": "^2.0.22" + }, + "engines": { + "node": "^16.20.2 || ^18.19.1 || ^20.11.1" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "optional": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "optional": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "optional": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.523.0.tgz", + "integrity": "sha512-Jdyaf6HPGF9cnaB+M/8t90YmiXIyZPJSmQJa7oL33ZvDZeqJWsSxvJVoVvqaz6VaEWg8l716ooDADXswg9hIEA==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.523.0", + "@aws-sdk/core": "3.523.0", + "@aws-sdk/credential-provider-node": "3.523.0", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.523.0", + "@aws-sdk/region-config-resolver": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.523.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.523.0", + "@smithy/config-resolver": "^2.1.3", + "@smithy/core": "^1.3.4", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.3", + "@smithy/middleware-retry": "^2.1.3", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.1", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.3", + "@smithy/util-defaults-mode-node": "^2.2.2", + "@smithy/util-endpoints": "^1.1.3", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.523.0.tgz", + "integrity": "sha512-vob/Tk9bIr6VIyzScBWsKpP92ACI6/aOXBL2BITgvRWl5Umqi1jXFtfssj/N2UJHM4CBMRwxIJ33InfN0gPxZw==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.523.0", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.523.0", + "@aws-sdk/region-config-resolver": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.523.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.523.0", + "@smithy/config-resolver": "^2.1.3", + "@smithy/core": "^1.3.4", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.3", + "@smithy/middleware-retry": "^2.1.3", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.1", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.3", + "@smithy/util-defaults-mode-node": "^2.2.2", + "@smithy/util-endpoints": "^1.1.3", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.523.0.tgz", + "integrity": "sha512-OktkdiuJ5DtYgNrJlo53Tf7pJ+UWfOt7V7or0ije6MysLP18GwlTkbg2UE4EUtfOxt/baXxHMlExB1vmRtlATw==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.523.0", + "@aws-sdk/core": "3.523.0", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.523.0", + "@aws-sdk/region-config-resolver": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.523.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.523.0", + "@smithy/config-resolver": "^2.1.3", + "@smithy/core": "^1.3.4", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.3", + "@smithy/middleware-retry": "^2.1.3", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.1", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.3", + "@smithy/util-defaults-mode-node": "^2.2.2", + "@smithy/util-endpoints": "^1.1.3", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-node": "^3.523.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.523.0.tgz", + "integrity": "sha512-ggAkL8szaJkqD8oOsS68URJ9XMDbLA/INO/NPZJqv9BhmftecJvfy43uUVWGNs6n4YXNzfF0Y+zQ3DT0fZkv9g==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.523.0", + "@aws-sdk/middleware-host-header": "3.523.0", + "@aws-sdk/middleware-logger": "3.523.0", + "@aws-sdk/middleware-recursion-detection": "3.523.0", + "@aws-sdk/middleware-user-agent": "3.523.0", + "@aws-sdk/region-config-resolver": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.523.0", + "@aws-sdk/util-user-agent-browser": "3.523.0", + "@aws-sdk/util-user-agent-node": "3.523.0", + "@smithy/config-resolver": "^2.1.3", + "@smithy/core": "^1.3.4", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/hash-node": "^2.1.3", + "@smithy/invalid-dependency": "^2.1.3", + "@smithy/middleware-content-length": "^2.1.3", + "@smithy/middleware-endpoint": "^2.4.3", + "@smithy/middleware-retry": "^2.1.3", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/node-config-provider": "^2.2.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.1", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-body-length-browser": "^2.1.1", + "@smithy/util-body-length-node": "^2.2.1", + "@smithy/util-defaults-mode-browser": "^2.1.3", + "@smithy/util-defaults-mode-node": "^2.2.2", + "@smithy/util-endpoints": "^1.1.3", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "@smithy/util-utf8": "^2.1.1", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-node": "^3.523.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.523.0.tgz", + "integrity": "sha512-JHa3ngEWkTzZ2YTn6EavcADC8gv6zZU4U9WBAleClh6ioXH0kGMBawZje3y0F0mKyLTfLhFqFUlCV5sngI/Qcw==", + "optional": true, + "dependencies": { + "@smithy/core": "^1.3.4", + "@smithy/protocol-http": "^3.2.1", + "@smithy/signature-v4": "^2.1.3", + "@smithy/smithy-client": "^2.4.1", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.523.0.tgz", + "integrity": "sha512-HmVtNZdo0JKBkJB00Az11ST5uPMeoIVNKdmOxcmPpdbVV+9OJK3IrlNmXAgoqmltke/KZEcdxOzd8ApQo8kx2Q==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.523.0.tgz", + "integrity": "sha512-Y6DWdH6/OuMDoNKVzZlNeBc6f1Yjk1lYMjANKpIhMbkRCvLJw/PYZKOZa8WpXbTYdgg9XLjKybnLIb3ww3uuzA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.523.0.tgz", + "integrity": "sha512-6YUtePbn3UFpY9qfVwHFWIVnFvVS5vsbGxxkTO02swvZBvVG4sdG0Xj0AbotUNQNY9QTCN7WkhwIrd50rfDQ9Q==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/property-provider": "^2.1.3", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.1", + "@smithy/types": "^2.10.1", + "@smithy/util-stream": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.523.0.tgz", + "integrity": "sha512-dRch5Ts67FFRZY5r9DpiC3PM6BVHv1tRcy1b26hoqfFkxP9xYH3dsTSPBog1azIqaJa2GcXqEvKCqhghFTt4Xg==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sts": "3.523.0", + "@aws-sdk/credential-provider-env": "3.523.0", + "@aws-sdk/credential-provider-process": "3.523.0", + "@aws-sdk/credential-provider-sso": "3.523.0", + "@aws-sdk/credential-provider-web-identity": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@smithy/credential-provider-imds": "^2.2.3", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.523.0.tgz", + "integrity": "sha512-0aW5ylA8pZmvv/8qA/+iel4acEyzSlHRiaHYL3L0qu9SSoe2a92+RHjrxKl6+Sb55eA2mRfQjaN8oOa5xiYyKA==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.523.0", + "@aws-sdk/credential-provider-http": "3.523.0", + "@aws-sdk/credential-provider-ini": "3.523.0", + "@aws-sdk/credential-provider-process": "3.523.0", + "@aws-sdk/credential-provider-sso": "3.523.0", + "@aws-sdk/credential-provider-web-identity": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@smithy/credential-provider-imds": "^2.2.3", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.523.0.tgz", + "integrity": "sha512-f0LP9KlFmMvPWdKeUKYlZ6FkQAECUeZMmISsv6NKtvPCI9e4O4cLTeR09telwDK8P0HrgcRuZfXM7E30m8re0Q==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.523.0.tgz", + "integrity": "sha512-/VfOJuI8ImV//W4gr+yieF/4shzWAzWYeaaNu7hv161C5YW7/OoCygwRVHSnF4KKeUGQZomZWwml5zHZ57f8xQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso": "3.523.0", + "@aws-sdk/token-providers": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.523.0.tgz", + "integrity": "sha512-EyBwVoTNZrhLRIHly3JnLzy86deT2hHGoxSCrT3+cVcF1Pq3FPp6n9fUkHd6Yel+wFrjpXCRggLddPvajUoXtQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sts": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.523.0.tgz", + "integrity": "sha512-A6uIcr4CuIq6+HTcho8soRmwDzXLVX2cs4U/WbHNOiD9rbLs/3kc4c/kkuGsMcq/pFm2dULxav0YuKyOAi3DEA==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.523.0", + "@aws-sdk/client-sso": "3.523.0", + "@aws-sdk/client-sts": "3.523.0", + "@aws-sdk/credential-provider-cognito-identity": "3.523.0", + "@aws-sdk/credential-provider-env": "3.523.0", + "@aws-sdk/credential-provider-http": "3.523.0", + "@aws-sdk/credential-provider-ini": "3.523.0", + "@aws-sdk/credential-provider-node": "3.523.0", + "@aws-sdk/credential-provider-process": "3.523.0", + "@aws-sdk/credential-provider-sso": "3.523.0", + "@aws-sdk/credential-provider-web-identity": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@smithy/credential-provider-imds": "^2.2.3", + "@smithy/property-provider": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.523.0.tgz", + "integrity": "sha512-4g3q7Ta9sdD9TMUuohBAkbx/e3I/juTqfKi7TPgP+8jxcYX72MOsgemAMHuP6CX27eyj4dpvjH+w4SIVDiDSmg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.523.0.tgz", + "integrity": "sha512-PeDNJNhfiaZx54LBaLTXzUaJ9LXFwDFFIksipjqjvxMafnoVcQwKbkoPUWLe5ytT4nnL1LogD3s55mERFUsnwg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.523.0.tgz", + "integrity": "sha512-nZ3Vt7ehfSDYnrcg/aAfjjvpdE+61B3Zk68i6/hSUIegT3IH9H1vSW67NDKVp+50hcEfzWwM2HMPXxlzuyFyrw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.523.0.tgz", + "integrity": "sha512-5OoKkmAPNaxLgJuS65gByW1QknGvvXdqzrIMXLsm9LjbsphTOscyvT439qk3Jf08TL4Zlw2x+pZMG7dZYuMAhQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@aws-sdk/util-endpoints": "3.523.0", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.523.0.tgz", + "integrity": "sha512-IypIAecBc8b4jM0uVBEj90NYaIsc0vuLdSFyH4LPO7is4rQUet4CkkD+S036NvDdcdxBsQ4hJZBmWrqiizMHhQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/node-config-provider": "^2.2.3", + "@smithy/types": "^2.10.1", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.523.0.tgz", + "integrity": "sha512-m3sPEnLuGV3JY9A8ytcz90SogVtjxEyIxUDFeswxY4C5wP/36yOq3ivenRu07dH+QIJnBhsQdjnHwJfrIetG6g==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso-oidc": "3.523.0", + "@aws-sdk/types": "3.523.0", + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.523.0.tgz", + "integrity": "sha512-AqGIu4u+SxPiUuNBp2acCVcq80KDUFjxe6e3cMTvKWTzCbrVk1AXv0dAaJnCmdkWIha6zJDWxpIk/aL4EGhZ9A==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.523.0.tgz", + "integrity": "sha512-f4qe4AdafjAZoVGoVt69Jb2rXCgo306OOobSJ/f4bhQ0zgAjGELKJATNRRe0J7P28+ffmSxeuYwM3r4gDkD/QA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", + "@smithy/util-endpoints": "^1.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.495.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.495.0.tgz", + "integrity": "sha512-MfaPXT0kLX2tQaR90saBT9fWQq2DHqSSJRzW+MZWsmF+y5LGCOhO22ac/2o6TKSQm7h0HRc2GaADqYYYor62yg==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.523.0.tgz", + "integrity": "sha512-6ZRNdGHX6+HQFqTbIA5+i8RWzxFyxsZv8D3soRfpdyWIKkzhSz8IyRKXRciwKBJDaC7OX2jzGE90wxRQft27nA==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/types": "^2.10.1", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.523.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.523.0.tgz", + "integrity": "sha512-tW7vliJ77EsE8J1bzFpDYCiUyrw2NTcem+J5ddiWD4HA/xNQUyX0CMOXMBZCBA31xLTIchyz0LkZHlDsmB9LUw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.523.0", + "@smithy/node-config-provider": "^2.2.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.0.0.tgz", + "integrity": "sha512-RThY/MnKrhubF6+s1JflwUjPEsnCEmYCWwqa/aRISKWNXGZ9epUwft4bUMM35SdKF9xvBrLydAM1RDHd1Z//ZQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.12.3.tgz", + "integrity": "sha512-jsNnTBlMWuTpDkeE3on7+dWJi0D6fdDfeANj/w7MpS8ztROCoLvIO2nG0CcFj+E4k8j4QrSTh4Oryi3i2G669g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.4.tgz", + "integrity": "sha512-8zJ8N1x51xo9hwPh6AWnKdLGEC5N3lDa6kms1YHmFBoRhTpJR6HG8wWk0td1MVCu9cD4YBrvjZEtd5Obw0Fbnw==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@postman/form-data": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@postman/form-data/-/form-data-3.1.1.tgz", + "integrity": "sha512-vjh8Q2a8S6UCm/KKs31XFJqEEgmbjBmpPNVV2eVav6905wyFAwaUOBGA1NPBI4ERH9MMZc6w0umFgM6WbEPMdg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@postman/tunnel-agent": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@postman/tunnel-agent/-/tunnel-agent-0.6.3.tgz", + "integrity": "sha512-k57fzmAZ2PJGxfOA4SGR05ejorHbVAa/84Hxh/2nAztjNXc4ZjOm9NUIk6/Z6LCrBvJZqjRZbN8e/nROVUPVdg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@sendgrid/client": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@sendgrid/client/-/client-7.7.0.tgz", + "integrity": "sha512-SxH+y8jeAQSnDavrTD0uGDXYIIkFylCo+eDofVmZLQ0f862nnqbC3Vd1ej6b7Le7lboyzQF6F7Fodv02rYspuA==", + "dependencies": { + "@sendgrid/helpers": "^7.7.0", + "axios": "^0.26.0" + }, + "engines": { + "node": "6.* || 8.* || >=10.*" + } + }, + "node_modules/@sendgrid/helpers": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@sendgrid/helpers/-/helpers-7.7.0.tgz", + "integrity": "sha512-3AsAxfN3GDBcXoZ/y1mzAAbKzTtUZ5+ZrHOmWQ279AuaFXUNCh9bPnRpN504bgveTqoW+11IzPg3I0WVgDINpw==", + "dependencies": { + "deepmerge": "^4.2.2" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@sendgrid/mail": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@sendgrid/mail/-/mail-7.7.0.tgz", + "integrity": "sha512-5+nApPE9wINBvHSUxwOxkkQqM/IAAaBYoP9hw7WwgDNQPxraruVqHizeTitVtKGiqWCKm2mnjh4XGN3fvFLqaw==", + "dependencies": { + "@sendgrid/client": "^7.7.0", + "@sendgrid/helpers": "^7.7.0" + }, + "engines": { + "node": "6.* || 8.* || >=10.*" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.1.3.tgz", + "integrity": "sha512-c2aYH2Wu1RVE3rLlVgg2kQOBJGM0WbjReQi5DnPTm2Zb7F0gk7J2aeQeaX2u/lQZoHl6gv8Oac7mt9alU3+f4A==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.1.4.tgz", + "integrity": "sha512-AW2WUZmBAzgO3V3ovKtsUbI3aBNMeQKFDumoqkNxaVDWF/xfnxAWqBKDr/NuG7c06N2Rm4xeZLPiJH/d+na0HA==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.2.4", + "@smithy/types": "^2.10.1", + "@smithy/util-config-provider": "^2.2.1", + "@smithy/util-middleware": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.3.5.tgz", + "integrity": "sha512-Rrc+e2Jj6Gu7Xbn0jvrzZlSiP2CZocIOfZ9aNUA82+1sa6GBnxqL9+iZ9EKHeD9aqD1nU8EK4+oN2EiFpSv7Yw==", + "optional": true, + "dependencies": { + "@smithy/middleware-endpoint": "^2.4.4", + "@smithy/middleware-retry": "^2.1.4", + "@smithy/middleware-serde": "^2.1.3", + "@smithy/protocol-http": "^3.2.1", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/util-middleware": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.2.4.tgz", + "integrity": "sha512-DdatjmBZQnhGe1FhI8gO98f7NmvQFSDiZTwC3WMvLTCKQUY+Y1SVkhJqIuLu50Eb7pTheoXQmK+hKYUgpUWsNA==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.2.4", + "@smithy/property-provider": "^2.1.3", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.1.3.tgz", + "integrity": "sha512-rGlCVuwSDv6qfKH4/lRxFjcZQnIE0LZ3D4lkMHg7ZSltK9rA74r0VuGSvWVQ4N/d70VZPaniFhp4Z14QYZsa+A==", + "optional": true, + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.10.1", + "@smithy/util-hex-encoding": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.4.3.tgz", + "integrity": "sha512-Fn/KYJFo6L5I4YPG8WQb2hOmExgRmNpVH5IK2zU3JKrY5FKW7y9ar5e0BexiIC9DhSKqKX+HeWq/Y18fq7Dkpw==", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^3.2.1", + "@smithy/querystring-builder": "^2.1.3", + "@smithy/types": "^2.10.1", + "@smithy/util-base64": "^2.1.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.1.3.tgz", + "integrity": "sha512-FsAPCUj7VNJIdHbSxMd5uiZiF20G2zdSDgrgrDrHqIs/VMxK85Vqk5kMVNNDMCZmMezp6UKnac0B4nAyx7HJ9g==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.1.3.tgz", + "integrity": "sha512-wkra7d/G4CbngV4xsjYyAYOvdAhahQje/WymuQdVEnXFExJopEu7fbL5AEAlBPgWHXwu94VnCSG00gVzRfExyg==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.1.1.tgz", + "integrity": "sha512-xozSQrcUinPpNPNPds4S7z/FakDTh1MZWtRP/2vQtYB/u3HYrX2UXuZs+VhaKBd6Vc7g2XPr2ZtwGBNDN6fNKQ==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.1.3.tgz", + "integrity": "sha512-aJduhkC+dcXxdnv5ZpM3uMmtGmVFKx412R1gbeykS5HXDmRU6oSsyy2SoHENCkfOGKAQOjVE2WVqDJibC0d21g==", + "optional": true, + "dependencies": { + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.4.4.tgz", + "integrity": "sha512-4yjHyHK2Jul4JUDBo2sTsWY9UshYUnXeb/TAK/MTaPEb8XQvDmpwSFnfIRDU45RY1a6iC9LCnmJNg/yHyfxqkw==", + "optional": true, + "dependencies": { + "@smithy/middleware-serde": "^2.1.3", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/shared-ini-file-loader": "^2.3.4", + "@smithy/types": "^2.10.1", + "@smithy/url-parser": "^2.1.3", + "@smithy/util-middleware": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.1.4.tgz", + "integrity": "sha512-Cyolv9YckZTPli1EkkaS39UklonxMd08VskiuMhURDjC0HHa/AD6aK/YoD21CHv9s0QLg0WMLvk9YeLTKkXaFQ==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.2.4", + "@smithy/protocol-http": "^3.2.1", + "@smithy/service-error-classification": "^2.1.3", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-retry": "^2.1.3", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.1.3.tgz", + "integrity": "sha512-s76LId+TwASrHhUa9QS4k/zeXDUAuNuddKklQzRgumbzge5BftVXHXIqL4wQxKGLocPwfgAOXWx+HdWhQk9hTg==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.1.3.tgz", + "integrity": "sha512-opMFufVQgvBSld/b7mD7OOEBxF6STyraVr1xel1j0abVILM8ALJvRoFbqSWHGmaDlRGIiV9Q5cGbWi0sdiEaLQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.2.4.tgz", + "integrity": "sha512-nqazHCp8r4KHSFhRQ+T0VEkeqvA0U+RhehBSr1gunUuNW3X7j0uDrWBxB2gE9eutzy6kE3Y7L+Dov/UXT871vg==", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^2.1.3", + "@smithy/shared-ini-file-loader": "^2.3.4", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.4.1.tgz", + "integrity": "sha512-HCkb94soYhJMxPCa61wGKgmeKpJ3Gftx1XD6bcWEB2wMV1L9/SkQu/6/ysKBnbOzWRE01FGzwrTxucHypZ8rdg==", + "optional": true, + "dependencies": { + "@smithy/abort-controller": "^2.1.3", + "@smithy/protocol-http": "^3.2.1", + "@smithy/querystring-builder": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.1.3.tgz", + "integrity": "sha512-bMz3se+ySKWNrgm7eIiQMa2HO/0fl2D0HvLAdg9pTMcpgp4SqOAh6bz7Ik6y7uQqSrk4rLjIKgbQ6yzYgGehCQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.2.1.tgz", + "integrity": "sha512-KLrQkEw4yJCeAmAH7hctE8g9KwA7+H2nSJwxgwIxchbp/L0B5exTdOQi9D5HinPLlothoervGmhpYKelZ6AxIA==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.1.3.tgz", + "integrity": "sha512-kFD3PnNqKELe6m9GRHQw/ftFFSZpnSeQD4qvgDB6BQN6hREHELSosVFUMPN4M3MDKN2jAwk35vXHLoDrNfKu0A==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "@smithy/util-uri-escape": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.1.3.tgz", + "integrity": "sha512-3+CWJoAqcBMR+yvz6D+Fc5VdoGFtfenW6wqSWATWajrRMGVwJGPT3Vy2eb2bnMktJc4HU4bpjeovFa566P3knQ==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.3.tgz", + "integrity": "sha512-iUrpSsem97bbXHHT/v3s7vaq8IIeMo6P6cXdeYHrx0wOJpMeBGQF7CB0mbJSiTm3//iq3L55JiEm8rA7CTVI8A==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.3.4.tgz", + "integrity": "sha512-CiZmPg9GeDKbKmJGEFvJBsJcFnh0AQRzOtQAzj1XEa8N/0/uSN/v1LYzgO7ry8hhO8+9KB7+DhSW0weqBra4Aw==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.1.3.tgz", + "integrity": "sha512-Jq4iPPdCmJojZTsPePn4r1ULShh6ONkokLuxp1Lnk4Sq7r7rJp4HlA1LbPBq4bD64TIzQezIpr1X+eh5NYkNxw==", + "optional": true, + "dependencies": { + "@smithy/eventstream-codec": "^2.1.3", + "@smithy/is-array-buffer": "^2.1.1", + "@smithy/types": "^2.10.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-middleware": "^2.1.3", + "@smithy/util-uri-escape": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.4.2.tgz", + "integrity": "sha512-ntAFYN51zu3N3mCd95YFcFi/8rmvm//uX+HnK24CRbI6k5Rjackn0JhgKz5zOx/tbNvOpgQIwhSX+1EvEsBLbA==", + "optional": true, + "dependencies": { + "@smithy/middleware-endpoint": "^2.4.4", + "@smithy/middleware-stack": "^2.1.3", + "@smithy/protocol-http": "^3.2.1", + "@smithy/types": "^2.10.1", + "@smithy/util-stream": "^2.1.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.10.1.tgz", + "integrity": "sha512-hjQO+4ru4cQ58FluQvKKiyMsFg0A6iRpGm2kqdH8fniyNd2WyanoOsYJfMX/IFLuLxEoW6gnRkNZy1y6fUUhtA==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.1.3.tgz", + "integrity": "sha512-X1NRA4WzK/ihgyzTpeGvI9Wn45y8HmqF4AZ/FazwAv8V203Ex+4lXqcYI70naX9ETqbqKVzFk88W6WJJzCggTQ==", + "optional": true, + "dependencies": { + "@smithy/querystring-parser": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.1.1.tgz", + "integrity": "sha512-UfHVpY7qfF/MrgndI5PexSKVTxSZIdz9InghTFa49QOvuu9I52zLPLUHXvHpNuMb1iD2vmc6R+zbv/bdMipR/g==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.1.1.tgz", + "integrity": "sha512-ekOGBLvs1VS2d1zM2ER4JEeBWAvIOUKeaFch29UjjJsxmZ/f0L3K3x0dEETgh3Q9bkZNHgT+rkdl/J/VUqSRag==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.2.1.tgz", + "integrity": "sha512-/ggJG+ta3IDtpNVq4ktmEUtOkH1LW64RHB5B0hcr5ZaWBmo96UX2cIOVbjCqqDickTXqBWZ4ZO0APuaPrD7Abg==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.1.1.tgz", + "integrity": "sha512-clhNjbyfqIv9Md2Mg6FffGVrJxw7bgK7s3Iax36xnfVj6cg0fUG7I4RH0XgXJF8bxi+saY5HR21g2UPKSxVCXg==", + "optional": true, + "dependencies": { + "@smithy/is-array-buffer": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.2.1.tgz", + "integrity": "sha512-50VL/tx9oYYcjJn/qKqNy7sCtpD0+s8XEBamIFo4mFFTclKMNp+rsnymD796uybjiIquB7VCB/DeafduL0y2kw==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.1.4.tgz", + "integrity": "sha512-J6XAVY+/g7jf03QMnvqPyU+8jqGrrtXoKWFVOS+n1sz0Lg8HjHJ1ANqaDN+KTTKZRZlvG8nU5ZrJOUL6VdwgcQ==", + "optional": true, + "dependencies": { + "@smithy/property-provider": "^2.1.3", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.2.3.tgz", + "integrity": "sha512-ttUISrv1uVOjTlDa3nznX33f0pthoUlP+4grhTvOzcLhzArx8qHB94/untGACOG3nlf8vU20nI2iWImfzoLkYA==", + "optional": true, + "dependencies": { + "@smithy/config-resolver": "^2.1.4", + "@smithy/credential-provider-imds": "^2.2.4", + "@smithy/node-config-provider": "^2.2.4", + "@smithy/property-provider": "^2.1.3", + "@smithy/smithy-client": "^2.4.2", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.1.4.tgz", + "integrity": "sha512-/qAeHmK5l4yQ4/bCIJ9p49wDe9rwWtOzhPHblu386fwPNT3pxmodgcs9jDCV52yK9b4rB8o9Sj31P/7Vzka1cg==", + "optional": true, + "dependencies": { + "@smithy/node-config-provider": "^2.2.4", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.1.1.tgz", + "integrity": "sha512-3UNdP2pkYUUBGEXzQI9ODTDK+Tcu1BlCyDBaRHwyxhA+8xLP8agEKQq4MGmpjqb4VQAjq9TwlCQX0kP6XDKYLg==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.1.3.tgz", + "integrity": "sha512-/+2fm7AZ2ozl5h8wM++ZP0ovE9/tiUUAHIbCfGfb3Zd3+Dyk17WODPKXBeJ/TnK5U+x743QmA0xHzlSm8I/qhw==", + "optional": true, + "dependencies": { + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.1.3.tgz", + "integrity": "sha512-Kbvd+GEMuozbNUU3B89mb99tbufwREcyx2BOX0X2+qHjq6Gvsah8xSDDgxISDwcOHoDqUWO425F0Uc/QIRhYkg==", + "optional": true, + "dependencies": { + "@smithy/service-error-classification": "^2.1.3", + "@smithy/types": "^2.10.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.1.3.tgz", + "integrity": "sha512-HvpEQbP8raTy9n86ZfXiAkf3ezp1c3qeeO//zGqwZdrfaoOpGKQgF2Sv1IqZp7wjhna7pvczWaGUHjcOPuQwKw==", + "optional": true, + "dependencies": { + "@smithy/fetch-http-handler": "^2.4.3", + "@smithy/node-http-handler": "^2.4.1", + "@smithy/types": "^2.10.1", + "@smithy/util-base64": "^2.1.1", + "@smithy/util-buffer-from": "^2.1.1", + "@smithy/util-hex-encoding": "^2.1.1", + "@smithy/util-utf8": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.1.1.tgz", + "integrity": "sha512-saVzI1h6iRBUVSqtnlOnc9ssU09ypo7n+shdQ8hBTZno/9rZ3AuRYvoHInV57VF7Qn7B+pFJG7qTzFiHxWlWBw==", + "optional": true, + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.1.1.tgz", + "integrity": "sha512-BqTpzYEcUMDwAKr7/mVRUtHDhs6ZoXDi9NypMvMfOr/+u1NW7JgqodPDECiiLboEm6bobcPcECxzjtQh865e9A==", + "optional": true, + "dependencies": { + "@smithy/util-buffer-from": "^2.1.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", + "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.11.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.21.tgz", + "integrity": "sha512-/ySDLGscFPNasfqStUuWWPfL78jompfIoVzLJPVVAHBh6rpG68+pI2Gk+fNLeI8/f1yPYL4s46EleVIc20F1Ow==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==" + }, + "node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/bcrypt": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", + "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.11", + "node-addon-api": "^5.0.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "dev": true, + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-1.4.0.tgz", + "integrity": "sha512-NpwMDdSIprbYx1CLnfbxEIarI0Z+s9MssEgggMNheGM+WD68yOhV7IEA/3r6tr0yTRgQD0HuZJDw32s99i6L+A==", + "dev": true + }, + "node_modules/charset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz", + "integrity": "sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-progress": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.10.0.tgz", + "integrity": "sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-table3": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "colors": "1.4.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecc-jsbn/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/errorhandler": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.1.tgz", + "integrity": "sha512-rcOwbfvP1WTViVoUjcfZicVzjhjTuhSMntHh6mW3IrEiyE6mJyXvsToJUJGlGlw/2xU9P5whlWNGlIDVeCiT4A==", + "dependencies": { + "accepts": "~1.3.7", + "escape-html": "~1.0.3" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.0.0.tgz", + "integrity": "sha512-IMryZ5SudxzQvuod6rUdIUz29qFItWx281VhtFVc2Psy/ZhlCeD/5DT6lBIJ4H3G+iamGJoTln1v+QSuPw0p7Q==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^3.0.2", + "@eslint/js": "9.0.0", + "@humanwhocodes/config-array": "^0.12.3", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.0.1", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", + "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/espree": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-jwt": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-8.4.1.tgz", + "integrity": "sha512-IZoZiDv2yZJAb3QrbaSATVtTCYT11OcqgFGoTN4iKVyN6NBkBkhtVIixww5fmakF0Upt5HfOxJuS6ZmJVeOtTQ==", + "dependencies": { + "@types/jsonwebtoken": "^9", + "express-unless": "^2.1.3", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/express-session": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", + "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", + "dependencies": { + "cookie": "0.6.0", + "cookie-signature": "1.0.7", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==" + }, + "node_modules/express-unless": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-2.1.3.tgz", + "integrity": "sha512-wj4tLMyCVYuIIKHGt0FhCtIViBcwzWejX0EjNxveAa6dG+0XBCQhMbx+PnkLkFCxLC69qoFrxds4pIyL88inaQ==" + }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", + "dev": true + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "optional": true, + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha512-RLoqTXE8/vPmMuTI88DAzhMYC99I8BWv7zYP4A1puo5HIjEJ5EX48ighy4ZyKMG9EDXxBgW6e++cn7d1xuFghA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flat-cache/node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/flatted": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.0.0.tgz", + "integrity": "sha512-m/C/yR4mjO6pXDTm9/R/SpYTAIyaUB4EOzcaaMEl7mds7Mshct9GfejiJNQGjHHbdMPey13Kpu4TMbYi9ex1pw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/hasown": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-reasons": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", + "integrity": "sha512-P6kYh0lKZ+y29T2Gqz+RlC9WBLhKe8kDmcJ+A+611jFfxdPsbMRQ5aNmFRM3lENqFkK+HTTL+tlQviAiv0AbLQ==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/httpntlm": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.7.tgz", + "integrity": "sha512-Pv2Rvrz8H0qv1Dne5mAdZ9JegG1uc6Vu5lwLflIY6s8RKHdZQbW39L4dYswSgqMDT0pkJILUTKjeyU0VPNRZjA==", + "dev": true, + "dependencies": { + "httpreq": ">=0.4.22", + "underscore": "~1.12.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/httpntlm/node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "dev": true + }, + "node_modules/httpreq": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz", + "integrity": "sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw==", + "dev": true, + "engines": { + "node": ">= 6.15.1" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha512-58yWmlHpp7VYfcdTwMTvwMmqx/Elfxjd9RXTDyMsbL7lLWmhMylLEqiYVLKuLzOZqVgiWXD9MfR62Vv89VRxkw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-sha512": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", + "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/liquid-json": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/liquid-json/-/liquid-json-0.3.1.tgz", + "integrity": "sha512-wUayTU8MS827Dam6MxgD72Ui+KOSF+u/eIqpatOtjnvgJ0+mnDq33uC2M7J0tPK+upe/DpUAuK4JUU89iBoNKQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/method-override": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/method-override/-/method-override-3.0.0.tgz", + "integrity": "sha512-IJ2NNN/mSl9w3kzWB92rcdHpz+HjkxhDJWNDBqSlas+zQdP8wBiJzITPg08M/k2uVvMow7Sk41atndNtt/PHSA==", + "dependencies": { + "debug": "3.1.0", + "methods": "~1.1.2", + "parseurl": "~1.3.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/method-override/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-format": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mime-format/-/mime-format-2.0.1.tgz", + "integrity": "sha512-XxU3ngPbEnrYnNbIX+lYSaYg0M01v6p2ntd2YaFksTu0vayaw5OJvbdRyWs07EYRlLED5qadUZ+xo+XhOvFhwg==", + "dev": true, + "dependencies": { + "charset": "^1.0.0" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mongodb": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.2.tgz", + "integrity": "sha512-mLV7SEiov2LHleRJPMPrK2PMyhXFZt2UQLC4VD4pnth3jMjYKHhtqfwwkkvS/NXuo/Fp3vbhaNcXrIDaLRb9Tg==", + "dependencies": { + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "@mongodb-js/saslprep": "^1.1.0" + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongoose": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.12.6.tgz", + "integrity": "sha512-VFxDnWj8esgswwplmpQYMT+lYcvuIhl76WDLz/vgp41/FOhBPM/n3GjyztK8R3r2ljsM6kudvKgqLhfcZEih1Q==", + "dependencies": { + "bson": "^4.7.2", + "kareem": "2.5.1", + "mongodb": "4.17.2", + "mpath": "0.9.0", + "mquery": "4.0.3", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/mongoose-unique-validator": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mongoose-unique-validator/-/mongoose-unique-validator-3.1.0.tgz", + "integrity": "sha512-UsBBlFapip8gc8x1h+nLWnkOy+GTy9Z+zmTyZ35icLV3EoLIVz180vJzepfMM9yBy2AJh+maeuoM8CWtqejGUg==", + "dependencies": { + "lodash.foreach": "^4.1.0", + "lodash.get": "^4.0.2", + "lodash.merge": "^4.6.2" + }, + "peerDependencies": { + "mongoose": "^6.0.0" + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", + "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/mquery/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mquery/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/newman": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/newman/-/newman-5.3.2.tgz", + "integrity": "sha512-cWy8pV0iwvMOZLTw3hkAHcwo2ZA0GKkXm8oUMn1Ltii3ZI2nKpnrg9QGdIT0hGHChRkX6prY5e3Aar7uykMGNg==", + "dev": true, + "dependencies": { + "async": "3.2.3", + "chardet": "1.4.0", + "cli-progress": "3.10.0", + "cli-table3": "0.6.1", + "colors": "1.4.0", + "commander": "7.2.0", + "csv-parse": "4.16.3", + "eventemitter3": "4.0.7", + "filesize": "8.0.7", + "lodash": "4.17.21", + "mkdirp": "1.0.4", + "postman-collection": "4.1.1", + "postman-collection-transformer": "4.1.6", + "postman-request": "2.88.1-postman.31", + "postman-runtime": "7.29.0", + "pretty-ms": "7.0.1", + "semver": "7.3.5", + "serialised-error": "1.1.3", + "tough-cookie": "3.0.1", + "word-wrap": "1.2.3", + "xmlbuilder": "15.1.1" + }, + "bin": { + "newman": "bin/newman.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/newman/node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true + }, + "node_modules/newman/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-oauth1": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/node-oauth1/-/node-oauth1-1.3.0.tgz", + "integrity": "sha512-0yggixNfrA1KcBwvh/Hy2xAS1Wfs9dcg6TdFf2zN7gilcAigMdrtZ4ybrBSXBgLvGDw9V1p2MRnGBMq7XjTWLg==", + "dev": true + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/passport": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", + "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1", + "utils-merge": "^1.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-headerapikey": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/passport-headerapikey/-/passport-headerapikey-1.2.2.tgz", + "integrity": "sha512-4BvVJRrWsNJPrd3UoZfcnnl4zvUWYKEtfYkoDsaOKBsrWHYmzTApCjs7qUbncOLexE9ul0IRiYBFfBG0y9IVQA==", + "dependencies": { + "lodash": "^4.17.15", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==", + "dependencies": { + "passport-strategy": "1.x.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postman-collection": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/postman-collection/-/postman-collection-4.1.1.tgz", + "integrity": "sha512-ODpJtlf8r99DMcTU7gFmi/yvQYckFzcuE6zL/fWnyrFT34ugdCBFlX+DN7M+AnP6lmR822fv5s60H4DnL4+fAg==", + "dev": true, + "dependencies": { + "faker": "5.5.3", + "file-type": "3.9.0", + "http-reasons": "0.1.0", + "iconv-lite": "0.6.3", + "liquid-json": "0.3.1", + "lodash": "4.17.21", + "mime-format": "2.0.1", + "mime-types": "2.1.34", + "postman-url-encoder": "3.0.5", + "semver": "7.3.5", + "uuid": "8.3.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection-transformer": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/postman-collection-transformer/-/postman-collection-transformer-4.1.6.tgz", + "integrity": "sha512-xvdQb6sZoWcG9xZXUPSuxocjcd6WCZlINlGGiuHdSfxhgiwQhj9qhF0JRFbagZ8xB0+pYUairD5MiCENc6DEVA==", + "dev": true, + "dependencies": { + "commander": "8.3.0", + "inherits": "2.0.4", + "lodash": "4.17.21", + "semver": "7.3.5", + "strip-json-comments": "3.1.1" + }, + "bin": { + "postman-collection-transformer": "bin/transform-collection.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection-transformer/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/postman-collection-transformer/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postman-collection/node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/postman-collection/node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/postman-collection/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-collection/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/postman-request": { + "version": "2.88.1-postman.31", + "resolved": "https://registry.npmjs.org/postman-request/-/postman-request-2.88.1-postman.31.tgz", + "integrity": "sha512-OJbYqP7ItxQ84yHyuNpDywCZB0HYbpHJisMQ9lb1cSL3N5H3Td6a2+3l/a74UMd3u82BiGC5yQyYmdOIETP/nQ==", + "dev": true, + "dependencies": { + "@postman/form-data": "~3.1.1", + "@postman/tunnel-agent": "^0.6.3", + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "brotli": "~1.3.2", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "har-validator": "~5.1.3", + "http-signature": "~1.3.1", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "stream-length": "^1.0.2", + "tough-cookie": "~2.5.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postman-request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/postman-request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/postman-request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/postman-runtime": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/postman-runtime/-/postman-runtime-7.29.0.tgz", + "integrity": "sha512-eXxHREE/fUpohkGPRgBY1YccSGx9cyW3mtGiPyIE4zD5fYzasgBHqW6kbEND3Xrd3yf/uht/YI1H8O7J1+A1+w==", + "dev": true, + "dependencies": { + "async": "3.2.3", + "aws4": "1.11.0", + "handlebars": "4.7.7", + "httpntlm": "1.7.7", + "js-sha512": "0.8.0", + "lodash": "4.17.21", + "mime-types": "2.1.34", + "node-oauth1": "1.3.0", + "performance-now": "2.1.0", + "postman-collection": "4.1.1", + "postman-request": "2.88.1-postman.31", + "postman-sandbox": "4.0.6", + "postman-url-encoder": "3.0.5", + "serialised-error": "1.1.3", + "tough-cookie": "3.0.1", + "uuid": "8.3.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-runtime/node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true + }, + "node_modules/postman-runtime/node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/postman-runtime/node_modules/mime-db": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", + "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/postman-runtime/node_modules/mime-types": { + "version": "2.1.34", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", + "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "dev": true, + "dependencies": { + "mime-db": "1.51.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/postman-runtime/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/postman-sandbox": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postman-sandbox/-/postman-sandbox-4.0.6.tgz", + "integrity": "sha512-PPRanSNEE4zy3kO7CeSBHmAfJnGdD9ecHY/Mjh26CQuZZarGkNO8c0U/n+xX3+5M1BRNc82UYq6YCtdsSDqcng==", + "dev": true, + "dependencies": { + "lodash": "4.17.21", + "teleport-javascript": "1.0.0", + "uvm": "2.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postman-url-encoder": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postman-url-encoder/-/postman-url-encoder-3.0.5.tgz", + "integrity": "sha512-jOrdVvzUXBC7C+9gkIkpDJ3HIxOHTIqjpQ4C1EMt1ZGeMvSEpbFCKq23DEfgsj46vMnDgyQf+1ZLp2Wm+bKSsA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, + "dependencies": { + "parse-ms": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/request/node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serialised-error": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/serialised-error/-/serialised-error-1.1.3.tgz", + "integrity": "sha512-vybp3GItaR1ZtO2nxZZo8eOo7fnVaNtP3XE2vJKgzkKR2bagCkdJ1EpYYhEMd3qu/80DwQk9KjsNSxE3fXWq0g==", + "dev": true, + "dependencies": { + "object-hash": "^1.1.2", + "stack-trace": "0.0.9", + "uuid": "^3.0.0" + } + }, + "node_modules/serialised-error/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sift": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/slug": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/slug/-/slug-8.2.3.tgz", + "integrity": "sha512-fXjhAZszNecz855GUNIwW0+sFPi9WV4bMiEKDOCA4wcq1ts1UnUVNy/F78B0Aat7/W3rA+se//33ILKNMrbeYQ==", + "bin": { + "slug": "cli.js" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha512-vjUc6sfgtgY0dxCdnc40mK6Oftjo9+2K8H/NG81TMhgL392FtiPA9tn9RLyTxXmTLPJPjF3VyzFp6bsWFLisMQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-length/-/stream-length-1.0.2.tgz", + "integrity": "sha512-aI+qKFiwoDV4rsXiS7WRoCt+v2RX1nUj17+KJC5r2gfh5xoSJIfP6Y3Do/HtvesFcTSWthIuJ3l1cvKQY/+nZg==", + "dev": true, + "dependencies": { + "bluebird": "^2.6.2" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "optional": true + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/teleport-javascript": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/teleport-javascript/-/teleport-javascript-1.0.0.tgz", + "integrity": "sha512-j1llvWVFyEn/6XIFDfX5LAU43DXe0GCt3NfXDwJ8XpRRMkS+i50SAkonAONBy+vxwPFBd50MFU8a2uj8R/ccLg==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tough-cookie": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "dev": true, + "dependencies": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "optional": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uvm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uvm/-/uvm-2.0.2.tgz", + "integrity": "sha512-Ra+aPiS5GXAbwXmyNExqdS42sTqmmx4XWEDF8uJlsTfOkKf9Rd9xNgav1Yckv4HfVEZg4iOFODWHFYuJ+9Fzfg==", + "dev": true, + "dependencies": { + "flatted": "3.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ace2425 --- /dev/null +++ b/package.json @@ -0,0 +1,57 @@ +{ + "name": "hu-api", + "version": "1.0.0", + "description": "Ad Astra API", + "main": "app.js", + "author": "Solide Apps ", + "contributors": [ + "Julien Gautier " + ], + "scripts": { + "start": "APP_ENV=production node ./app.js", + "dev": "APP_ENV=development nodemon ./app.js", + "local": "APP_ENV=local nodemon ./app.js", + "test": "newman run ./tests/api-tests.postman.json -e ./tests/env-api-tests.postman.json", + "stop": "lsof -ti :3200 | xargs kill", + "mongo:start": "docker run --name hu-mongo -p 27017:27017 mongo & sleep 5", + "mongo:stop": "docker stop hu-mongo && docker rm hu-mongo" + }, + "engines": { + "node": "^16.20.2 || ^18.19.1 || ^20.11.1" + }, + "license": "UNLICENSED", + "private": true, + "dependencies": { + "@sendgrid/mail": "^7.7.0", + "bcrypt": "^5.1.1", + "body-parser": "^1.20.2", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "ejs": "^3.1.9", + "errorhandler": "^1.5.1", + "express": "^4.18.2", + "express-jwt": "^8.4.1", + "express-session": "^1.18.0", + "jsonwebtoken": "^9.0.2", + "method-override": "3.0.0", + "methods": "1.1.2", + "mongoose": "^6.12.6", + "mongoose-unique-validator": "^3.1.0", + "morgan": "^1.10.0", + "node-fetch": "^3.3.2", + "passport": "^0.6.0", + "passport-headerapikey": "^1.2.2", + "passport-local": "^1.0.0", + "request": "^2.88.2", + "slug": "^8.2.3", + "underscore": "^1.13.6", + "uuid": "^9.0.1" + }, + "devDependencies": { + "@eslint/js": "^9.0.0", + "eslint": "^9.0.0", + "globals": "^15.0.0", + "newman": "^5.3.2", + "nodemon": "^2.0.22" + } +} diff --git a/public/.keep b/public/.keep new file mode 100644 index 0000000..e69de29 diff --git a/qcm.json b/qcm.json new file mode 100644 index 0000000..a1e71a1 --- /dev/null +++ b/qcm.json @@ -0,0 +1,3563 @@ +{ + "qcm": [ + { + "name": "bpa", + "categories": [ + { + "num": 1, + "name": "Aéronefs", + "questions": [ + { + "num": 1, + "libelle": "La position correcte du trim avant le décollage à pleine charge est :", + "answers": [ + {"index": "A", "libelle": "Extrémité vers le haut", "correct": false}, + {"index": "B", "libelle": "Extrémité vers le bas", "correct": true} + ] + }, + { + "num": 2, + "libelle": "A bord de l’avion :", + "answers": [ + {"index": "A", "libelle": "La répartition de masse a une influence directe sur le centrage et la stabilité de l’avion.", "correct": true}, + {"index": "B", "libelle": "La répartition de masse n’a pas d’importance pour le vol.", "correct": false} + ] + }, + { + "num": 3, + "libelle": "Peut-on se déplacer à bord de l’avion pendant le décollage ?", + "answers": [ + {"index": "A", "libelle": "Non car cela modifie le centrage de l’avion.", "correct": true}, + {"index": "B", "libelle": "Oui sans problème.", "correct": false} + ] + }, + { + "num": 4, + "libelle": "Lors du décollage, si les parachutistes se déplacent inconsidérément à bord de l’avion, celui ci peut décrocher.", + "answers": [ + {"index": "A", "libelle": "Vrai", "correct": true}, + {"index": "B", "libelle": "Faux", "correct": false} + ] + }, + { + "num": 5, + "libelle": "Un vent de travers est dangereux pour l’avion.", + "answers": [ + {"index": "A", "libelle": "Au décollage et à l’atterrissage si on dépasse la limite de vent recommandée pour l’avion.", "correct": true}, + {"index": "B", "libelle": "N’est pas dangereux si l’avion n’est pas en surcharge.", "correct": false} + ] + }, + { + "num": 6, + "libelle": "Durant les manœuvres de décollage et d’atterrissage, parler au pilote présente une gène, voir un risque.", + "answers": [ + {"index": "A", "libelle": "Faux", "correct": false}, + {"index": "B", "libelle": "Vrai", "correct": true} + ] + }, + { + "num": 7, + "libelle": "Une vitesse de largage trop faible peut entraîner :", + "answers": [ + {"index": "A", "libelle": "Un risque de percuter le plan fixe.", "correct": false}, + {"index": "B", "libelle": "Un risque de décrochage.", "correct": true}, + {"index": "C", "libelle": "Un meilleur confort pour la sortie.", "correct": false} + ] + }, + { + "num": 8, + "libelle": "Pour l’atterrissage et le décollage, la sortie des dispositifs hypersustentateurs (volets) est pour le pilote :", + "answers": [ + {"index": "A", "libelle": "Fonction de paramètres tels que vent, longueur de piste, etc.", "correct": true}, + {"index": "B", "libelle": "Obligatoire quel que soit le cas.", "correct": false}, + {"index": "C", "libelle": "Interdit quel que soit le cas.", "correct": false} + ] + }, + { + "num": 9, + "libelle": "A bord de l’avion, pendant la montée, vous remarquez un écoulement de liquide.", + "answers": [ + {"index": "A", "libelle": "Vous prévenez immédiatement le pilote.", "correct": true}, + {"index": "B", "libelle": "Vous sautez normalement et en arrivant au sol vous prévenez le directeur technique.", "correct": false}, + {"index": "C", "libelle": "Vous ne dites rien à personne.", "correct": false} + ] + }, + { + "num": 10, + "libelle": "En montant à bord de l’avion, vous remarquez une arrête coupante dans l’encadrement de porte.", + "answers": [ + {"index": "A", "libelle": "Vous sautez et vous prévenez le directeur technique une fois arrivé au sol.", "correct": false}, + {"index": "B", "libelle": "Vous ne dites rien et vous sautez en faisant attention en sortant.", "correct": false}, + {"index": "C", "libelle": "Vous prévenez immédiatement le pilote et les parachutistes.", "correct": true} + ] + }, + { + "num": 11, + "libelle": "En montant à bord de l’avion avec 9 parachutistes, vous remarquez que le trim du Pilatus est en position « plein cabré » avant le décollage.", + "answers": [ + {"index": "A", "libelle": "Vous ne dites rien car c’est une position de trim normale au décollage en pleine charge pour un Pilatus.", "correct": false}, + {"index": "B", "libelle": "Vous ne dites rien car cette position n’a pas d’influence sur le décollage, quelle que soit la charge et le centrage du Pilatus.", "correct": false}, + {"index": "C", "libelle": "Vous en informez immédiatement le pilote.", "correct": true} + ] + }, + { + "num": 12, + "libelle": "La vitesse de largage d’un avion est définie par le manuel de vol.", + "answers": [ + {"index": "A", "libelle": "Vrai", "correct": false}, + {"index": "B", "libelle": "Faux", "correct": true} + ] + }, + { + "num": 13, + "libelle": "Au moment de monter à bord de l’avion, vous remarquer une fuite de carburant venant d’un réservoir.", + "answers": [ + {"index": "A", "libelle": "Vous attendez d’avoir effectué le saut pour prévenir le directeur technique.", "correct": false}, + {"index": "B", "libelle": "C’est anormal, vous prévenez immédiatement le pilote.", "correct": true}, + {"index": "C", "libelle": "C’est normal à cause de la dilatation ; vous ne dites rien.", "correct": false} + ] + }, + { + "num": 14, + "libelle": "Les avions ayant une issue de saut à l’arrière de la carlingue sont très sensibles aux problèmes de centrage.", + "answers": [ + {"index": "A", "libelle": "Vrai", "correct": true}, + {"index": "B", "libelle": "Faux", "correct": false} + ] + }, + { + "num": 15, + "libelle": "Le centrage peut limiter le nombre de parachutistes pouvant effectuer une sortie de groupe.", + "answers": [ + {"index": "A", "libelle": "Vrai", "correct": true}, + {"index": "B", "libelle": "Faux", "correct": false} + ] + }, + { + "num": 16, + "libelle": "Un nombre trop important de parachutistes effectuant une sortie de groupe sur un avion ayant une issue de saut située à l’arrière peut induire :", + "answers": [ + {"index": "A", "libelle": "Uniquement un décrochage.", "correct": false}, + {"index": "B", "libelle": "Uniquement un départ en tonneaux.", "correct": false}, + {"index": "C", "libelle": "Uniquement une vrille à plat.", "correct": false}, + {"index": "D", "libelle": "Un des points précédents et éventuellement une combinaison des trois propositions précédentes.", "correct": true} + ] + }, + { + "num": 17, + "libelle": "Au moment d’embarquer, vous remarquez d’importantes traînées d’huile sous la carlingue de l’avion.", + "answers": [ + {"index": "A", "libelle": "C’est normal car il y a toujours des fuites.", "correct": false}, + {"index": "B", "libelle": "Vous prévenez immédiatement le pilote.", "correct": true} + ] + }, + { + "num": 18, + "libelle": "La vitesse de largage est définie par :", + "answers": [ + {"index": "A", "libelle": "Le constructeur et consignée dans le manuel de vol.", "correct": true}, + {"index": "B", "libelle": "Le pilote.", "correct": false}, + {"index": "C", "libelle": "Les parachutistes en fonction du type de saut.", "correct": false} + ] + }, + { + "num": 19, + "libelle": "Au moment d’embarquer, vous remarquez une crique (fissure) sur le plan fixe de l’avion.", + "answers": [ + {"index": "A", "libelle": "Vous attendez d’avoir effectué votre saut pour avertir le directeur technique.", "correct": false}, + {"index": "B", "libelle": "Vous avertissez immédiatement le pilote.", "correct": true}, + {"index": "C", "libelle": "Vous ne dites rien, le pilote ayant effectué une visite pré-vol sait ce qu’il fait.", "correct": false} + ] + }, + { + "num": 20, + "libelle": "La vitesse de largage d’un Pilatus est d’environ :", + "answers": [ + {"index": "A", "libelle": "110 kts.", "correct": false}, + {"index": "B", "libelle": "70 kts.", "correct": true}, + {"index": "C", "libelle": "45 kts.", "correct": false} + ] + }, + { + "num": 21, + "libelle": "La vitesse de largage d’un Cessna (206 ; 207) est d ‘environ :", + "answers": [ + {"index": "A", "libelle": "50 kts.", "correct": false}, + {"index": "B", "libelle": "80 kts.", "correct": true}, + {"index": "C", "libelle": "105 kts.", "correct": false} + ] + }, + { + "num": 22, + "libelle": "La vitesse de largage d’un Cessna Caravan est d ‘environ :", + "answers": [ + {"index": "A", "libelle": "100 kts.", "correct": false}, + {"index": "B", "libelle": "80 kts.", "correct": true}, + {"index": "C", "libelle": "70 kts.", "correct": false} + ] + }, + { + "num": 23, + "libelle": "La vitesse de largage d’un gros porteur Type Hercules est d’environ :", + "answers": [ + {"index": "A", "libelle": "200 kts.", "correct": false}, + {"index": "B", "libelle": "120 kts.", "correct": true}, + {"index": "C", "libelle": "70 kts.", "correct": false} + ] + }, + { + "num": 24, + "libelle": "Une vitesse de largage trop importante pour un avion léger de type CESSNA peut entraîner une collision d’un chuteur avec le plan fixe.", + "answers": [ + {"index": "A", "libelle": "Faux", "correct": false}, + {"index": "B", "libelle": "Vrai", "correct": true} + ] + } + ] + }, + { + "num": 2, + "name": "Altimètre", + "questions": [ + { + "num": 25, + "libelle": "Plus on monte en altitude.", + "answers": [ + {"index": "A", "libelle": "Plus un altimètre est précis.", "correct": false}, + {"index": "B", "libelle": "Moins un altimètre est précis.", "correct": true} + ] + }, + { + "num": 26, + "libelle": "A 1000 mètres, une précision de + ou – 200 mètres sur un altimètre est-elle satisfaisante ?", + "answers": [ + {"index": "A", "libelle": "C’est à la limite de l’acceptable.", "correct": false}, + {"index": "B", "libelle": "Non.", "correct": true}, + {"index": "C", "libelle": "Oui.", "correct": false} + ] + }, + { + "num": 27, + "libelle": "« Tapoter » sur un altimètre pour faire se déplacer l’aiguille :", + "answers": [ + {"index": "A", "libelle": "N’a aucune conséquence.", "correct": false}, + {"index": "B", "libelle": "Est indispensable pour remettre l’aiguille à zéro.", "correct": false}, + {"index": "C", "libelle": "Augmente le jeu normal du fonctionnement et n’apporte qu’un vieillissement prématuré de l’appareil.", "correct": true} + ] + }, + { + "num": 28, + "libelle": "Les « altisons » ont-ils tous une alarme sonore de non fonctionnement ou de mauvais fonctionnement ?", + "answers": [ + {"index": "A", "libelle": "Oui.", "correct": false}, + {"index": "B", "libelle": "Non.", "correct": true} + ] + } + ] + }, + { + "num": 3, + "name": "Déclencheurs et matériels", + "questions": [ + { + "num": 29, + "libelle": "La FXC 12000 :", + "answers": [ + {"index": "A", "libelle": "Déclenche à une hauteur fixe à partir d’une vitesse supérieure à 12 m/s.", "correct": false}, + {"index": "B", "libelle": "Déclenche à une hauteur que l’on règle avant chaque saut à partir d’une vitesse supérieure à 0,5 m/s.", "correct": false}, + {"index": "C", "libelle": "Déclenche à une hauteur fixe à partir d’une vitesse supérieure à 0,5 m/s.", "correct": false}, + {"index": "D", "libelle": "Déclenche à une hauteur que l’on règle avant chaque saut à partir d’une vitesse supérieure à 12 m/s 0", "correct": true} + ] + }, + { + "num": 30, + "libelle": "Sur une FXC 12000 réglé avant le saut si l’aiguille disparaît pendant la montée en avion :", + "answers": [ + {"index": "A", "libelle": "Elle est en panne, il ne faut pas sauter.", "correct": false}, + {"index": "B", "libelle": "Il faut le signaler à un moniteur après le saut.", "correct": false}, + {"index": "C", "libelle": "C’est normal, l’aiguille disparaît à la hauteur de réglage.", "correct": true} + ] + }, + { + "num": 31, + "libelle": "Un déclencheur FXC 12000 dont l’aiguille de réglage est sur le 1 signifie :", + "answers": [ + {"index": "A", "libelle": "Réglage à 100 m.", "correct": false}, + {"index": "B", "libelle": "Réglage à 1000 m.", "correct": false}, + {"index": "C", "libelle": "Réglage à 1000 pieds (soit sensiblement 300 m).", "correct": true} + ] + }, + { + "num": 32, + "libelle": "Le saut est annulé, l’avion redescend rapidement, les déclencheurs de sécurité de type FXC 12000 peuvent fonctionner dans l’avion.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 33, + "libelle": "Les déclencheurs FXC 12000 réglés sur 1000 pieds peuvent déclencher à partir de 400 m.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 34, + "libelle": "Le saut est annulé, l’avion redescend à pleine charge, les déclencheurs FXC 12000 doivent être neutralisés en plaçant la molette sur off (couleur verte).", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 35, + "libelle": "Si un Cypres 2 est mouillé suite à une courte immersion à moins de 1,5 m de profondeur :", + "answers": [ + {"index": "A", "libelle": "Il faut faire changer le filtre de l’appareil.", "correct": true}, + {"index": "B", "libelle": "Il n’y a pas d’opération particulière à faire effectuer.", "correct": false} + ] + }, + { + "num": 36, + "libelle": "Si un Cypres affiche le code 0, cela signifie :", + "answers": [ + {"index": "A", "libelle": "Qu’il faut faire changer les piles.", "correct": false}, + {"index": "B", "libelle": "Qu’il faut l’éteindre et le remettre en fonction.", "correct": false}, + {"index": "C", "libelle": "Que le déclencheur est prêt à être utilisé.", "correct": true} + ] + }, + { + "num": 37, + "libelle": "Lors d’un posé hors zone, si l’atterrissage se fait à une hauteur de ± 10 mètres par rapport à la zone de saut habituelle, il faut éteindre le Cypres et le remettre en route le avant le prochain saut.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Faux. Seulement si la différence de hauteur excède ± 30 mètres.", "correct": false}, + {"index": "C", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 38, + "libelle": "Au bout de combien de temps un Cypres doit-il être envoyé en révision ?", + "answers": [ + {"index": "A", "libelle": "Tous les ans.", "correct": false}, + {"index": "B", "libelle": "Il n’y a pas besoin de le faire réviser, il faut simplement changer les piles tous les deux ans.", "correct": true}, + {"index": "C", "libelle": "Il faut le faire réviser quand on change les piles.", "correct": false}, + {"index": "D", "libelle": "Il faut le faire réviser tous les quatre ans.", "correct": false} + ] + }, + { + "num": 39, + "libelle": "Le Cypres expert :", + "answers": [ + {"index": "A", "libelle": "Déclenche à une hauteur fixe à partir d’une vitesse supérieure à 35 m/s.", "correct": true}, + {"index": "B", "libelle": "Déclenche à une hauteur qu’il faut régler avant chaque saut à partir d’une vitesse supérieure à 13 m/s.", "correct": false}, + {"index": "C", "libelle": "Déclenche à une hauteur qu’il faut régler avant chaque saut à partir d’une vitesse supérieure à 35 m/s.", "correct": false}, + {"index": "D", "libelle": "Déclenche à une hauteur fixe à partir d’une vitesse supérieure à 13 m/s.", "correct": false} + ] + }, + { + "num": 40, + "libelle": "Le Cypres école :", + "answers": [ + {"index": "A", "libelle": "Déclenche à 300m à partir d’une vitesse supérieure à 35 m/s.", "correct": false}, + {"index": "B", "libelle": "Déclenche à 225m une à partir d’une vitesse supérieure à 13 m/s.", "correct": false}, + {"index": "C", "libelle": "Déclenche à une hauteur qu’il faut régler avant chaque saut à partir d’une vitesse supérieure à 35 m/s.", "correct": false}, + {"index": "D", "libelle": "Déclenche à 300m à partir d’une vitesse supérieure à 13 m/s, et à 225m à partir d’une vitesse supérieure à 35m/s.", "correct": true} + ] + }, + { + "num": 41, + "libelle": "Si la vitesse est suffisante, un déclencheur Cypres confirmé déclenche à une hauteur de :", + "answers": [ + {"index": "A", "libelle": "225 m.", "correct": true}, + {"index": "B", "libelle": "315 m.", "correct": false}, + {"index": "C", "libelle": "175 m.", "correct": false} + ] + }, + { + "num": 42, + "libelle": "En cas de descente rapide avec l’avion, un déclencheur Cypres confirmé peut-il déclencher ?", + "answers": [ + {"index": "A", "libelle": "Non.", "correct": false}, + {"index": "B", "libelle": "Oui.", "correct": true} + ] + }, + { + "num": 43, + "libelle": "La vitesse de chute minimum nécessaire pour déclencher un Cypres confirmé est supérieure ou égale à :", + "answers": [ + {"index": "A", "libelle": "30 m/s.", "correct": false}, + {"index": "B", "libelle": "35 m/s.", "correct": true}, + {"index": "C", "libelle": "25 m/s.", "correct": false} + ] + }, + { + "num": 44, + "libelle": "La vitesse de chute minimum nécessaire pour déclencher un Cypres élève est supérieure ou égale à :", + "answers": [ + {"index": "A", "libelle": "35 m/s à partir de 300m.", "correct": false}, + {"index": "B", "libelle": "13 m/s à partir de 225 m.", "correct": false}, + {"index": "C", "libelle": "13 m/s à partir de 300m.", "correct": true} + ] + }, + { + "num": 45, + "libelle": "En cas d’action du Cypres, il y a :", + "answers": [ + {"index": "A", "libelle": "Sectionnement de la bouclette de fermeture (loop) du conteneur secours.", "correct": true}, + {"index": "B", "libelle": "Extraction de l’aiguille du conteneur secours.", "correct": false}, + {"index": "C", "libelle": "Libération de la voilure principale.", "correct": false} + ] + }, + { + "num": 46, + "libelle": "Le Cypres 2 doit être renvoyé en révision :", + "answers": [ + {"index": "A", "libelle": "Tous les 4 ans.", "correct": true}, + {"index": "B", "libelle": "Tous les 2 ans ou tous les 800 sauts.", "correct": false}, + {"index": "C", "libelle": "Tous les 2 ans.", "correct": false} + ] + }, + { + "num": 47, + "libelle": "Les batteries d’un Cypres 2 sont changées :", + "answers": [ + {"index": "A", "libelle": "Tous les 2 ans ou tous les 800 sauts.", "correct": false}, + {"index": "B", "libelle": "Tous les 4 ans.", "correct": true}, + {"index": "C", "libelle": "Après chaque déclenchement.", "correct": false}, + {"index": "D", "libelle": "A chaque contrôle périodique du parachute.", "correct": false} + ] + }, + { + "num": 48, + "libelle": "Le boîtier de contrôle d’un Cypres élève en fonction indique :", + "answers": [ + {"index": "A", "libelle": "Student.", "correct": false}, + {"index": "B", "libelle": "Jump.", "correct": false}, + {"index": "C", "libelle": "Rien d’écrit.", "correct": false}, + {"index": "D", "libelle": "0.", "correct": true} + ] + }, + { + "num": 49, + "libelle": "Le Cypres doit être « réarmé » tous les matins même s’il est encore en marche.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 50, + "libelle": "Le Cypres s’éteint automatiquement 14 heures après sa mise en route.", + "answers": [ + {"index": "A", "libelle": "Oui.", "correct": true}, + {"index": "B", "libelle": "Sauf si l’on resaute entre temps.", "correct": false}, + {"index": "C", "libelle": "Sauf si les batteries sont faibles.", "correct": false} + ] + }, + { + "num": 51, + "libelle": "En cas d’évacuation à 300m pendant la montée, le Cypres (confirmé et élève) peut déclencher.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": false}, + {"index": "B", "libelle": "Faux car il ne s’active que s’il a dépassé une hauteur de 450m.", "correct": true}, + {"index": "C", "libelle": "Faux car il ne s’active que s’il a dépassé une hauteur de 900m.", "correct": false} + ] + }, + { + "num": 52, + "libelle": "Le Vigile possède trois modes d’utilisation.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Cela dépend des modèles.", "correct": false}, + {"index": "C", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 53, + "libelle": "La révision du vigil doit être effectuée :", + "answers": [ + {"index": "A", "libelle": "Tous les quatre ans.", "correct": false}, + {"index": "B", "libelle": "Uniquement dans le cas d’un message d’erreur.", "correct": true}, + {"index": "C", "libelle": "Tous les 700 sauts.", "correct": false} + ] + }, + { + "num": 54, + "libelle": "Le changement des piles sur un vigil s’effectue :", + "answers": [ + {"index": "A", "libelle": "A l’apparition du message « bat low ».", "correct": true}, + {"index": "B", "libelle": "Tous les deux ans.", "correct": false}, + {"index": "C", "libelle": "Jamais.", "correct": false} + ] + }, + { + "num": 55, + "libelle": "Pour les versions confirmées, les hauteurs de déclenchement du Vigil et du Cypres sont sensiblement identiques.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 56, + "libelle": "La vitesse de déclenchement du vigil en mode « pro » est de :", + "answers": [ + {"index": "A", "libelle": "20 m/s.", "correct": false}, + {"index": "B", "libelle": "12 m/s.", "correct": false}, + {"index": "C", "libelle": "35 m/s.", "correct": true} + ] + }, + { + "num": 57, + "libelle": "La hauteur de déclenchement du vigil en mode « pro » est de :", + "answers": [ + {"index": "A", "libelle": "256 mètres.", "correct": true}, + {"index": "B", "libelle": "216 mètres.", "correct": false}, + {"index": "C", "libelle": "225 mètres.", "correct": false} + ] + }, + { + "num": 58, + "libelle": "La vitesse de déclenchement du vigil en mode « student » est de :", + "answers": [ + {"index": "A", "libelle": "12 m/s.", "correct": false}, + {"index": "B", "libelle": "20 m/s.", "correct": true}, + {"index": "C", "libelle": "35 m/s.", "correct": false} + ] + }, + { + "num": 59, + "libelle": "Qu’est-ce qu’un système de rétraction ?", + "answers": [ + {"index": "A", "libelle": "C’est le système qui permet de déventer l’extracteur après l’ouverture.", "correct": false}, + {"index": "B", "libelle": "C’est l’action de tirer sur les élévateurs.", "correct": true} + ] + }, + { + "num": 60, + "libelle": "Lors du repliage du parachute de secours :", + "answers": [ + {"index": "A", "libelle": "Le plieur qualifié contrôle la voilure dans tous les cas mais ne contrôle rien d’autre.", "correct": false}, + {"index": "B", "libelle": "Le plieur qualifié ne contrôle la voilure que si elle a été ouverte en vol.", "correct": false}, + {"index": "C", "libelle": "Le plieur qualifié fait un contrôle détaillé de l’ensemble de l’équipement.", "correct": true} + ] + }, + { + "num": 61, + "libelle": "Le contrôle périodique d’un parachute doit être fait :", + "answers": [ + {"index": "A", "libelle": "Avec la même périodicité que le pliage du secours.", "correct": true}, + {"index": "B", "libelle": "Le contrôle périodique d’un parachute n’est pas réglementé, seul le pliage du secours l’est.", "correct": false}, + {"index": "C", "libelle": "Uniquement après une ouverture en vol.", "correct": false} + ] + }, + { + "num": 62, + "libelle": "Un contrôle détaillé et un entretien du système de libération de la voilure principale doit être effectué régulièrement entre deux opérations de contrôle périodique.", + "answers": [ + {"index": "A", "libelle": "Non.", "correct": false}, + {"index": "B", "libelle": "Oui.", "correct": true} + ] + }, + { + "num": 63, + "libelle": "Quels sont les contrôles et l’entretien à réaliser sur le système de libération trois anneaux ?", + "answers": [ + {"index": "A", "libelle": "Aucun contrôle particulier, le système étant visible en permanence.", "correct": false}, + {"index": "B", "libelle": "Manipuler les sangles et nettoyer les gaines de câbles et les joncs de la poignée de libération.", "correct": true}, + {"index": "C", "libelle": "Nettoyer les gaines de câbles et les joncs avec de l’essence avion uniquement.", "correct": false} + ] + }, + { + "num": 64, + "libelle": "Sur une sangle principale de harnais, une dégradation de 5 mm peut entraîner une perte de résistance de 50 %.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 65, + "libelle": "Rallonger la longueur de la bouclette de verrouillage (loop) d’un parachute pour permettre une fermeture très aisée génère des risques d’ouverture intempestive.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 66, + "libelle": "Utiliser une suspente d’un diamètre trop important pour la confection d’une bouclette de verrouillage (loop) peut générer une non ouverture du conteneur.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 67, + "libelle": "Les loops de fermeture :", + "answers": [ + {"index": "A", "libelle": "Doivent être très courts pour éviter une ouverture intempestive.", "correct": false}, + {"index": "B", "libelle": "Doivent être tendus normalement pour éviter à la fois les blocages et les ouvertures intempestives.", "correct": true}, + {"index": "C", "libelle": "Doivent être relâché pour faciliter l’ouverture.", "correct": false} + ] + }, + { + "num": 68, + "libelle": "Quelle peut être la conséquence de l’utilisation d’un loop de fermeture trop long ?", + "answers": [ + {"index": "A", "libelle": "Un retard à l’ouverture.", "correct": false}, + {"index": "B", "libelle": "Une ouverture intempestive.", "correct": true} + ] + }, + { + "num": 69, + "libelle": "Quelle peut être la conséquence de l’utilisation d’un loop trop court ?", + "answers": [ + {"index": "A", "libelle": "Une ouverture intempestive.", "correct": false}, + {"index": "B", "libelle": "Un blocage du système d’ouverture (poignée, hand deploy, pull out).", "correct": true} + ] + }, + { + "num": 70, + "libelle": "Un parachute doit être stocké :", + "answers": [ + {"index": "A", "libelle": "Au sec et à l’abri du soleil.", "correct": true}, + {"index": "B", "libelle": "Les conditions de stockage n’ont pas d’importance.", "correct": false} + ] + }, + { + "num": 71, + "libelle": "L’exposition au soleil :", + "answers": [ + {"index": "A", "libelle": "Est un facteur de vieillissement des matières textiles.", "correct": true}, + {"index": "B", "libelle": "N’induit pas de vieillissement anormal.", "correct": false} + ] + }, + { + "num": 72, + "libelle": "Des expositions prolongées et répétées au soleil peuvent réduire la durée de vie d’une voilure de manière importante.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 73, + "libelle": "Quels rayons, générés par le soleil, induisent un vieillissement prématuré des voilures ?", + "answers": [ + {"index": "A", "libelle": "Les rayons ultra-violets.", "correct": true}, + {"index": "B", "libelle": "Les rayons électromagnétiques.", "correct": false}, + {"index": "C", "libelle": "Les rayons gamma.", "correct": false} + ] + }, + { + "num": 74, + "libelle": "Vous remarquez un début de décousure entre deux sangles d’un sac harnais :", + "answers": [ + {"index": "A", "libelle": "Vous ne laissez pas sauter le parachute et vous consultez un moniteur ou un plieur réparateur.", "correct": true}, + {"index": "B", "libelle": "Cela n’est pas gênant si elle fait moins de 5 mm.", "correct": false}, + {"index": "C", "libelle": "Cela n’est pas gênant si elle fait moins de 8 mm.", "correct": false} + ] + }, + { + "num": 75, + "libelle": "Une déchirure dans un sac de déploiement (POD) :", + "answers": [ + {"index": "A", "libelle": "Nécessite un contrôle par une personne qualifiée quelque soit sa longueur.", "correct": true}, + {"index": "B", "libelle": "Ne nécessite pas de réparation si elle fait moins de 5 cm.", "correct": false}, + {"index": "C", "libelle": "Ne nécessite pas de réparation si elle fait moins de 2 cm.", "correct": false}, + {"index": "D", "libelle": "Ne nécessite pas de réparation si elle fait moins de 8 cm.", "correct": false} + ] + }, + { + "num": 76, + "libelle": "Une suspente présentant une amorce de rupture, même légère, peut voir sa résistance diminuée de façon importante.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 77, + "libelle": "Une déchirure sur une voilure principale :", + "answers": [ + {"index": "A", "libelle": "Nécessite un contrôle par une personne qualifiée quelque soit sa longueur.", "correct": true}, + {"index": "B", "libelle": "Ne nécessite pas de réparation si elle fait moins de 8 cm.", "correct": false}, + {"index": "C", "libelle": "Ne nécessite pas de réparation si elle fait moins de 2 cm.", "correct": false}, + {"index": "D", "libelle": "Ne nécessite pas de réparation si elle fait moins de 5 cm.", "correct": false} + ] + } + ] + }, + { + "num": 4, + "name": "Largage", + "questions": [ + { + "num": 78, + "libelle": "Durant la montée en altitude, vers 1200 m, le moteur de l’avion s’arrête.", + "answers": [ + {"index": "A", "libelle": "Vous attendez les consignes du pilote pour ouvrir la porte et procéder à l’évacuation.", "correct": true}, + {"index": "B", "libelle": "Vous ouvrez la porte et vous sautez en enjoignant aux autres de vous suivre.", "correct": false} + ] + }, + { + "num": 79, + "libelle": "Lors de l’équipement pour un saut à 4000 mètres, le vent au sol est de 5 m/s. Au décollage le vent est de 7 m/s. A 2500 mètres le pilote vous annonce que le vent au sol est de 9 m/s avec rafales à 13 m/s.", + "answers": [ + {"index": "A", "libelle": "Il faut annuler le largage et demander au pilote de redescendre.", "correct": true}, + {"index": "B", "libelle": "Vous larguez tout de suite avant que le vent n’augmente encore.", "correct": false}, + {"index": "C", "libelle": "Vous poursuivez la montée et larguez à 4000 m.", "correct": false} + ] + }, + { + "num": 80, + "libelle": "L’avion est bloqué à 800 m par des nuages :", + "answers": [ + {"index": "A", "libelle": "Vous sautez et ouvrez immédiatement.", "correct": false}, + {"index": "B", "libelle": "Vous redescendez avec l’avion.", "correct": true}, + {"index": "C", "libelle": "Seuls les parachutistes titulaires du brevet C ou D peuvent sauter s’ils le désirent.", "correct": false} + ] + }, + { + "num": 81, + "libelle": "A 1500 m de hauteur, le pilote annonce que le largage est annulé et qu’il va redescendre et se poser à pleine charge.", + "answers": [ + {"index": "A", "libelle": "Il faut faire cela uniquement si l’avion vole porte ouverte.", "correct": false}, + {"index": "B", "libelle": "Il faut faire cela uniquement en dessous de 500 m.", "correct": false}, + {"index": "C", "libelle": "Il faut désarmer les déclencheurs de sécurité ou demander au pilote de respecter une vitesse de descente fonction du type de déclencheur.", "correct": true} + ] + }, + { + "num": 82, + "libelle": "A 1800 m de hauteur, le pilote réduit la puissance et se met à descendre.", + "answers": [ + {"index": "A", "libelle": "Ne sachant exactement ce qui se passe, vous sautez immédiatement.", "correct": false}, + {"index": "B", "libelle": "Il faut couper les déclencheurs de sécurité ou demander au pilote de respecter une vitesse de descente fonction du type de déclencheur.", "correct": true}, + {"index": "C", "libelle": "Vous désarmez les déclencheurs uniquement en dessous de 500 m.", "correct": false} + ] + }, + { + "num": 83, + "libelle": "Au moment du largage :", + "answers": [ + {"index": "A", "libelle": "Il ne faut pas sauter sans l’accord du pilote.", "correct": true}, + {"index": "B", "libelle": "C’est sans importance.", "correct": false} + ] + }, + { + "num": 84, + "libelle": "Pour embarquer dans l’avion.", + "answers": [ + {"index": "A", "libelle": "C’est sans importance.", "correct": false}, + {"index": "B", "libelle": "Il ne faut pas passer derrière l’avion.", "correct": false}, + {"index": "C", "libelle": "Il ne faut jamais passer devant l’hélice.", "correct": true} + ] + }, + { + "num": 85, + "libelle": "A 3000 m, vous remarquez que votre altimètre indique 3800 m.", + "answers": [ + {"index": "A", "libelle": "C’est normal si la température est supérieure à la normale.", "correct": false}, + {"index": "B", "libelle": "Vous le recalez à 3000 m.", "correct": false}, + {"index": "C", "libelle": "C’est normal s’il y a des inversions de pression atmosphérique.", "correct": false}, + {"index": "D", "libelle": "Vous ne sautez pas.", "correct": true} + ] + }, + { + "num": 86, + "libelle": "A bord de l’avion, vous remarquez lors de la vérification, que le système trois anneaux d’un parachutiste est mal monté.", + "answers": [ + {"index": "A", "libelle": "Le parachutiste ne doit pas sauter.", "correct": true}, + {"index": "B", "libelle": "La probabilité d’une procédure de secours étant très faible, vous ne dites rien pour ne pas l’inquiéter.", "correct": false}, + {"index": "C", "libelle": "Vous démonter et remonter l’élévateur en demandant au pilote de refaire un tour.", "correct": false} + ] + }, + { + "num": 87, + "libelle": "Lors de l’embarquement, vous constatez que les S.O.A. d’un largage précédant sont toujours accrochées.", + "answers": [ + {"index": "A", "libelle": "Vous pouvez les laisser accrochées.", "correct": false}, + {"index": "B", "libelle": "Vous devez les décrocher et les ranger avant d’embarquer.", "correct": true}, + {"index": "C", "libelle": "Vous les décrochez et les rangez après avoir embarqué.", "correct": false} + ] + }, + { + "num": 88, + "libelle": "Un G.P.S. dans l’avion :", + "answers": [ + {"index": "A", "libelle": "Indique que l’espace aérien est dégagé.", "correct": false}, + {"index": "B", "libelle": "Permet au pilote de prendre l’axe plus facilement.", "correct": true}, + {"index": "C", "libelle": "Calcule le point de largage.", "correct": false} + ] + }, + { + "num": 89, + "libelle": "La vitesse de vol et la trajectoire de l’avion par rapport au sol :", + "answers": [ + {"index": "A", "libelle": "Ne donne pas d’indications sur le vent en altitude.", "correct": false}, + {"index": "B", "libelle": "Donne des indications sur le vent en altitude.", "correct": true} + ] + }, + { + "num": 90, + "libelle": "Ceux qui ouvrent le plus bas :", + "answers": [ + {"index": "A", "libelle": "Partent généralement en premier de l’avion.", "correct": true}, + {"index": "B", "libelle": "Partent généralement en dernier de l’avion.", "correct": false}, + {"index": "C", "libelle": "La hauteur d’ouverture n’a pas d’importance pour l’ordre des départs.", "correct": false} + ] + }, + { + "num": 91, + "libelle": "Ceux qui ouvrent le plus haut :", + "answers": [ + {"index": "A", "libelle": "La hauteur d’ouverture n’a pas d’importance pour l’ordre des départs.", "correct": false}, + {"index": "B", "libelle": "Partent généralement en dernier de l’avion.", "correct": true}, + {"index": "C", "libelle": "Partent généralement en premier de l’avion.", "correct": false} + ] + }, + { + "num": 92, + "libelle": "Sur un même passage, les grands groupes partent généralement :", + "answers": [ + {"index": "A", "libelle": "En premier.", "correct": true}, + {"index": "B", "libelle": "En dernier.", "correct": false}, + {"index": "C", "libelle": "C’est sans importance.", "correct": false} + ] + }, + { + "num": 93, + "libelle": "Au moment du largage, il faut :", + "answers": [ + {"index": "A", "libelle": "Se contenter de vérifier que l’on saute au dessus du terrain et assurer l’espacement entre les départs.", "correct": false}, + {"index": "B", "libelle": "Contrôler l’axe, le point de largage et assurer l’espacement entre les départs.", "correct": true} + ] + }, + { + "num": 94, + "libelle": "Au moment du largage, s‘assurer que l’espace aérien est dégagé en dessous :", + "answers": [ + {"index": "A", "libelle": "Est de la responsabilité du pilote, du directeur de séance et du largueur.", "correct": true}, + {"index": "B", "libelle": "Est de la responsabilité du directeur de séance uniquement.", "correct": false}, + {"index": "C", "libelle": "Est de la responsabilité du pilote uniquement.", "correct": false} + ] + }, + { + "num": 95, + "libelle": "Si au moment du largage, on constate qu’il y a des voiles ouvertes en dessous de l’axe et assez haut.", + "answers": [ + {"index": "A", "libelle": "Chacun assure sa sécurité une fois en chute.", "correct": false}, + {"index": "B", "libelle": "On refait un passage ou/et on décale suffisamment l’axe de largage.", "correct": true} + ] + }, + { + "num": 96, + "libelle": "Quand on largue, si l’avion est en montée :", + "answers": [ + {"index": "A", "libelle": "Le fait que l’avion monte n’influence pas la visualisation du point de largage.", "correct": false}, + {"index": "B", "libelle": "On a tendance à larguer trop court (trop tôt).", "correct": true}, + {"index": "C", "libelle": "On a tendance à larguer trop long (trop loin).", "correct": false} + ] + }, + { + "num": 97, + "libelle": "Quand on largue, si l’avion est en descente :", + "answers": [ + {"index": "A", "libelle": "On a tendance à larguer trop long (trop loin).", "correct": true}, + {"index": "B", "libelle": "On a tendance à larguer trop court (trop tôt).", "correct": false}, + {"index": "C", "libelle": "Le fait que l’avion descende n’influence pas la visualisation du point de largage.", "correct": false} + ] + }, + { + "num": 98, + "libelle": "Quand on large, si l’avion est incliné à droite :", + "answers": [ + {"index": "A", "libelle": "Le fait que l’avion soit incliné n’influence pas la visualisation du point de largage.", "correct": false}, + {"index": "B", "libelle": "On a tendance à larguer trop à gauche.", "correct": true}, + {"index": "C", "libelle": "On a tendance à larguer trop à droite.", "correct": false} + ] + }, + { + "num": 99, + "libelle": "Si vous larguez au cap 270° :", + "answers": [ + {"index": "A", "libelle": "Vous larguez en direction du sud.", "correct": false}, + {"index": "B", "libelle": "Vous larguez en direction de l’est.", "correct": false}, + {"index": "C", "libelle": "Vous larguez en direction du nord.", "correct": false}, + {"index": "D", "libelle": "Vous larguez en direction de l’ouest.", "correct": true} + ] + }, + { + "num": 100, + "libelle": "Si vous larguez au cap 180° :", + "answers": [ + {"index": "A", "libelle": "Vous larguez en direction de l'ouest.", "correct": false}, + {"index": "B", "libelle": "Vous larguez en direction du sud.", "correct": true}, + {"index": "C", "libelle": "Vous larguez en direction de l'est.", "correct": false}, + {"index": "D", "libelle": "Vous larguez en direction du nord.", "correct": false} + ] + }, + { + "num": 101, + "libelle": "Si vous larguez au cap 225° :", + "answers": [ + {"index": "A", "libelle": "Vous larguez en direction du nord-est.", "correct": false}, + {"index": "B", "libelle": "Vous larguez en direction de sud-ouest.", "correct": true}, + {"index": "C", "libelle": "Vous larguez en direction du nord-ouest.", "correct": false}, + {"index": "D", "libelle": "Vous larguez en direction du sud-est.", "correct": false} + ] + }, + { + "num": 102, + "libelle": "En cas d’ouverture intempestive d’un parachute dans l’avion durant la montée :", + "answers": [ + {"index": "A", "libelle": "Il faut placer le parachutiste au fond de l’avion avant le largage.", "correct": false}, + {"index": "B", "libelle": "Il faut placer le parachutiste à un endroit où il ne gênera pas le largage.", "correct": false}, + {"index": "C", "libelle": "Il faut placer le parachutiste à coté du pilote avant le largage.", "correct": false}, + {"index": "D", "libelle": "Il faut suspendre la montée et se reposer.", "correct": true} + ] + }, + { + "num": 103, + "libelle": "En cas d’ouverture intempestive d’un parachute dans l’avion durant la montée :", + "answers": [ + {"index": "A", "libelle": "Il faut placer le parachutiste à un endroit où il ne gênera pas le largage.", "correct": false}, + {"index": "B", "libelle": "Il faut essayer de refermer le parachute avant le largage.", "correct": false}, + {"index": "C", "libelle": "On peut poursuivre la montée et effectuer le largage.", "correct": false}, + {"index": "D", "libelle": "Il faut suspendre la montée et se reposer.", "correct": true} + ] + }, + { + "num": 104, + "libelle": "Avec du vent, ceux qui chutent le plus vite, par exemple le « free-fly » :", + "answers": [ + {"index": "A", "libelle": "Subissent une dérive moins importante que ceux qui chutent à plat.", "correct": true}, + {"index": "B", "libelle": "Subissent une dérive plus importante que ceux qui chutent à plat.", "correct": false} + ] + }, + { + "num": 105, + "libelle": "Ceux qui ouvrent haut :", + "answers": [ + {"index": "A", "libelle": "Subissent une dérive sous voile moins grande que ceux qui ouvrent plus bas.", "correct": false}, + {"index": "B", "libelle": "Subissent une dérive sous voile plus grande que ceux qui ouvrent plus bas.", "correct": true} + ] + }, + { + "num": 106, + "libelle": "De quoi dépend la distance de séparation horizontale entre deux parachutistes qui ne sautent pas ensemble ?", + "answers": [ + {"index": "A", "libelle": "De la vitesse de l’avion uniquement.", "correct": false}, + {"index": "B", "libelle": "Du temps laissé entre deux départs uniquement.", "correct": false}, + {"index": "C", "libelle": "De la vitesse de l’avion et du temps entre deux départs.", "correct": true} + ] + }, + { + "num": 107, + "libelle": "Qu’est-ce que la projection ?", + "answers": [ + {"index": "A", "libelle": "C’est l’impulsion donnée en sortie d’avion.", "correct": false}, + {"index": "B", "libelle": "C’est la distance horizontale parcourue pendant les dix premières secondes de chute.", "correct": true}, + {"index": "C", "libelle": "C’est le temps mis pour atteindre la vitesse maximale de chute.", "correct": false} + ] + }, + { + "num": 108, + "libelle": "Qu’est- ce que la dérive totale due au vent au cours d’un saut ?", + "answers": [ + {"index": "A", "libelle": "C’est la dérive en chute / par la dérive parachute ouvert.", "correct": false}, + {"index": "B", "libelle": "C’est la dérive en chute – la dérive parachute ouvert.", "correct": false}, + {"index": "C", "libelle": "C’est la dérive en chute + la dérive parachute ouvert.", "correct": true} + ] + }, + { + "num": 109, + "libelle": "On appelle dérive totale :", + "answers": [ + {"index": "A", "libelle": "Le temps de chute + le temps de descente parachute ouvert.", "correct": false}, + {"index": "B", "libelle": "Le produit (temps de chute + temps de descente parachute ouvert) x vitesse du vent.", "correct": true}, + {"index": "C", "libelle": "La vitesse du vent.", "correct": false} + ] + }, + { + "num": 110, + "libelle": "En chute libre avec du vent :", + "answers": [ + {"index": "A", "libelle": "On subit une dérive égale à la distance parcourue multiplié par la vitesse du vent.", "correct": false}, + {"index": "B", "libelle": "On subit une dérive égale au temps de chute multiplié par la vitesse du vent.", "correct": true}, + {"index": "C", "libelle": "On ne subit aucune dérive.", "correct": false} + ] + }, + { + "num": 111, + "libelle": "Parachute ouvert :", + "answers": [ + {"index": "A", "libelle": "On subit une dérive égale au temps de descente multiplié par la vitesse du vent.", "correct": true}, + {"index": "B", "libelle": "On ne subit aucune dérive.", "correct": false}, + {"index": "C", "libelle": "On subit une dérive égale à la distance parcourue multiplié par la vitesse du vent.", "correct": false} + ] + }, + { + "num": 112, + "libelle": "Sans vent, sur un avion de type Pilatus, le temps entre deux départ doit être de :", + "answers": [ + {"index": "A", "libelle": "8 à 10 secondes.", "correct": true}, + {"index": "B", "libelle": "5 à 6 secondes.", "correct": false}, + {"index": "C", "libelle": "3 à 4 secondes.", "correct": false}, + {"index": "D", "libelle": "12 à 14 secondes.", "correct": false} + ] + }, + { + "num": 113, + "libelle": "Sans vent, sur un avion de type Pilatus, 5 départs successifs, en respectant les espacements recommandés implique une distance de largage de :", + "answers": [ + {"index": "A", "libelle": "Environ 800 m.", "correct": false}, + {"index": "B", "libelle": "Environ 300 m.", "correct": false}, + {"index": "C", "libelle": "Environ 500 m.", "correct": false}, + {"index": "D", "libelle": "Environ 1150 m.", "correct": true} + ] + }, + { + "num": 114, + "libelle": "Avec un avion gros porteur, comparativement à un avion de type Pilatus ou Cessna :", + "answers": [ + {"index": "A", "libelle": "La vitesse de largage est plus élevée, il faut diminuer l’espacement entre les départs.", "correct": true}, + {"index": "B", "libelle": "La vitesse de largage est plus élevée, il faut augmenter l’espacement entre les départs.", "correct": false}, + {"index": "C", "libelle": "La vitesse de largage est moins élevée, il faut diminuer l’espacement entre les départs.", "correct": false}, + {"index": "D", "libelle": "La vitesse de largage est moins élevée, il faut augmenter l’espacement entre les départs.", "correct": false} + ] + }, + { + "num": 115, + "libelle": "La météorologie vous donne un vent de 35 kts de 1000 à 4000 mètres. La dérive en chute de 4000 à 1000 mètres pour un parachutiste qui chute à plat sera de :", + "answers": [ + {"index": "A", "libelle": "Environ 600 m.", "correct": false}, + {"index": "B", "libelle": "Environ 300 m.", "correct": false}, + {"index": "C", "libelle": "Environ 1100 m.", "correct": true} + ] + }, + { + "num": 116, + "libelle": "L’avion avance lentement par rapport au sol :", + "answers": [ + {"index": "A", "libelle": "Il vole face à un vent fort. Je conserve l’espacement standard entre les départs, le vent en altitude n’ayant que peu d’influence.", "correct": false}, + {"index": "B", "libelle": "Il vole face à un vent fort. Il faut diminuer le temps entre les départs.", "correct": false}, + {"index": "C", "libelle": "Il vole face à un vent fort. Il faut augmenter le temps entre les départs.", "correct": true} + ] + }, + { + "num": 117, + "libelle": "Pour déterminer le point de largage, il faut observer :", + "answers": [ + {"index": "A", "libelle": "Le vent au sol et le vent en altitude.", "correct": true}, + {"index": "B", "libelle": "Surtout le vent au sol.", "correct": false}, + {"index": "C", "libelle": "Uniquement le vent en altitude.", "correct": false} + ] + }, + { + "num": 118, + "libelle": "Par vent fort, il faut larguer :", + "answers": [ + {"index": "A", "libelle": "Au vent du terrain, d’autant plus loin que le vent est fort.", "correct": true}, + {"index": "B", "libelle": "Au vent du terrain, d’autant moins loin que le vent est fort.", "correct": false}, + {"index": "C", "libelle": "Sous le vent du terrain, d’autant moins loin que le vent est fort.", "correct": false}, + {"index": "D", "libelle": "Sous le vent du terrain, d’autant plus loin que le vent est fort.", "correct": false} + ] + }, + { + "num": 119, + "libelle": "Par vent nul, il faut larguer :", + "answers": [ + {"index": "A", "libelle": "A la verticale du terrain.", "correct": true}, + {"index": "B", "libelle": "Loin de la verticale du terrain.", "correct": false} + ] + }, + { + "num": 120, + "libelle": "Si on largue vent arrière avec plusieurs départs au même passage, il faut :", + "answers": [ + {"index": "A", "libelle": "Anticiper le départ des premiers et espacer les départs au moins autant que vent de face.", "correct": true}, + {"index": "B", "libelle": "Espacer un peu moins les départs pour compenser la vitesse sol de l’avion.", "correct": false}, + {"index": "C", "libelle": "Larguer au même endroit que vent de face.", "correct": false} + ] + }, + { + "num": 121, + "libelle": "Par vent fort en larguant face au vent, il faut :", + "answers": [ + {"index": "A", "libelle": "On ne tient jamais compte du vent pour déterminer l’espacement des départs.", "correct": false}, + {"index": "B", "libelle": "Espacer davantage les départs que par vent faible.", "correct": true}, + {"index": "C", "libelle": "Espacer un peu moins les départs que par vent faible.", "correct": false} + ] + }, + { + "num": 122, + "libelle": "Quand le vent est fort entre 4000 m et 1000 m", + "answers": [ + {"index": "A", "libelle": "Il vaut mieux faire partir le groupe de FF avant le groupe de VR.", "correct": false}, + {"index": "B", "libelle": "Il vaut mieux faire partir le groupe de VR avant le groupe de FF.", "correct": true}, + {"index": "C", "libelle": "C’est sans importance.", "correct": false} + ] + }, + { + "num": 123, + "libelle": "Quand le vent est très faible entre 4000 m et 1000 m :", + "answers": [ + {"index": "A", "libelle": "Il vaut mieux faire partir le groupe de VR avant le groupe de FF", "correct": false}, + {"index": "B", "libelle": "Il vaut mieux faire partir le groupe de FF avant le groupe de VR", "correct": true}, + {"index": "C", "libelle": "C’est sans importance.", "correct": false} + ] + }, + { + "num": 124, + "libelle": "Quand on constate sur l’axe de largage que l’avion vole doucement par rapport au sol.", + "answers": [ + {"index": "A", "libelle": "On vole face à un vent fort, il faut partir loin et espacer davantage les départs.", "correct": true}, + {"index": "B", "libelle": "On vole face à un vent fort, il n’y a pas de précautions particulières à prendre.", "correct": false}, + {"index": "C", "libelle": "Cela ne signifie rien de particulier.", "correct": false} + ] + }, + { + "num": 125, + "libelle": "Après avoir vérifié son ouverture :", + "answers": [ + {"index": "A", "libelle": "Il faut s’orienter face au terrain dès que possible.", "correct": false}, + {"index": "B", "libelle": "Il faut s’orienter face au vent dès que possible.", "correct": false}, + {"index": "C", "libelle": "Il faut s’orienter perpendiculairement à l’axe de largage dès que possible.", "correct": true}, + {"index": "D", "libelle": "L’orientation n’a pas d’importance.", "correct": false} + ] + }, + { + "num": 126, + "libelle": "Parachute ouvert, ceux qui ont ouvert le plus haut :", + "answers": [ + {"index": "A", "libelle": "Ils n’ont pas à s’occuper des autres.", "correct": false}, + {"index": "B", "libelle": "Doivent essayer de ne pas descendre trop vite pour ne pas rattraper les autres.", "correct": true}, + {"index": "C", "libelle": "Doivent descendre le plus vite possible pour rattraper les autres.", "correct": false} + ] + }, + { + "num": 127, + "libelle": "Parachute ouvert :", + "answers": [ + {"index": "A", "libelle": "C’est possible si l’on passe juste derrière l’autre voilure.", "correct": false}, + {"index": "B", "libelle": "Il faut éviter de suivre des trajectoires convergentes avec une autre voilure.", "correct": true} + ] + }, + { + "num": 128, + "libelle": "Si deux parachutistes volent en direction l’un de l’autre, face à face :", + "answers": [ + {"index": "A", "libelle": "L’un des deux doit dégager sur sa gauche et l’autre sur sa droite.", "correct": false}, + {"index": "B", "libelle": "Les deux doivent dégager sur leur gauche.", "correct": false}, + {"index": "C", "libelle": "Les deux doivent dégager sur leur droite.", "correct": true} + ] + }, + { + "num": 129, + "libelle": "Si deux parachutistes volent en direction l’un de l’autre, face à face :", + "answers": [ + {"index": "A", "libelle": "Elle est égale à la somme des vitesses des deux voilures.", "correct": true}, + {"index": "B", "libelle": "Elle est égale à celle de la plus lente des deux voilures.", "correct": false}, + {"index": "C", "libelle": "Leur vitesse de rapprochement est égale à celle de la plus rapide des deux voilures.", "correct": false} + ] + }, + { + "num": 130, + "libelle": "Combien de temps mettront pour se rejoindre deux voilures dont les vitesses horizontales respective sont de 10 mètres par seconde, si elles sont ouvertes face à face à 100 mètres de distance ?", + "answers": [ + {"index": "A", "libelle": "20 secondes.", "correct": false}, + {"index": "B", "libelle": "15 secondes.", "correct": false}, + {"index": "C", "libelle": "10 secondes.", "correct": false}, + {"index": "D", "libelle": "5 secondes.", "correct": true} + ] + }, + { + "num": 131, + "libelle": "Deux parachutistes partent à 4000 mètres à 8 secondes d’intervalle d’un avion volant à la vitesse de 70 nœuds (vitesse sol). Ils chutent sans déplacement horizontal dans la masse d’air. Le vent est nul. Quelle est environ leur distance horizontale de séparation à l’ouverture ?", + "answers": [ + {"index": "A", "libelle": "330 m.", "correct": false}, + {"index": "B", "libelle": "280 m.", "correct": true}, + {"index": "C", "libelle": "200 m.", "correct": false}, + {"index": "D", "libelle": "160 m.", "correct": false} + ] + }, + { + "num": 132, + "libelle": "Avec une vitesse de largage de 70 kts et un vent de face de 40 kts de 1000 à 4000 mètres, quel est l’espacement souhaitable entre les départs lors d’un largage à 4000 mètres afin d’obtenir un espacement horizontal de 300 mètres entre chaque départ ?", + "answers": [ + {"index": "A", "libelle": "20 secondes.", "correct": true}, + {"index": "B", "libelle": "15 secondes.", "correct": false}, + {"index": "C", "libelle": "12 secondes.", "correct": false}, + {"index": "D", "libelle": "10 secondes.", "correct": false} + ] + }, + { + "num": 133, + "libelle": "Si un parachutiste évolue devant vous et un peu au-dessus :", + "answers": [ + {"index": "A", "libelle": "Il a la priorité parce qu’il ne vous voit pas.", "correct": true}, + {"index": "B", "libelle": "Vous avez la priorité parce que vous êtes le plus bas.", "correct": false} + ] + }, + { + "num": 134, + "libelle": "Si un parachutiste se trouve au-dessus d’un obstacle en bordure de la zone de poser, un peu au-dessus de vous :", + "answers": [ + {"index": "A", "libelle": "Vous avez la priorité car vous êtes en dessous.", "correct": false}, + {"index": "B", "libelle": "Il a la priorité et vous devez lui laisser la place pour rentrer la zone de poser.", "correct": true} + ] + }, + { + "num": 135, + "libelle": "Un élève débutant et un parachutiste confirmé se présentent en même temps dans le circuit d’atterrissage :", + "answers": [ + {"index": "A", "libelle": "C’est le plus expérimenté qui a la priorité.", "correct": false}, + {"index": "B", "libelle": "C’est le moins expérimenté qui a la priorité.", "correct": true} + ] + }, + { + "num": 136, + "libelle": "Entre un tandem et un élève débutant :", + "answers": [ + {"index": "A", "libelle": "C’est le tandem qui est prioritaire car il est moins manœuvrant.", "correct": false}, + {"index": "B", "libelle": "C’est l’élève qui est prioritaire car il est moins expérimenté.", "correct": true} + ] + } + ] + }, + { + "num": 5, + "name": "Règlementation", + "questions": [ + { + "num": 137, + "libelle": "Le pilote traverse une fine couche nuageuse à 2000 mètres pour monter larguer à 4000 mètres. Personne ne voit le sol au moment du largage. Celui-ci s’effectue à l’aide au GPS.", + "answers": [ + {"index": "A", "libelle": "C’est une infraction.", "correct": true}, + {"index": "B", "libelle": "Cela ne constitue pas une infraction si le pilote est qualifié IFR.", "correct": false}, + {"index": "C", "libelle": "Si le pilote est qualifié IFR et titulaire d’une licence professionnelle ce n’est pas une infraction.", "correct": false}, + {"index": "D", "libelle": "Cela ne constitue pas une infraction car l’avion est équipé d’un GPS.", "correct": false} + ] + }, + { + "num": 138, + "libelle": "Une couche de nuageuse soudée est à 3000 mètres. Vous demandez au pilote de la traverser et de larguer à l’aide du GPS.", + "answers": [ + {"index": "A", "libelle": "Si le pilote est qualifié IFR et titulaire d’une licence professionnelle ce n’est pas une infraction.", "correct": false}, + {"index": "B", "libelle": "Cela ne constitue pas une infraction car l’avion est équipé d’un GPS", "correct": false}, + {"index": "C", "libelle": "Cela ne constitue pas une infraction si le pilote est qualifié IFR.", "correct": false}, + {"index": "D", "libelle": "C’est une infraction.", "correct": true} + ] + }, + { + "num": 139, + "libelle": "En VFR, la traversée d’une couche nuageuse, même mince, est interdite :", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 140, + "libelle": "Un pilote titulaire d’une licence professionnelle ou privée en conditions de vol VMC peut se voir retirer sa licence temporairement ou à vie s’il traverse une couche nuageuse ou s’il pénètre dans un nuage.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 141, + "libelle": "Dans l’avion, la présence d’un « coupe sangle » est obligatoire.", + "answers": [ + {"index": "A", "libelle": "Uniquement si l’avion est équipé pour le largage des élèves en ouverture automatique.", "correct": false}, + {"index": "B", "libelle": "Uniquement lors du largage d’élèves en ouverture automatique.", "correct": false}, + {"index": "C", "libelle": "Dans tous les cas quelque soit le type de largage effectué.", "correct": true} + ] + }, + { + "num": 142, + "libelle": "Quel est le brevet minimum nécessaire afin d’effectuer des sauts de nuit ?", + "answers": [ + {"index": "A", "libelle": "Le brevet B.", "correct": false}, + {"index": "B", "libelle": "Le BPA.", "correct": true}, + {"index": "C", "libelle": "Le brevet C ou D.", "correct": false} + ] + }, + { + "num": 143, + "libelle": "Quel est le brevet qui donne l’autorisation d’effectuer des sauts à haute altitude ?", + "answers": [ + {"index": "A", "libelle": "Le BPA.", "correct": true}, + {"index": "B", "libelle": "Le brevet A.", "correct": false}, + {"index": "C", "libelle": "Le brevet B.", "correct": false} + ] + }, + { + "num": 144, + "libelle": "Quel est le brevet qui donne l’autorisation d’effectuer des sauts de ballon ?", + "answers": [ + {"index": "A", "libelle": "Le brevet A.", "correct": false}, + {"index": "B", "libelle": "Le brevet B.", "correct": false}, + {"index": "C", "libelle": "Le BPA.", "correct": false}, + {"index": "D", "libelle": "Le brevet C ou D.", "correct": true} + ] + }, + { + "num": 145, + "libelle": "Quel est le brevet qui donne la possibilité de participer à des compétitions ?", + "answers": [ + {"index": "A", "libelle": "Le brevet A.", "correct": false}, + {"index": "B", "libelle": "Le brevet B dans la spécialité correspondante.", "correct": true}, + {"index": "C", "libelle": "Le brevet C.", "correct": false} + ] + }, + { + "num": 146, + "libelle": "La durée de la validité du contrôle périodique d’un parachute est de :", + "answers": [ + {"index": "A", "libelle": "24 mois.", "correct": false}, + {"index": "B", "libelle": "12 mois.", "correct": true}, + {"index": "C", "libelle": "6 mois.", "correct": false}, + {"index": "D", "libelle": "3 mois.", "correct": false} + ] + }, + { + "num": 147, + "libelle": "La vitesse de vent maximale autorisée au sol pour des parachutistes titulaires uniquement du brevet A est de :", + "answers": [ + {"index": "A", "libelle": "12 m/s.", "correct": false}, + {"index": "B", "libelle": "11 m/s.", "correct": true}, + {"index": "C", "libelle": "9 m/s.", "correct": false}, + {"index": "D", "libelle": "7 m/s.", "correct": false} + ] + }, + { + "num": 148, + "libelle": "La vitesse de vent maximale autorisée au sol pour des parachutistes titulaires uniquement du brevet B est de :", + "answers": [ + {"index": "A", "libelle": "12 m/s.", "correct": false}, + {"index": "B", "libelle": "11 m/s.", "correct": true}, + {"index": "C", "libelle": "9 m/s.", "correct": false}, + {"index": "D", "libelle": "7 m/s.", "correct": false} + ] + }, + { + "num": 149, + "libelle": "La vitesse de vent maximale autorisée au sol pour des sauts en tandem est de :", + "answers": [ + {"index": "A", "libelle": "13 m/s.", "correct": false}, + {"index": "B", "libelle": "15 m/s.", "correct": false}, + {"index": "C", "libelle": "12 m/s.", "correct": false}, + {"index": "D", "libelle": "11 m/s.", "correct": true} + ] + }, + { + "num": 150, + "libelle": "La vitesse de vent maximale autorisée au sol pour des élèves non titulaires du brevet A est de :", + "answers": [ + {"index": "A", "libelle": "5 m/s.", "correct": false}, + {"index": "B", "libelle": "7 m/s.", "correct": true}, + {"index": "C", "libelle": "8 m/s.", "correct": false}, + {"index": "D", "libelle": "6 m/s.", "correct": false} + ] + }, + { + "num": 151, + "libelle": "Un parachutiste titulaire uniquement du BPA et totalisant 300 sauts peut-il sauter avec une voile de la surface de son choix ?", + "answers": [ + {"index": "A", "libelle": "Non.", "correct": true}, + {"index": "B", "libelle": "Oui.", "correct": false} + ] + }, + { + "num": 152, + "libelle": "Un parachutiste titulaire uniquement du BPA et totalisant 700 sauts peut-il sauter avec une voile de la surface de son choix ?", + "answers": [ + {"index": "A", "libelle": "Non.", "correct": true}, + {"index": "B", "libelle": "Oui.", "correct": false} + ] + }, + { + "num": 153, + "libelle": "Peut-on poursuivre une séance de sauts si le vent au sol est constant à 10 m/s avec des rafales à 13 m/s ?", + "answers": [ + {"index": "A", "libelle": "Uniquement pour les sauts en tandem.", "correct": false}, + {"index": "B", "libelle": "Non.", "correct": true}, + {"index": "C", "libelle": "Oui.", "correct": false}, + {"index": "D", "libelle": "Uniquement pour les parachutistes titulaires du BPA.", "correct": false} + ] + }, + { + "num": 154, + "libelle": "Quel est l’encadrement minimum nécessaire au sol lors d’une séance de pratique autonome ?", + "answers": [ + {"index": "A", "libelle": "Un parachutiste titulaire du Brevet C.", "correct": true}, + {"index": "B", "libelle": "Un moniteur titulaire au minimum du monitorat fédéral.", "correct": false}, + {"index": "C", "libelle": "Un parachutiste titulaire du Brevet BPA.", "correct": false}, + {"index": "D", "libelle": "Un parachutiste titulaire du Brevet D.", "correct": false} + ] + }, + { + "num": 155, + "libelle": "Une assurance responsabilité civile est-elle obligatoire pour les parachutistes qui pratiquent dans les structures de la FFP ?", + "answers": [ + {"index": "A", "libelle": "Uniquement pour les moniteurs.", "correct": false}, + {"index": "B", "libelle": "Oui.", "correct": true}, + {"index": "C", "libelle": "Uniquement pour les compétiteurs.", "correct": false}, + {"index": "D", "libelle": "Non.", "correct": false} + ] + }, + { + "num": 156, + "libelle": "La hauteur minimale d’ouverture imposé par la réglementation fédérale pour les parachutistes titulaire du BPA est de :", + "answers": [ + {"index": "A", "libelle": "850 m.", "correct": true}, + {"index": "B", "libelle": "1200 m.", "correct": false}, + {"index": "C", "libelle": "650 m.", "correct": false}, + {"index": "D", "libelle": "1000 m.", "correct": false} + ] + }, + { + "num": 157, + "libelle": "Quel est le document attestant l’affiliation à la FFP ?", + "answers": [ + {"index": "A", "libelle": "L’assurance responsabilité civile.", "correct": false}, + {"index": "B", "libelle": "Le livret de progression et un des brevets fédéraux.", "correct": false}, + {"index": "C", "libelle": "La licence assurance de l’année en cours", "correct": true} + ] + }, + { + "num": 158, + "libelle": "Les documents de saut qu’un parachutiste doit présenter pour sauter dans les structures fédérales sont :", + "answers": [ + {"index": "A", "libelle": "Le livret de parachute uniquement.", "correct": false}, + {"index": "B", "libelle": "La licence assurance uniquement.", "correct": false}, + {"index": "C", "libelle": "Le carnet de sauts uniquement.", "correct": false}, + {"index": "D", "libelle": "L’ensemble de ces documents.", "correct": true} + ] + }, + { + "num": 159, + "libelle": "L’assurance en responsabilité civile :", + "answers": [ + {"index": "A", "libelle": "Garantie la réparation des dommages causés aux tiers.", "correct": true}, + {"index": "B", "libelle": "Garantie le remboursement des frais médicaux et chirurgicaux de l’assuré.", "correct": false} + ] + }, + { + "num": 160, + "libelle": "L’assurance individuelle :", + "answers": [ + {"index": "A", "libelle": "Garantie la réparation des dommages causés aux tiers.", "correct": false}, + {"index": "B", "libelle": "Garantie le remboursement des frais médicaux et chirurgicaux de l’assuré.", "correct": true} + ] + }, + { + "num": 161, + "libelle": "Le titulaire du BPA peut effectuer tous les sauts spéciaux.", + "answers": [ + {"index": "A", "libelle": "Uniquement les sauts de nuit et les sauts à haute altitude avec l’accord du directeur technique.", "correct": false}, + {"index": "B", "libelle": "Faux.", "correct": true}, + {"index": "C", "libelle": "Vrai.", "correct": false} + ] + }, + { + "num": 162, + "libelle": "Le titulaire du brevet B peut-il effectuer des sauts spéciaux ?", + "answers": [ + {"index": "A", "libelle": "Oui.", "correct": false}, + {"index": "B", "libelle": "Non.", "correct": true}, + {"index": "C", "libelle": "Uniquement les sauts de nuit et les sauts à haute altitude avec l’accord du directeur technique.", "correct": false} + ] + }, + { + "num": 163, + "libelle": "Le titulaire du BPA peut-il effectuer des sauts de démonstration hors école de parachutisme ?", + "answers": [ + {"index": "A", "libelle": "Oui.", "correct": false}, + {"index": "B", "libelle": "Non.", "correct": true}, + {"index": "C", "libelle": "Oui si les sauts ne se déroulent pas lors d’une manifestation aérienne.", "correct": false} + ] + } + ] + }, + { + "num": 6, + "name": "Pilotage et mécanique de vol", + "questions": [ + { + "num": 164, + "libelle": "Plus je fais un mouvement brusque et ample pour tourner :", + "answers": [ + {"index": "A", "libelle": "L’inclinaison de la voile est indépendante de la manœuvre de mise en virage.", "correct": false}, + {"index": "B", "libelle": "Moins l’inclinaison de voile augmente.", "correct": false}, + {"index": "C", "libelle": "Plus l’inclinaison de la voile augmente.", "correct": true} + ] + }, + { + "num": 165, + "libelle": "Plus la vitesse initiale est élevée avant le virage :", + "answers": [ + {"index": "A", "libelle": "Moins le rayon de virage augmente.", "correct": false}, + {"index": "B", "libelle": "Plus le rayon de virage augmente.", "correct": true}, + {"index": "C", "libelle": "Le rayon de virage est indépendant de la vitesse initiale.", "correct": false} + ] + }, + { + "num": 166, + "libelle": "Plus la voile s’incline en virage :", + "answers": [ + {"index": "A", "libelle": "Plus la vitesse verticale diminue.", "correct": false}, + {"index": "B", "libelle": "Plus la vitesse verticale augmente.", "correct": true}, + {"index": "C", "libelle": "La vitesse verticale est indépendante de l’inclinaison de la voile.", "correct": false} + ] + }, + { + "num": 167, + "libelle": "Pour faire un virage ‘’à plat’’ :", + "answers": [ + {"index": "A", "libelle": "Il faut manœuvrer très rapidement à pleine vitesse.", "correct": false}, + {"index": "B", "libelle": "Il faut manœuvrer doucement et en ½ frein.", "correct": true} + ] + }, + { + "num": 168, + "libelle": "Qu’appelle-t-on vitesse sur trajectoire d’une aile ?", + "answers": [ + {"index": "A", "libelle": "La vitesse qui résulte de la somme vectoriel de la vitesse horizontale et de la vitesse verticale.", "correct": true}, + {"index": "B", "libelle": "La vitesse verticale.", "correct": false}, + {"index": "C", "libelle": "La vitesse horizontale.", "correct": false} + ] + }, + { + "num": 169, + "libelle": "La vitesse propre d’une aile, dans la masse d’air :", + "answers": [ + {"index": "A", "libelle": "Est plus grande vent arrière que vent de face.", "correct": false}, + {"index": "B", "libelle": "Est plus grande vent de face que vent arrière.", "correct": false}, + {"index": "C", "libelle": "Est indépendante du vent.", "correct": true} + ] + }, + { + "num": 170, + "libelle": "La vitesse sol d’une aile :", + "answers": [ + {"index": "A", "libelle": "Est plus grande vent arrière que vent de face.", "correct": true}, + {"index": "B", "libelle": "Est plus grande vent de face que vent arrière.", "correct": false}, + {"index": "C", "libelle": "Est indépendante du vent.", "correct": false} + ] + }, + { + "num": 171, + "libelle": "En faisant un virage rapide :", + "answers": [ + {"index": "A", "libelle": "La vitesse verticale diminue.", "correct": false}, + {"index": "B", "libelle": "La vitesse verticale augmente beaucoup.", "correct": true}, + {"index": "C", "libelle": "La vitesse verticale augmente peu.", "correct": false} + ] + }, + { + "num": 172, + "libelle": "Pour augmenter la pénétration dans l’air par vent fort :", + "answers": [ + {"index": "A", "libelle": "Il faut faire une légère traction sur les élévateurs avants.", "correct": true}, + {"index": "B", "libelle": "Il faut faire une légère traction sur les élévateurs arrières.", "correct": false}, + {"index": "C", "libelle": "On ne peut pas améliorer la pénétration par vent fort.", "correct": false} + ] + }, + { + "num": 173, + "libelle": "Avec un vent de face égal à la vitesse horizontale de la voile, si on fait une traction sur les élévateurs avants :", + "answers": [ + {"index": "A", "libelle": "La finesse sol augmente.", "correct": true}, + {"index": "B", "libelle": "La finesse sol diminue.", "correct": false}, + {"index": "C", "libelle": "La finesse sol reste la même.", "correct": false} + ] + }, + { + "num": 174, + "libelle": "Par vent nul, si l’on tire sur les élévateurs avant :", + "answers": [ + {"index": "A", "libelle": "La vitesse diminue et la finesse augmente.", "correct": false}, + {"index": "B", "libelle": "La vitesse augmente et la finesse diminue.", "correct": true}, + {"index": "C", "libelle": "La vitesse et la finesse diminuent.", "correct": false}, + {"index": "D", "libelle": "La vitesse et la finesse augmentent.", "correct": false} + ] + }, + { + "num": 175, + "libelle": "Tirer sur les élévateurs avant peut être utile :", + "answers": [ + {"index": "A", "libelle": "Pour revenir sur le terrain par vent nul ou vent arrière, si l’on est loin.", "correct": false}, + {"index": "B", "libelle": "Pour contrer un fort vent de face.", "correct": true}, + {"index": "C", "libelle": "En aucune circonstance.", "correct": false} + ] + }, + { + "num": 176, + "libelle": "Une traction sur un élévateur avant provoque.", + "answers": [ + {"index": "A", "libelle": "Un virage lent à petit rayon et enfoncement important.", "correct": false}, + {"index": "B", "libelle": "Un virage lent à grand rayon et faible enfoncement.", "correct": false}, + {"index": "C", "libelle": "Un virage rapide à petit rayon et enfoncement important.", "correct": true}, + {"index": "D", "libelle": "Un virage rapide à grand rayon et faible enfoncement.", "correct": false} + ] + }, + { + "num": 177, + "libelle": "Par vent nul, si l’on tire modérément sur les élévateurs arrière :", + "answers": [ + {"index": "A", "libelle": "La vitesse augmente et la finesse diminue.", "correct": false}, + {"index": "B", "libelle": "La vitesse et la finesse diminuent.", "correct": false}, + {"index": "C", "libelle": "La vitesse diminue et la finesse augmente.", "correct": true}, + {"index": "D", "libelle": "La vitesse et la finesse augmentent.", "correct": false} + ] + }, + { + "num": 178, + "libelle": "Tirer sur les élévateurs arrière peut être utile :", + "answers": [ + {"index": "A", "libelle": "Pour revenir sur le terrain par vent nul ou vent arrière, si l’on est loin.", "correct": true}, + {"index": "B", "libelle": "Pour contrer un fort vent de face.", "correct": false}, + {"index": "C", "libelle": "En aucune circonstance.", "correct": false} + ] + }, + { + "num": 179, + "libelle": "Une traction modérée sur un élévateur arrière provoque :", + "answers": [ + {"index": "A", "libelle": "Un virage rapide à grand rayon et faible enfoncement.", "correct": false}, + {"index": "B", "libelle": "Un virage lent à grand rayon et faible enfoncement.", "correct": true}, + {"index": "C", "libelle": "Un virage rapide à petit rayon et enfoncement important.", "correct": false}, + {"index": "D", "libelle": "Un virage lent à petit rayon et enfoncement important.", "correct": false} + ] + }, + { + "num": 180, + "libelle": "Pour piloter avec les élévateurs :", + "answers": [ + {"index": "A", "libelle": "L’effort à fournir est le même que pour piloter avec les commandes.", "correct": false}, + {"index": "B", "libelle": "L’effort à fournir est plus faible que pour piloter avec les commandes.", "correct": false}, + {"index": "C", "libelle": "L’effort à fournir est plus important que pour piloter avec les commandes.", "correct": true} + ] + }, + { + "num": 181, + "libelle": "Quand on pilote avec les élévateurs :", + "answers": [ + {"index": "A", "libelle": "Il est plus bas.", "correct": false}, + {"index": "B", "libelle": "Il est plus haut.", "correct": true}, + {"index": "C", "libelle": "Le point de décrochage est au même niveau que quand on pilote avec les commandes.", "correct": false} + ] + }, + { + "num": 182, + "libelle": "Qu’appelle-t-on finesse ?", + "answers": [ + {"index": "A", "libelle": "Le rapport entre la surface et la masse du parachutiste équipé.", "correct": false}, + {"index": "B", "libelle": "L’épaisseur du profil d’une aile.", "correct": false}, + {"index": "C", "libelle": "Le rapport entre la vitesse horizontale et la vitesse verticale de la voilure.", "correct": true} + ] + }, + { + "num": 183, + "libelle": "On appelle finesse air :", + "answers": [ + {"index": "A", "libelle": "Le rapport vitesse sur trajectoire / vitesse verticale.", "correct": false}, + {"index": "B", "libelle": "Le rapport vitesse verticale / vitesse horizontale.", "correct": false}, + {"index": "C", "libelle": "Le rapport vitesse horizontale / vitesse verticale.", "correct": true} + ] + }, + { + "num": 184, + "libelle": "Dans la masse d’air, la finesse air est égale :", + "answers": [ + {"index": "A", "libelle": "Au rapport perte de hauteur / distance parcourue.", "correct": false}, + {"index": "B", "libelle": "Au rapport distance parcourue / perte de hauteur.", "correct": true} + ] + }, + { + "num": 185, + "libelle": "La finesse sol est égale à :", + "answers": [ + {"index": "A", "libelle": "Vitesse sur trajectoire par rapport au sol / vitesse verticale par rapport au sol.", "correct": false}, + {"index": "B", "libelle": "Vitesse sur trajectoire dans la masse d’air / vitesse verticale dans la masse d’air.", "correct": false}, + {"index": "C", "libelle": "Vitesse horizontale par rapport au sol / vitesse verticale par rapport au sol.", "correct": true}, + {"index": "D", "libelle": "Vitesse horizontale dans la masse d’air / vitesse verticale dans la masse d’air.", "correct": false} + ] + }, + { + "num": 186, + "libelle": "La finesse sol :", + "answers": [ + {"index": "A", "libelle": "Augmente avec un vent de face.", "correct": false}, + {"index": "B", "libelle": "Diminue avec un vent de face.", "correct": true}, + {"index": "C", "libelle": "Reste constante quelque soit le vent.", "correct": false} + ] + }, + { + "num": 187, + "libelle": "Par vent nul, avec une perte de hauteur de 1000 mètres et une finesse de 2,5 quelle est la distance parcourue?", + "answers": [ + {"index": "A", "libelle": "500 m", "correct": false}, + {"index": "B", "libelle": "2500 m", "correct": true}, + {"index": "C", "libelle": "1500 m", "correct": false} + ] + }, + { + "num": 188, + "libelle": "Comment se nomme la force aérodynamique qui est parallèle à la trajectoire ?", + "answers": [ + {"index": "A", "libelle": "La traînée.", "correct": true}, + {"index": "B", "libelle": "La résultante aérodynamique.", "correct": false}, + {"index": "C", "libelle": "La portance.", "correct": false} + ] + }, + { + "num": 189, + "libelle": "Comment se nomme la force aérodynamique qui est perpendiculaire à la trajectoire ?", + "answers": [ + {"index": "A", "libelle": "La portance.", "correct": true}, + {"index": "B", "libelle": "La traînée.", "correct": false}, + {"index": "C", "libelle": "La résultante aérodynamique.", "correct": false} + ] + }, + { + "num": 190, + "libelle": "En vol stable, quelle est la force qui équilibre le poids ?", + "answers": [ + {"index": "A", "libelle": "La portance.", "correct": false}, + {"index": "B", "libelle": "La traînée.", "correct": false}, + {"index": "C", "libelle": "La résultante aérodynamique.", "correct": true} + ] + }, + { + "num": 191, + "libelle": "Qu‘appelle-t-on angle d’incidence ?", + "answers": [ + {"index": "A", "libelle": "L’angle entre l’aile et l’axe du cône de suspension.", "correct": false}, + {"index": "B", "libelle": "L’angle entre la trajectoire et l’horizontale.", "correct": false}, + {"index": "C", "libelle": "L’angle entre la trajectoire et la corde de profil de l’aile.", "correct": true} + ] + }, + { + "num": 192, + "libelle": "La charge alaire :", + "answers": [ + {"index": "A", "libelle": "Est la masse du parachutiste équipé.", "correct": false}, + {"index": "B", "libelle": "Est la masse du parachute.", "correct": false}, + {"index": "C", "libelle": "Est la masse de la voilure.", "correct": false}, + {"index": "D", "libelle": "Est le rapport entre la masse du parachutiste équipé et la surface de voile.", "correct": true} + ] + }, + { + "num": 193, + "libelle": "On appelle charge alaire :", + "answers": [ + {"index": "A", "libelle": "Le rapport surface de voile / masse du parachutiste équipé.", "correct": false}, + {"index": "B", "libelle": "Le rapport masse du parachutiste équipé / surface de voile.", "correct": true}, + {"index": "C", "libelle": "La résistance du tissu de voile.", "correct": false} + ] + }, + { + "num": 194, + "libelle": "La charge alaire :", + "answers": [ + {"index": "A", "libelle": "Est un paramètre important.", "correct": true}, + {"index": "B", "libelle": "Est un paramètre négligeable.", "correct": false} + ] + }, + { + "num": 195, + "libelle": "Une finesse de 2.5 signifie :", + "answers": [ + {"index": "A", "libelle": "Que pour une perte de hauteur de 1000 m. La distance horizontale parcourue sera de 2500 m.", "correct": true}, + {"index": "B", "libelle": "Que pour une perte de hauteur de 2500 m. La distance horizontale parcourue sera de 1000 m.", "correct": false} + ] + }, + { + "num": 196, + "libelle": "Lors d’un virage, la vitesse verticale :", + "answers": [ + {"index": "A", "libelle": "Diminue.", "correct": false}, + {"index": "B", "libelle": "Augmente.", "correct": true}, + {"index": "C", "libelle": "Ne change pas.", "correct": false} + ] + }, + { + "num": 197, + "libelle": "Lors d’un décrochage, la vitesse verticale d’une voilure de type aile :", + "answers": [ + {"index": "A", "libelle": "Ne change pas.", "correct": false}, + {"index": "B", "libelle": "Augmente un petit peu.", "correct": false}, + {"index": "C", "libelle": "Augmente beaucoup.", "correct": true} + ] + }, + { + "num": 198, + "libelle": "Le décrochage :", + "answers": [ + {"index": "A", "libelle": "Survient uniquement suite à une action sur les commandes de manœuvre.", "correct": false}, + {"index": "B", "libelle": "Peut survenir quand on passe dans une zone de fortes turbulences.", "correct": true} + ] + }, + { + "num": 199, + "libelle": "Une voilure de type aile peut décrocher même si l’on n’a pas atteint les 100% de frein.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 200, + "libelle": "Dans un écoulement laminaire, le point de décrochage :", + "answers": [ + {"index": "A", "libelle": "Varie en fonction de l’orientation et de la vitesse du vent.", "correct": false}, + {"index": "B", "libelle": "Est indépendant du vent.", "correct": true} + ] + }, + { + "num": 201, + "libelle": "Un décrochage dynamique :", + "answers": [ + {"index": "A", "libelle": "Peut survenir lors d’un freinage brusque.", "correct": true}, + {"index": "B", "libelle": "N’est possible qu’en condition de vent laminaire.", "correct": false}, + {"index": "C", "libelle": "N’est possible qu’en conditions turbulentes.", "correct": false} + ] + }, + { + "num": 202, + "libelle": "Si on augmente la masse sous un parachute, les vitesses verticales et horizontales :", + "answers": [ + {"index": "A", "libelle": "Diminuent.", "correct": false}, + {"index": "B", "libelle": "Augmentent.", "correct": true}, + {"index": "C", "libelle": "Ne changent pas.", "correct": false} + ] + }, + { + "num": 203, + "libelle": "Avec une voilure donnée, la vitesse sur trajectoire :", + "answers": [ + {"index": "A", "libelle": "C’est uniquement la vitesse verticale qui augmente.", "correct": false}, + {"index": "B", "libelle": "Ne varie pas quand la masse du parachutiste augmente.", "correct": false}, + {"index": "C", "libelle": "Augmente quand la masse du parachutiste augmente.", "correct": true} + ] + }, + { + "num": 204, + "libelle": "L’avant d’une voilure de type aile s’appelle :", + "answers": [ + {"index": "A", "libelle": "Le bord d’attaque.", "correct": true}, + {"index": "B", "libelle": "Le bord de fuite.", "correct": false}, + {"index": "C", "libelle": "Le saumon.", "correct": false} + ] + }, + { + "num": 205, + "libelle": "L’arrière d’une voilure de type aile s’appelle :", + "answers": [ + {"index": "A", "libelle": "L’intrados.", "correct": false}, + {"index": "B", "libelle": "Le bord d’attaque.", "correct": false}, + {"index": "C", "libelle": "Le bord de fuite.", "correct": true} + ] + }, + { + "num": 206, + "libelle": "Lors d’un décrochage, la vitesse horizontale :", + "answers": [ + {"index": "A", "libelle": "Augmente.", "correct": false}, + {"index": "B", "libelle": "Ne change pas.", "correct": false}, + {"index": "C", "libelle": "Diminue.", "correct": true} + ] + }, + { + "num": 207, + "libelle": "Si votre voilure décroche lors d’un freinage excessif :", + "answers": [ + {"index": "A", "libelle": "Il faut relâcher doucement les commandes de manœuvre.", "correct": true}, + {"index": "B", "libelle": "Il faut attendre que la voilure se remette en pression toute seule.", "correct": false}, + {"index": "C", "libelle": "Il faut agir sur les commandes par tractions répétées.", "correct": false} + ] + }, + { + "num": 208, + "libelle": "Le point de décrochage :", + "answers": [ + {"index": "A", "libelle": "Dépend des caractéristiques de l’aile et du réglage des commandes de manœuvre.", "correct": true}, + {"index": "B", "libelle": "Ne dépend que des caractéristiques de l’aile.", "correct": false} + ] + }, + { + "num": 209, + "libelle": "Le point de décrochage :", + "answers": [ + {"index": "A", "libelle": "Est toujours au même niveau.", "correct": false}, + {"index": "B", "libelle": "Peut varier en fonction des conditions aérologiques et des manœuvres effectuées.", "correct": true} + ] + }, + { + "num": 210, + "libelle": "Le décrochage survient :", + "answers": [ + {"index": "A", "libelle": "Eventuellement avant le point de décrochage dans une zone de turbulences.", "correct": true}, + {"index": "B", "libelle": "Uniquement quand on freine au-delà du point de décrochage.", "correct": false} + ] + }, + { + "num": 211, + "libelle": "En cas de décrochage :", + "answers": [ + {"index": "A", "libelle": "Il faut maintenir la voilure en freins.", "correct": false}, + {"index": "B", "libelle": "Il faut relâcher progressivement les commandes de manœuvre.", "correct": true}, + {"index": "C", "libelle": "Il faut relâcher le plus vite possible les commandes de manœuvre.", "correct": false} + ] + }, + { + "num": 212, + "libelle": "Lors d’un freinage, si on relâche les commandes brusquement :", + "answers": [ + {"index": "A", "libelle": "La voile reprend progressivement sa trajectoire initiale de vol.", "correct": false}, + {"index": "B", "libelle": "La voile subit un balancement et une accélération.", "correct": true} + ] + }, + { + "num": 213, + "libelle": "En cas de décrochage près du sol :", + "answers": [ + {"index": "A", "libelle": "Il faut relâcher un tout petit peu les commandes de manœuvre, très doucement.", "correct": true}, + {"index": "B", "libelle": "Il faut relâcher le plus vite possible les commandes de manœuvre.", "correct": false}, + {"index": "C", "libelle": "Il faut maintenir les commandes enfoncées.", "correct": false} + ] + }, + { + "num": 214, + "libelle": "En décrochage :", + "answers": [ + {"index": "A", "libelle": "Il est toujours possible de contrôler la voile avec les commandes de manœuvre.", "correct": false}, + {"index": "B", "libelle": "L’aile n’est plus pilotable normalement.", "correct": true} + ] + }, + { + "num": 215, + "libelle": "Après un décrochage, il faut plusieurs secondes pour que la voilure reprenne sa ligne de vol.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 216, + "libelle": "Après un décrochage, la perte de hauteur avant le retour à un vol normal peut être supérieur à:", + "answers": [ + {"index": "A", "libelle": "Pas de perte de hauteur.", "correct": false}, + {"index": "B", "libelle": "20 m.", "correct": false}, + {"index": "C", "libelle": "100 m.", "correct": true} + ] + }, + { + "num": 217, + "libelle": "La vitesse de descente d’une voilure pour une masse et un pourcentage de frein donné :", + "answers": [ + {"index": "A", "libelle": "Dépend du gradient turbulo-laminaire de vent", "correct": false}, + {"index": "B", "libelle": "Est supérieure dans le vent.", "correct": false}, + {"index": "C", "libelle": "Est identique quel que soit le vent.", "correct": true}, + {"index": "D", "libelle": "Est supérieure face au vent.", "correct": false} + ] + }, + { + "num": 218, + "libelle": "Si il y a du vent, une voilure de type aile se met naturellement dans le vent.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": false}, + {"index": "B", "libelle": "Faux.", "correct": true}, + {"index": "C", "libelle": "Uniquement si le vent est fort.", "correct": false} + ] + }, + { + "num": 219, + "libelle": "Si il y a du vent, une voilure de type aile se met naturellement contre le vent.", + "answers": [ + {"index": "A", "libelle": "Uniquement si le vent est fort.", "correct": false}, + {"index": "B", "libelle": "Faux.", "correct": true}, + {"index": "C", "libelle": "Vrai.", "correct": false} + ] + } + ] + }, + { + "num": 7, + "name": "Physiologie", + "questions": [ + { + "num": 220, + "libelle": "Avec l’altitude, les problèmes lié à l’hypoxie sont dus à :", + "answers": [ + {"index": "A", "libelle": "Une augmentation de la pression partielle d’oxygène.", "correct": false}, + {"index": "B", "libelle": "Une diminution de la pression partielle d’oxygène.", "correct": true} + ] + }, + { + "num": 221, + "libelle": "Est-il important d’être en bonne condition physique pour sauter en parachute ?", + "answers": [ + {"index": "A", "libelle": "Uniquement pour les compétiteurs.", "correct": false}, + {"index": "B", "libelle": "Oui car elle atténue les conséquences de microtraumatismes répétés.", "correct": true}, + {"index": "C", "libelle": "Non car le saut ne requiert pas beaucoup d’efforts.", "correct": false} + ] + }, + { + "num": 222, + "libelle": "Avant de débuter une journée de sauts :", + "answers": [ + {"index": "A", "libelle": "Il faut s’alimenter.", "correct": true}, + {"index": "B", "libelle": "Mieux vaut ne rien manger.", "correct": false} + ] + }, + { + "num": 223, + "libelle": "L’absorption d’alcool pendant une journée de saut :", + "answers": [ + {"index": "A", "libelle": "Est sans importance tant que l’on reste dans des limites raisonnables.", "correct": false}, + {"index": "B", "libelle": "Est à proscrire absolument.", "correct": true}, + {"index": "C", "libelle": "Donne un peu de courage.", "correct": false} + ] + }, + { + "num": 224, + "libelle": "Comment appelle t’ont le phénomène physiologique dû à une insuffisance en oxygène ?", + "answers": [ + {"index": "A", "libelle": "L’hypoxie.", "correct": true}, + {"index": "B", "libelle": "L’hypoglycémie.", "correct": false}, + {"index": "C", "libelle": "L’hyperventilation.", "correct": false} + ] + }, + { + "num": 225, + "libelle": "Quelle est la partie du corps qui, souffrant du manque d’oxygène, est la plus problématique pour le parachutisme ?", + "answers": [ + {"index": "A", "libelle": "Le cerveau.", "correct": true}, + {"index": "B", "libelle": "L’estomac.", "correct": false}, + {"index": "C", "libelle": "Les poumons.", "correct": false}, + {"index": "D", "libelle": "Les oreilles.", "correct": false} + ] + }, + { + "num": 226, + "libelle": "A 6000 mètres, ne pas avoir d’oxygène à bord présente un risque de troubles physiologiques importants pouvant aller jusqu’à la perte de connaissance.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + }, + { + "num": 227, + "libelle": "En cas d’hypoxie, le froid est un facteur aggravant vis à vis des problèmes rencontrés.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux, les deux sont complètement indépendants.", "correct": false} + ] + }, + { + "num": 228, + "libelle": "Les problèmes d’hypoxie peuvent apparaître à partir de 3500 m.", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": true}, + {"index": "B", "libelle": "Faux.", "correct": false} + ] + }, + { + "num": 229, + "libelle": "Les problèmes liés à l’hypoxie sont dépendant du temps passé en altitude.", + "answers": [ + {"index": "A", "libelle": "Faux.", "correct": false}, + {"index": "B", "libelle": "Vrai.", "correct": true} + ] + } + ] + }, + { + "num": 8, + "name": "Connaissances générales", + "questions": [ + { + "num": 230, + "libelle": "Pour embarquer dans un hélicoptère léger :", + "answers": [ + {"index": "A", "libelle": "C’est sans importance.", "correct": false}, + {"index": "B", "libelle": "Il faut aborder l’appareil par l’arrière.", "correct": false}, + {"index": "C", "libelle": "Il faut aborder l’appareil par l’avant.", "correct": true} + ] + }, + { + "num": 231, + "libelle": "En montant dans l’avion :", + "answers": [ + {"index": "A", "libelle": "On risque d’accrocher quelque chose sur son équipement si l’on ne fait pas attention.", "correct": true}, + {"index": "B", "libelle": "Ce risque est négligeable.", "correct": false} + ] + }, + { + "num": 232, + "libelle": "Quand l’avion prend l’axe de largage :", + "answers": [ + {"index": "A", "libelle": "Il est inutile de contrôler son équipement.", "correct": false}, + {"index": "B", "libelle": "Il faut contrôler quelques points essentiels de son équipement avant de sauter.", "correct": true} + ] + }, + { + "num": 233, + "libelle": "En sortie d’avion", + "answers": [ + {"index": "A", "libelle": "Il ne faut plus s’occuper de problèmes de matériel.", "correct": false}, + {"index": "B", "libelle": "Il faut veiller à ne rien accrocher sur son équipement.", "correct": true} + ] + }, + { + "num": 234, + "libelle": "Pour sauter la première fois d’un avion gros porteur :", + "answers": [ + {"index": "A", "libelle": "Je m’informe des consignes particulières.", "correct": true}, + {"index": "B", "libelle": "Inutile, je suivrai les autres.", "correct": false} + ] + }, + { + "num": 235, + "libelle": "En chute, la vitesse moyenne à plat face au sol :", + "answers": [ + {"index": "A", "libelle": "Est proche de 150 km/h.", "correct": false}, + {"index": "B", "libelle": "Est proche de 200 km/h.", "correct": true}, + {"index": "C", "libelle": "Est proche de 250 km/h.", "correct": false} + ] + }, + { + "num": 236, + "libelle": "La perte de hauteur en chute libre à plat face sol est de :", + "answers": [ + {"index": "A", "libelle": "Approximativement 300 m pendant les 10 premières secondes puis 50 m/s.", "correct": true}, + {"index": "B", "libelle": "Approximativement 50 m/s pendant toute la chute.", "correct": false}, + {"index": "C", "libelle": "Approximativement 500 m pendant les 10 premières secondes puis 50 m/s.", "correct": false} + ] + }, + { + "num": 237, + "libelle": "La vitesse verticale de chute est en moyenne de :", + "answers": [ + {"index": "A", "libelle": "50 m/s et ne dépasse jamais 60 m/s.", "correct": false}, + {"index": "B", "libelle": "50 m/s, elle peut dépasser 70 m/s en piqué ou tête en bas.", "correct": true} + ] + }, + { + "num": 238, + "libelle": "Quand on chute à plat face au sol, après 15 secondes de chute, on a perdu :", + "answers": [ + {"index": "A", "libelle": "700 m de hauteur.", "correct": false}, + {"index": "B", "libelle": "550 m de hauteur.", "correct": true}, + {"index": "C", "libelle": "400 m de hauteur.", "correct": false} + ] + }, + { + "num": 239, + "libelle": "La vitesse de chute tête en bas ou debout :", + "answers": [ + {"index": "A", "libelle": "Peut atteindre 300 km/h.", "correct": true}, + {"index": "B", "libelle": "Est sensiblement la même qu’à plat face sol.", "correct": false}, + {"index": "C", "libelle": "Ne dépasse pas 250 km/h.", "correct": false} + ] + }, + { + "num": 240, + "libelle": "Lors d’un saut de groupe :", + "answers": [ + {"index": "A", "libelle": "Il faut toujours assurer la sécurité en chute pour éviter tout risque de collisions.", "correct": true}, + {"index": "B", "libelle": "Les risques de collision sont faibles car tout le monde chute à la même vitesse.", "correct": false} + ] + }, + { + "num": 241, + "libelle": "Lors d’un saut de groupe :", + "answers": [ + {"index": "A", "libelle": "Avant d’ouvrir, il suffit de dériver longtemps pour éviter tout risque de collision.", "correct": false}, + {"index": "B", "libelle": "Il faut dériver en contrôlant sa trajectoire et garder si possible le contact visuel sur les autres parachutistes pour s’assurer que la séparation est suffisante.", "correct": true} + ] + }, + { + "num": 242, + "libelle": "Si vous n’avez pas sauté depuis plusieurs mois, vous programmez :", + "answers": [ + {"index": "A", "libelle": "Un saut de reprise, sans exercice particulier, avec un matériel que vous connaissez et en adaptant la hauteur d’ouverture.", "correct": true}, + {"index": "B", "libelle": "Un saut de VR ou de free fly afin de ne pas être seul.", "correct": false}, + {"index": "C", "libelle": "N’importe quel type de saut.", "correct": false} + ] + }, + { + "num": 243, + "libelle": "En faisant des virages rapides et enchaînés en dessous de 500 mètres :", + "answers": [ + {"index": "A", "libelle": "Il n’y a pas de risques particuliers.", "correct": false}, + {"index": "B", "libelle": "On risque de faire fonctionner le déclencheur de sécurité ou d’entrer en collision avec d’autres parachutistes.", "correct": true} + ] + }, + { + "num": 244, + "libelle": "L’atterrissage dans une pente prononcée, par temps calme sur un grand terrain ou rien n’indique le vent se fait de préférence :", + "answers": [ + {"index": "A", "libelle": "En travers de la pente.", "correct": true}, + {"index": "B", "libelle": "Face à la pente.", "correct": false}, + {"index": "C", "libelle": "Dans le sens de la pente.", "correct": false} + ] + }, + { + "num": 245, + "libelle": "En finale, hors zone, vous vous rapprochez dangereusement d’une ligne électrique face à vous.", + "answers": [ + {"index": "A", "libelle": "Vous conservez votre trajectoire en freinant au maximum et en espérant que ça va passer.", "correct": false}, + {"index": "B", "libelle": "Il faut l’éviter à tout prix, vous changez de trajectoire.", "correct": true} + ] + }, + { + "num": 246, + "libelle": "Lors d’un atterrissage hors zone, l’objectif prioritaire est de :", + "answers": [ + {"index": "A", "libelle": "Se poser face au vent.", "correct": false}, + {"index": "B", "libelle": "Se poser hors obstacles avec une trajectoire dégagée.", "correct": true} + ] + }, + { + "num": 247, + "libelle": "Parachute ouvert, vous constatez que vous ne pourrez pas rejoindre la zone de sauts. Il faut :", + "answers": [ + {"index": "A", "libelle": "Ne pas survoler d’obstacles, surtout à basse hauteur.", "correct": true}, + {"index": "B", "libelle": "Se rapprocher au maximum au plus près de la zone, quel que soit le terrain survolé.", "correct": false} + ] + }, + { + "num": 248, + "libelle": "Parachute ouvert, vous constatez que vous ne pourrez pas rejoindre la zone d’atterrissage prévue. Il faut :", + "answers": [ + {"index": "A", "libelle": "Trouver rapidement une zone de dégagement facile à atteindre même si elle est très éloignée de la zone d’atterrissage prévue.", "correct": true}, + {"index": "B", "libelle": "Se rapprocher au maximum au plus près de la zone d’atterrissage prévue.", "correct": false} + ] + }, + { + "num": 249, + "libelle": "Parachute ouvert, vous constatez que vous ne pourrez pas rejoindre la zone de saut. Il faut :", + "answers": [ + {"index": "A", "libelle": "Attendre d’être près du sol pour bien voir les obstacles.", "correct": false}, + {"index": "B", "libelle": "Repérer dès que possible les obstacles et les zones dégagées.", "correct": true} + ] + }, + { + "num": 250, + "libelle": "Piste 27 en service signifie :", + "answers": [ + {"index": "A", "libelle": "Que l’avion va décoller face au sud.", "correct": false}, + {"index": "B", "libelle": "Que l’avion va décoller face à l’est.", "correct": false}, + {"index": "C", "libelle": "Que l’avion va décoller face au nord.", "correct": false}, + {"index": "D", "libelle": "Que l’avion va décoller face à l’ouest.", "correct": true} + ] + }, + { + "num": 251, + "libelle": "Piste 09 en service signifie :", + "answers": [ + {"index": "A", "libelle": "Que l’avion va décoller face à l’ouest.", "correct": false}, + {"index": "B", "libelle": "Que l’avion va décoller face à l’est.", "correct": true}, + {"index": "C", "libelle": "Que l’avion va décoller face au nord.", "correct": false}, + {"index": "D", "libelle": "Que l’avion va décoller face au sud.", "correct": false} + ] + }, + { + "num": 252, + "libelle": "Piste 18 en service signifie :", + "answers": [ + {"index": "A", "libelle": "Que l’avion va décoller face au nord.", "correct": false}, + {"index": "B", "libelle": "Que l’avion va décoller face à l’est.", "correct": false}, + {"index": "C", "libelle": "Que l’avion va décoller face au sud.", "correct": true}, + {"index": "D", "libelle": "Que l’avion va décoller face à l’ouest.", "correct": false} + ] + }, + { + "num": 253, + "libelle": "Piste 36 en service signifie :", + "answers": [ + {"index": "A", "libelle": "Que l’avion va décoller face au nord.", "correct": true}, + {"index": "B", "libelle": "Que l’avion va décoller face à l’est.", "correct": false}, + {"index": "C", "libelle": "Que l’avion va décoller face au sud.", "correct": false}, + {"index": "D", "libelle": "Que l’avion va décoller face à l’ouest.", "correct": false} + ] + }, + { + "num": 254, + "libelle": "En embarquant dans l’avion si vous remarquez quelque chose d’anormal :", + "answers": [ + {"index": "A", "libelle": "Il faut le signaler immédiatement au pilote.", "correct": true}, + {"index": "B", "libelle": "Il ne faut rien lui dire pour ne pas le perturber.", "correct": false} + ] + }, + { + "num": 255, + "libelle": "Quand l’avion prend l’axe de largage :", + "answers": [ + {"index": "A", "libelle": "Il faut contrôler ou faire contrôler son équipement pour éviter une ouverture intempestive en chute ou à la mise en place.", "correct": true}, + {"index": "B", "libelle": "Il est inutile de contrôler ou de faire contrôler son équipement car cela a été fait au sol.", "correct": false} + ] + }, + { + "num": 256, + "libelle": "En sortie d’avion en position flotteur :", + "answers": [ + {"index": "A", "libelle": "Il est possible de se tenir à n’importe quelle partie de la cellule.", "correct": false}, + {"index": "B", "libelle": "Des équipements spécifiques doivent être mis en place pour se tenir.", "correct": true} + ] + }, + { + "num": 257, + "libelle": "Lors d’un largage par vent nul, vous sortez troisième du passage.", + "answers": [ + {"index": "A", "libelle": "Vous laissez environ 8 secondes, vous surveillez le précèdent et vous contrôlez la zone et l’axe sur lesquels vous partez.", "correct": true}, + {"index": "B", "libelle": "Seul le temps de séparation compte.", "correct": false} + ] + }, + { + "num": 258, + "libelle": "Vous partez premier du passage ; le pilote donne l’autorisation de sortie.", + "answers": [ + {"index": "A", "libelle": "Vous ouvrez la porte et vous sautez.", "correct": false}, + {"index": "B", "libelle": "Vous ouvrez la porte, vous contrôlez la zone et l’axe sur lesquels vous allez partir avant de sautez.", "correct": true} + ] + }, + { + "num": 259, + "libelle": "Contrôler ou faire contrôler son équipement avant la sortie d’avion est :", + "answers": [ + {"index": "A", "libelle": "Inutile puisque déjà fait au sol.", "correct": false}, + {"index": "B", "libelle": "Conseillé juste pour les élèves.", "correct": false}, + {"index": "C", "libelle": "Indispensable quel que soit le niveau du parachutiste.", "correct": true} + ] + }, + { + "num": 260, + "libelle": "Avant de s’équiper faut-il effectuer une vérification de son parachute ?", + "answers": [ + {"index": "A", "libelle": "Non c’est inutile car cela sera fait lors de la vérification d’embarquement.", "correct": false}, + {"index": "B", "libelle": "Oui c’est important.", "correct": true} + ] + }, + { + "num": 261, + "libelle": "Que signifient les deux chiffres placés à l’entrée d’une piste ?", + "answers": [ + {"index": "A", "libelle": "L’orientation de la piste", "correct": true}, + {"index": "B", "libelle": "La longueur de la piste.", "correct": false}, + {"index": "C", "libelle": "Le code OACI de l’aérodrome.", "correct": false} + ] + } + ] + }, + { + "num": 9, + "name": "Unités de mesure", + "questions": [ + { + "num": 262, + "libelle": "Pour convertir des pieds/ minute (ft/min) en m/s on utilise la règle suivante :", + "answers": [ + {"index": "A", "libelle": "1000 ft/min = 3 m/s", "correct": false}, + {"index": "B", "libelle": "1000 ft/min = 5 m/s", "correct": true}, + {"index": "C", "libelle": "1000 ft/min = 30 m/s", "correct": false} + ] + }, + { + "num": 263, + "libelle": "Une vitesse verticale de 13 m/s correspond à environ :", + "answers": [ + {"index": "A", "libelle": "7000 ft/min.", "correct": false}, + {"index": "B", "libelle": "1000 ft/min.", "correct": false}, + {"index": "C", "libelle": "2500 ft/min.", "correct": true}, + {"index": "D", "libelle": "3500 ft/min.", "correct": false} + ] + }, + { + "num": 264, + "libelle": "Une vitesse verticale de 35 m/s correspond approximativement à :", + "answers": [ + {"index": "A", "libelle": "3500 ft/min.", "correct": false}, + {"index": "B", "libelle": "2500 ft/min.", "correct": false}, + {"index": "C", "libelle": "7000 ft/min.", "correct": true}, + {"index": "D", "libelle": "8500 ft/min.", "correct": false} + ] + }, + { + "num": 265, + "libelle": "Dire qu’un mètre est égale à trois pieds est :", + "answers": [ + {"index": "A", "libelle": "Parfaitement Juste.", "correct": false}, + {"index": "B", "libelle": "Approximatif mais acceptable.", "correct": true}, + {"index": "C", "libelle": "Trop approximatif.", "correct": false} + ] + }, + { + "num": 266, + "libelle": "Un mètre est égale à :", + "answers": [ + {"index": "A", "libelle": "32,808 pieds soit environ 33 pieds.", "correct": false}, + {"index": "B", "libelle": "3,2808 pieds soit environ 3.3 pieds.", "correct": true}, + {"index": "C", "libelle": "3 pieds.", "correct": false} + ] + }, + { + "num": 267, + "libelle": "Un pied est égal à :", + "answers": [ + {"index": "A", "libelle": "33 cm.", "correct": false}, + {"index": "B", "libelle": "34,08 cm.", "correct": false}, + {"index": "C", "libelle": "30,48 cm.", "correct": true}, + {"index": "D", "libelle": "30 cm.", "correct": false} + ] + }, + { + "num": 268, + "libelle": "Un pied carré est sensiblement égale à :", + "answers": [ + {"index": "A", "libelle": "1,2m2", "correct": false}, + {"index": "B", "libelle": "0,09 m2", "correct": true}, + {"index": "C", "libelle": "0,9 m2", "correct": false} + ] + }, + { + "num": 269, + "libelle": "1 mille terrestre est égal à :", + "answers": [ + {"index": "A", "libelle": "1609 m.", "correct": true}, + {"index": "B", "libelle": "2185 m.", "correct": false}, + {"index": "C", "libelle": "1852 m.", "correct": false} + ] + }, + { + "num": 270, + "libelle": "1 mille nautique est égale à :", + "answers": [ + {"index": "A", "libelle": "1609 m.", "correct": false}, + {"index": "B", "libelle": "2185 m.", "correct": false}, + {"index": "C", "libelle": "1852 m.", "correct": true} + ] + }, + { + "num": 271, + "libelle": "Une vitesse d’un mètre par seconde (1 m/s) est égale à :", + "answers": [ + {"index": "A", "libelle": "3,6 km/h.", "correct": true}, + {"index": "B", "libelle": "36 km/h.", "correct": false}, + {"index": "C", "libelle": "6,3 km/h.", "correct": false} + ] + }, + { + "num": 272, + "libelle": "Une vitesse de 36 km/h est égale à :", + "answers": [ + {"index": "A", "libelle": "16 m/s.", "correct": false}, + {"index": "B", "libelle": "10 m/s.", "correct": true}, + {"index": "C", "libelle": "6 m/s.", "correct": false}, + {"index": "D", "libelle": "3.6 m/s.", "correct": false} + ] + } + ] + }, + { + "num": 10, + "name": "Altimétrie", + "questions": [ + { + "num": 273, + "libelle": "L’altimètre fournit au parachutiste des informations d’altitude en mesurant des différences :", + "answers": [ + {"index": "A", "libelle": "De pression.", "correct": true}, + {"index": "B", "libelle": "De température.", "correct": false}, + {"index": "C", "libelle": "De masse volumique.", "correct": false} + ] + }, + { + "num": 274, + "libelle": "Un niveau de vol c’est :", + "answers": [ + {"index": "A", "libelle": "L’indication donnée par l’altimètre quand il est réglé à zéro au sol.", "correct": false}, + {"index": "B", "libelle": "L’indication donnée par l’altimètre quand il est réglé au QNH au sol.", "correct": false}, + {"index": "C", "libelle": "L’indication donnée par l’altimètre quand il est réglé à 1013.25 hPa au sol.", "correct": true} + ] + }, + { + "num": 275, + "libelle": "Voler au niveau 115 signifie :", + "answers": [ + {"index": "A", "libelle": "Que l’on vole à une hauteur réelle de 11500 pieds.", "correct": false}, + {"index": "B", "libelle": "Qu’un altimètre calé à 1013,25 hPa indique 11500 pieds.", "correct": true}, + {"index": "C", "libelle": "Que l’on vole à une altitude de 11500 mètres.", "correct": false}, + {"index": "D", "libelle": "Qu’un altimètre calé à 1013,25 hPa indique 11500 mètres.", "correct": false} + ] + }, + { + "num": 276, + "libelle": "En atmosphère standard :", + "answers": [ + {"index": "A", "libelle": "La pression est de 1013,25 hPa au niveau de la mer.", "correct": true}, + {"index": "B", "libelle": "La pression est de 1013,25 hPa au sol.", "correct": false} + ] + }, + { + "num": 277, + "libelle": "L’altitude :", + "answers": [ + {"index": "A", "libelle": "Est la distance sur un axe vertical entre un point et le sol.", "correct": false}, + {"index": "B", "libelle": "Est la distance sur un axe vertical entre un point et le niveau de la mer.", "correct": true}, + {"index": "C", "libelle": "Est la distance sur un axe vertical entre un point et la surface isobare 1013.25 hPa.", "correct": false} + ] + }, + { + "num": 278, + "libelle": "La hauteur :", + "answers": [ + {"index": "A", "libelle": "Est la distance sur un axe vertical entre un point et le niveau de la mer.", "correct": false}, + {"index": "B", "libelle": "Est la distance sur un axe vertical entre un point et le sol.", "correct": true}, + {"index": "C", "libelle": "Est la distance sur un axe vertical entre un point et la surface isobare 1013.25 hPa.", "correct": false} + ] + }, + { + "num": 279, + "libelle": "La distance verticale entre un point et le sol est :", + "answers": [ + {"index": "A", "libelle": "La hauteur.", "correct": true}, + {"index": "B", "libelle": "L’altitude.", "correct": false}, + {"index": "C", "libelle": "Un niveau de vol.", "correct": false} + ] + }, + { + "num": 280, + "libelle": "La distance verticale entre un point et le niveau de la mer est :", + "answers": [ + {"index": "A", "libelle": "La hauteur.", "correct": false}, + {"index": "B", "libelle": "L’altitude.", "correct": true}, + {"index": "C", "libelle": "Un niveau de vol.", "correct": false} + ] + }, + { + "num": 281, + "libelle": "La distance verticale entre un point et la surface isobare 1013.25 hPa est :", + "answers": [ + {"index": "A", "libelle": "L’altitude.", "correct": false}, + {"index": "B", "libelle": "Un niveau de vol.", "correct": true}, + {"index": "C", "libelle": "La hauteur.", "correct": false} + ] + }, + { + "num": 282, + "libelle": "Une hauteur de 3000 pieds en atmosphère standard est approximativement égale à :", + "answers": [ + {"index": "A", "libelle": "1000 m.", "correct": false}, + {"index": "B", "libelle": "900 m.", "correct": true}, + {"index": "C", "libelle": "1100 m.", "correct": false} + ] + }, + { + "num": 283, + "libelle": "Le pied (ft) est une unité de mesure qui est égale à :", + "answers": [ + {"index": "A", "libelle": "0.30 cm.", "correct": false}, + {"index": "B", "libelle": "33 cm.", "correct": false}, + {"index": "C", "libelle": "30,48 cm.", "correct": true} + ] + }, + { + "num": 284, + "libelle": "Le soir, au sol, votre altimètre indique 0. Le lendemain matin il indique + 100 m. Qu’en déduisez-vous ?", + "answers": [ + {"index": "A", "libelle": "Une dépression arrive ou la pression baisse.", "correct": true}, + {"index": "B", "libelle": "On va vers une situation anticyclonique.", "correct": false}, + {"index": "C", "libelle": "Le sol est monté.", "correct": false} + ] + }, + { + "num": 285, + "libelle": "Le soir, au sol, votre altimètre indique 0. Le lendemain matin il indique – 100 m. Qu’en déduisez-vous ?", + "answers": [ + {"index": "A", "libelle": "Une dépression arrive.", "correct": false}, + {"index": "B", "libelle": "On va vers une situation anticyclonique ou la pression augmente.", "correct": true}, + {"index": "C", "libelle": "Le sol est plus bas qu’hier.", "correct": false} + ] + }, + { + "num": 286, + "libelle": "Lorsqu’il y a une baisse de température :", + "answers": [ + {"index": "A", "libelle": "L’altimètre sous estime la hauteur.", "correct": false}, + {"index": "B", "libelle": "L’altimètre surestime la hauteur.", "correct": true}, + {"index": "C", "libelle": "La température n’a pas d’influence sur l’altimètre.", "correct": false} + ] + }, + { + "num": 287, + "libelle": "Lorsqu’il y a une hausse de température :", + "answers": [ + {"index": "A", "libelle": "L’altimètre sous-estime la hauteur.", "correct": true}, + {"index": "B", "libelle": "L’altimètre surestime la hauteur.", "correct": false}, + {"index": "C", "libelle": "La température n’a pas d’influence sur l’altimètre.", "correct": false} + ] + }, + { + "num": 288, + "libelle": "Lorsqu’il y a une baisse de pression (arrivé d’une dépression) :", + "answers": [ + {"index": "A", "libelle": "L’altimètre surestime la hauteur.", "correct": true}, + {"index": "B", "libelle": "Les changements de pression dues à la météorologie n’ont pas d’influence sur l’altimètre.", "correct": false}, + {"index": "C", "libelle": "L’altimètre sous-estime la hauteur.", "correct": false} + ] + }, + { + "num": 289, + "libelle": "Lorsqu’il y a une hausse de pression (arrivé d’un anticyclone) :", + "answers": [ + {"index": "A", "libelle": "L’altimètre surestime la hauteur.", "correct": false}, + {"index": "B", "libelle": "L’altimètre sous-estime la hauteur.", "correct": true}, + {"index": "C", "libelle": "Les changements de pression dues à la météorologie n’ont pas d’influence sur l’altimètre.", "correct": false} + ] + }, + { + "num": 290, + "libelle": "Quand vous sautez au niveau 135 (FL 135) :", + "answers": [ + {"index": "A", "libelle": "Vous sautez toujours à une altitude de 4115 mètres.", "correct": false}, + {"index": "B", "libelle": "Pour connaitre la hauteur précise du saut il faut déduire l’altitude terrain.", "correct": false}, + {"index": "C", "libelle": "La hauteur du saut va varier en fonction des conditions météorologique et de l’altitude du terrain.", "correct": true}, + {"index": "D", "libelle": "Vous sautez toujours à une hauteur de 4000 mètres.", "correct": false} + ] + }, + { + "num": 291, + "libelle": "Votre zone de saut est à 500 mètres d’altitude. Quand vous sautez au niveau 145 (FL 145) :", + "answers": [ + {"index": "A", "libelle": "Vous sautez toujours à une altitude de 3920 mètres.", "correct": false}, + {"index": "B", "libelle": "a hauteur du saut va varier en fonction des conditions météorologique et de l’altitude du terrain.", "correct": true}, + {"index": "C", "libelle": "Vous sautez toujours à une hauteur de 3920 mètres.", "correct": false}, + {"index": "D", "libelle": "Vous sautez toujours à une altitude de 4420 mètres.", "correct": false} + ] + } + ] + }, + { + "num": 11, + "name": "Météorologie et aérologie", + "questions": [ + { + "num": 292, + "libelle": "En atmosphère standard :", + "answers": [ + {"index": "A", "libelle": "La température décroît de 8.5° c tous les 1000 m.", "correct": false}, + {"index": "B", "libelle": "La température décroît de 6.5° c tous les 1000 m.", "correct": true}, + {"index": "C", "libelle": "La température décroît de 10° c tous les 1000 m.", "correct": false} + ] + }, + { + "num": 293, + "libelle": "En atmosphère standard, quelle température fera-t-il à 4000 mètres si la température au sol est de 20° c ?", + "answers": [ + {"index": "A", "libelle": "+13.5° c.", "correct": false}, + {"index": "B", "libelle": "-6° c.", "correct": true}, + {"index": "C", "libelle": "–20° c.", "correct": false} + ] + }, + { + "num": 294, + "libelle": "En atmosphère standard, quelle température fera-t-il à 3000 mètres si la température au sol est de 10° c ?", + "answers": [ + {"index": "A", "libelle": "0° c.", "correct": false}, + {"index": "B", "libelle": "– 9.5° c.", "correct": true}, + {"index": "C", "libelle": "+ 6.5° c.", "correct": false} + ] + }, + { + "num": 295, + "libelle": "En atmosphère standard, quelle température fera-t-il à 4000 mètres si la température au sol est de 0° c ?", + "answers": [ + {"index": "A", "libelle": "–26° c.", "correct": true}, + {"index": "B", "libelle": "–54° c.", "correct": false}, + {"index": "C", "libelle": "–10° c.", "correct": false} + ] + }, + { + "num": 296, + "libelle": "Comment s’appellent Les lignes d’égale pression représentées sur les cartes météo ?", + "answers": [ + {"index": "A", "libelle": "Les lignes isohypses.", "correct": false}, + {"index": "B", "libelle": "Les lignes isothermes.", "correct": false}, + {"index": "C", "libelle": "Les lignes isobares.", "correct": true} + ] + }, + { + "num": 297, + "libelle": "Sur une carte météo, plus les lignes isobares sont serrées :", + "answers": [ + {"index": "A", "libelle": "Plus le vent est fort.", "correct": true}, + {"index": "B", "libelle": "Moins le vent est fort.", "correct": false}, + {"index": "C", "libelle": "La vitesse du vent ne dépend pas du resserrement des isobares.", "correct": false} + ] + }, + { + "num": 298, + "libelle": "Comment appelle-t-on une zone de hautes pressions généralisées ?", + "answers": [ + {"index": "A", "libelle": "Une dépression.", "correct": false}, + {"index": "B", "libelle": "Un thalweg.", "correct": false}, + {"index": "C", "libelle": "Un anticyclone.", "correct": true}, + {"index": "D", "libelle": "Une dorsale.", "correct": false} + ] + }, + { + "num": 299, + "libelle": "Comment appelle-t-on une zone de basses pressions généralisées ?", + "answers": [ + {"index": "A", "libelle": "Une dépression.", "correct": true}, + {"index": "B", "libelle": "Un thalweg.", "correct": false}, + {"index": "C", "libelle": "Un anticyclone.", "correct": false}, + {"index": "D", "libelle": "Une dorsale.", "correct": false} + ] + }, + { + "num": 300, + "libelle": "Comment appelle-t-on une crête de haute pression ?", + "answers": [ + {"index": "A", "libelle": "Une dépression.", "correct": false}, + {"index": "B", "libelle": "Un thalweg.", "correct": false}, + {"index": "C", "libelle": "Un anticyclone.", "correct": false}, + {"index": "D", "libelle": "Une dorsale.", "correct": true} + ] + }, + { + "num": 301, + "libelle": "Comment appelle-t-on une vallée de basse pression ?", + "answers": [ + {"index": "A", "libelle": "Une dépression.", "correct": false}, + {"index": "B", "libelle": "Un thalweg.", "correct": true}, + {"index": "C", "libelle": "Un anticyclone.", "correct": false}, + {"index": "D", "libelle": "Une dorsale.", "correct": false} + ] + }, + { + "num": 302, + "libelle": "Quand on monte en altitude, la pression atmosphérique :", + "answers": [ + {"index": "A", "libelle": "Augmente ou diminue suivant la situation météo.", "correct": false}, + {"index": "B", "libelle": "Diminue.", "correct": true}, + {"index": "C", "libelle": "Augmente.", "correct": false} + ] + }, + { + "num": 303, + "libelle": "La variation de pression entre le sol et 500 m. Est en moyenne de :", + "answers": [ + {"index": "A", "libelle": "1 hPa tous les 17 m.", "correct": false}, + {"index": "B", "libelle": "1 hPa tous les 11 m.", "correct": false}, + {"index": "C", "libelle": "1 hPa tous les 8.5 m.", "correct": true} + ] + }, + { + "num": 304, + "libelle": "Quand on monte en altitude en dessous de 500 m. La pression atmosphérique", + "answers": [ + {"index": "A", "libelle": "Augmente de 1 hPa tous les 8.5 m.", "correct": false}, + {"index": "B", "libelle": "Diminue de 1 hPa tous les 8.5 m.", "correct": true}, + {"index": "C", "libelle": "Diminue de 1 hPa tous les 11 m.", "correct": false} + ] + }, + { + "num": 305, + "libelle": "Un nuage est constitué :", + "answers": [ + {"index": "A", "libelle": "D’eau à l’état liquide ou solide.", "correct": true}, + {"index": "B", "libelle": "De vapeur d’eau uniquement.", "correct": false} + ] + }, + { + "num": 306, + "libelle": "On parle de brouillard :", + "answers": [ + {"index": "A", "libelle": "Quand la visibilité est inférieure à 100 m.", "correct": false}, + {"index": "B", "libelle": "Quand la visibilité est inférieure à 1 km.", "correct": true}, + {"index": "C", "libelle": "Quand la visibilité est réduite mais supérieure à 1 km.", "correct": false} + ] + }, + { + "num": 307, + "libelle": "On parle de brume :", + "answers": [ + {"index": "A", "libelle": "Quand la visibilité est inférieure à 100 m.", "correct": false}, + {"index": "B", "libelle": "Quand la visibilité est inférieure à 1 km.", "correct": false}, + {"index": "C", "libelle": "Quand la visibilité est réduite mais supérieure à 1 km.", "correct": true} + ] + }, + { + "num": 308, + "libelle": "A 5600 mètres d’altitude, la pression partielle d’oxygène :", + "answers": [ + {"index": "A", "libelle": "N’a pas changée.", "correct": false}, + {"index": "B", "libelle": "A diminué de 30%", "correct": false}, + {"index": "C", "libelle": "A diminué de moitié", "correct": true} + ] + }, + { + "num": 309, + "libelle": "Le vent est dû :", + "answers": [ + {"index": "A", "libelle": "Essentiellement aux phénomènes orageux.", "correct": false}, + {"index": "B", "libelle": "Aux différences de pression atmosphérique et aux différences de température.", "correct": true}, + {"index": "C", "libelle": "Aux marées.", "correct": false} + ] + }, + { + "num": 310, + "libelle": "Le vent en altitude est dû :", + "answers": [ + {"index": "A", "libelle": "Surtout à l’influence du sol et du relief.", "correct": false}, + {"index": "B", "libelle": "Aux anticyclones et aux dépressions.", "correct": true} + ] + }, + { + "num": 311, + "libelle": "Le vent au sol est dû :", + "answers": [ + {"index": "A", "libelle": "Uniquement à la nature du sol et au relief.", "correct": false}, + {"index": "B", "libelle": "Uniquement aux anticyclones et aux dépressions.", "correct": false}, + {"index": "C", "libelle": "A la situation météorologique générale et à l’influence du sol et du relief.", "correct": true} + ] + }, + { + "num": 312, + "libelle": "Dans une zone d’étranglement (col, vallée).", + "answers": [ + {"index": "A", "libelle": "La vitesse du vent augmente.", "correct": true}, + {"index": "B", "libelle": "La vitesse du vent diminue.", "correct": false}, + {"index": "C", "libelle": "Le relief n’a pas d’influence sur la vitesse du vent.", "correct": false} + ] + }, + { + "num": 313, + "libelle": "Un vent du sud-ouest :", + "answers": [ + {"index": "A", "libelle": "Souffle du sud au sol et de l’ouest en altitude.", "correct": false}, + {"index": "B", "libelle": "Souffle en provenance du sud-ouest.", "correct": true}, + {"index": "C", "libelle": "Souffle en direction du sud-ouest.", "correct": false} + ] + }, + { + "num": 314, + "libelle": "Le vent du nord :", + "answers": [ + {"index": "A", "libelle": "Souffle en provenance du nord.", "correct": true}, + {"index": "B", "libelle": "Souffle en direction du nord.", "correct": false} + ] + }, + { + "num": 315, + "libelle": "Un vent de 10 kts souffle à environ :", + "answers": [ + {"index": "A", "libelle": "5 m/s.", "correct": true}, + {"index": "B", "libelle": "10 m/s.", "correct": false}, + {"index": "C", "libelle": "20 m/s.", "correct": false} + ] + }, + { + "num": 316, + "libelle": "Un vent de 10 kts souffle à environ :", + "answers": [ + {"index": "A", "libelle": "36 km/h.", "correct": false}, + {"index": "B", "libelle": "18 km/h.", "correct": true}, + {"index": "C", "libelle": "10 km/h.", "correct": false} + ] + }, + { + "num": 317, + "libelle": "Un vent de 10 m/s souffle à environ :", + "answers": [ + {"index": "A", "libelle": "36 km/h.", "correct": true}, + {"index": "B", "libelle": "18 km/h.", "correct": false}, + {"index": "C", "libelle": "10 km/h.", "correct": false} + ] + }, + { + "num": 318, + "libelle": "Un vent de 18 kts souffle à environ :", + "answers": [ + {"index": "A", "libelle": "18 m/s.", "correct": false}, + {"index": "B", "libelle": "9 m/s.", "correct": true}, + {"index": "C", "libelle": "5 m/s.", "correct": false} + ] + }, + { + "num": 319, + "libelle": "Un vent de 7 m/s souffle à environ :", + "answers": [ + {"index": "A", "libelle": "36 km/h.", "correct": false}, + {"index": "B", "libelle": "18 km/h.", "correct": false}, + {"index": "C", "libelle": "25 km/h.", "correct": true} + ] + }, + { + "num": 320, + "libelle": "Un vent de 5 m/s souffle à environ :", + "answers": [ + {"index": "A", "libelle": "5 km/h.", "correct": false}, + {"index": "B", "libelle": "10 km/h.", "correct": false}, + {"index": "C", "libelle": "18 km/h.", "correct": true} + ] + }, + { + "num": 321, + "libelle": "Quelle est la vitesse du vent en m/s quand il souffle à 20 kts :", + "answers": [ + {"index": "A", "libelle": "10 m/s.", "correct": true}, + {"index": "B", "libelle": "5 m/s.", "correct": false}, + {"index": "C", "libelle": "18 m/s.", "correct": false} + ] + }, + { + "num": 322, + "libelle": "La météo annonce un vent du 270° ; cela veut dire qu’il vient :", + "answers": [ + {"index": "A", "libelle": "De l’ouest.", "correct": true}, + {"index": "B", "libelle": "Du nord.", "correct": false}, + {"index": "C", "libelle": "Du sud ouest.", "correct": false} + ] + }, + { + "num": 323, + "libelle": "Qu’appelle-t-on inversion de vent ?", + "answers": [ + {"index": "A", "libelle": "Le vent change de direction en altitude par rapport au vent au sol.", "correct": true}, + {"index": "B", "libelle": "C’est l’ordre de saut des parachutistes qui est inversé à cause du vent.", "correct": false}, + {"index": "C", "libelle": "Le vent souffle de façon irrégulière dans toutes les directions.", "correct": false} + ] + }, + { + "num": 324, + "libelle": "Qu’appelle-t-on cisaillement de vent ?", + "answers": [ + {"index": "A", "libelle": "C’est un vent suffisamment fort pour couper la cime des arbres.", "correct": false}, + {"index": "B", "libelle": "C’est la zone de séparation entre deux vents de sens contraire.", "correct": true} + ] + }, + { + "num": 325, + "libelle": "Qu’est-ce qu’une zone de cisaillement ?", + "answers": [ + {"index": "A", "libelle": "C’est une zone comprise entre deux couches d’air où la température est différente.", "correct": false}, + {"index": "B", "libelle": "C’est une zone comprise entre deux couches d’air où la pression est différente.", "correct": false}, + {"index": "C", "libelle": "C’est une zone comprise entre deux couches d’air où le vent n’a pas la même direction.", "correct": true} + ] + }, + { + "num": 326, + "libelle": "Le vent en altitude et le vent au sol :", + "answers": [ + {"index": "A", "libelle": "Peuvent souffler en sens contraire.", "correct": true}, + {"index": "B", "libelle": "Soufflent toujours dans le même sens.", "correct": false} + ] + }, + { + "num": 327, + "libelle": "Dans l’hémisphère nord, le vent :", + "answers": [ + {"index": "A", "libelle": "Tourne autour des dépressions dans le sens des aiguilles d’une montre et autour des anticyclones en sens inverse.", "correct": false}, + {"index": "B", "libelle": "Tourne autour des anticyclones dans le sens des aiguilles d’une montre et autour des dépressions en sens inverse.", "correct": true} + ] + }, + { + "num": 328, + "libelle": "Dans quel sens le vent tourne-t-il autour des anticyclones dans l’hémisphère nord ?", + "answers": [ + {"index": "A", "libelle": "Il tourne dans le sens des aiguilles d’une montre.", "correct": true}, + {"index": "B", "libelle": "Il tourne dans le sens inverse des aiguilles d’une montre.", "correct": false} + ] + }, + { + "num": 329, + "libelle": "Dans quel sens le vent tourne-t-il autour des dépressions dans l’hémisphère nord ?", + "answers": [ + {"index": "A", "libelle": "Il tourne dans le sens des aiguilles d’une montre.", "correct": false}, + {"index": "B", "libelle": "Il tourne dans le sens inverse des aiguilles d’une montre.", "correct": true} + ] + }, + { + "num": 330, + "libelle": "En altitude, le vent météo :", + "answers": [ + {"index": "A", "libelle": "Est dévié sur la droite dans l’hémisphère nord.", "correct": true}, + {"index": "B", "libelle": "Est dévié sur la gauche dans l’hémisphère nord.", "correct": false}, + {"index": "C", "libelle": "Ne subit aucune déviation.", "correct": false} + ] + }, + { + "num": 331, + "libelle": "En bord de mer, par ciel couvert sans vent météorologique :", + "answers": [ + {"index": "A", "libelle": "Il y aura probablement une brise soufflant de la mer vers la terre.", "correct": false}, + {"index": "B", "libelle": "Il y aura probablement une brise soufflant de la terre vers la mer.", "correct": false}, + {"index": "C", "libelle": "Il n’y aura probablement pas de brise.", "correct": true} + ] + }, + { + "num": 332, + "libelle": "En bord de mer, en été, en milieu d’après midi et par temps ensoleillé sans vent météorologique :", + "answers": [ + {"index": "A", "libelle": "Il y aura probablement une brise soufflant de la mer vers la terre.", "correct": true}, + {"index": "B", "libelle": "Il y aura probablement une brise soufflant de la terre vers la mer.", "correct": false}, + {"index": "C", "libelle": "Il n’y aura probablement pas de brise.", "correct": false} + ] + }, + { + "num": 333, + "libelle": "En milieu de journée, par temps ensoleillé, la brise souffle.", + "answers": [ + {"index": "A", "libelle": "De la terre vers la mer.", "correct": false}, + {"index": "B", "libelle": "De la mer vers la terre.", "correct": true} + ] + }, + { + "num": 334, + "libelle": "En bord de mer, la nuit, on risque d’avoir.", + "answers": [ + {"index": "A", "libelle": "De la brise de mer.", "correct": false}, + {"index": "B", "libelle": "De la brise de terre.", "correct": true}, + {"index": "C", "libelle": "Aucune brise.", "correct": false} + ] + }, + { + "num": 335, + "libelle": "Dans une vallée étroite, en milieu d’après midi et par temps ensoleillé, il y aura probablement :", + "answers": [ + {"index": "A", "libelle": "Une forte brise de vallée montante qui risque d’empêcher les sauts.", "correct": true}, + {"index": "B", "libelle": "Une forte brise de vallée montante mais il est toujours possible de sauter.", "correct": false}, + {"index": "C", "libelle": "Une forte brise de vallée descendante.", "correct": false} + ] + }, + { + "num": 336, + "libelle": "Sur une pente, par temps ensoleillé, on rencontre en milieu de journée :", + "answers": [ + {"index": "A", "libelle": "Des brises descendantes.", "correct": false}, + {"index": "B", "libelle": "Des brises montantes.", "correct": true} + ] + }, + { + "num": 337, + "libelle": "Les brises de vallée soufflent dans la même direction toute la journée :", + "answers": [ + {"index": "A", "libelle": "Vrai.", "correct": false}, + {"index": "B", "libelle": "Faux.", "correct": true} + ] + }, + { + "num": 338, + "libelle": "Les brises sont des vents :", + "answers": [ + {"index": "A", "libelle": "Bien établis, qui changent lentement.", "correct": false}, + {"index": "B", "libelle": "Qui soufflent dans tous les sens et changent sans cesse de direction.", "correct": false}, + {"index": "C", "libelle": "Bien établis, mais qui changent de direction en peu de temps.", "correct": true} + ] + }, + { + "num": 339, + "libelle": "Avec du vent, le risque de turbulences est maximum :", + "answers": [ + {"index": "A", "libelle": "Sur un relief accidenté.", "correct": true}, + {"index": "B", "libelle": "En plaine dans une zone dégagée.", "correct": false} + ] + }, + { + "num": 340, + "libelle": "Par fort vent, derrière un hangar :", + "answers": [ + {"index": "A", "libelle": "Il n’y a pas de turbulences.", "correct": false}, + {"index": "B", "libelle": "Il y a des turbulences.", "correct": true} + ] + }, + { + "num": 341, + "libelle": "Par fort vent derrière une haie d’arbres :", + "answers": [ + {"index": "A", "libelle": "Il n’y a pas de turbulences.", "correct": false}, + {"index": "B", "libelle": "Il y a des turbulences.", "correct": true} + ] + }, + { + "num": 342, + "libelle": "On risque de rencontrer des turbulences :", + "answers": [ + {"index": "A", "libelle": "En présence de stratus.", "correct": false}, + {"index": "B", "libelle": "En présence de cumulus.", "correct": true}, + {"index": "C", "libelle": "En présence de cirrus.", "correct": false} + ] + }, + { + "num": 343, + "libelle": "On risque surtout de rencontrer des turbulences :", + "answers": [ + {"index": "A", "libelle": "Par vent faible.", "correct": false}, + {"index": "B", "libelle": "Par vent fort.", "correct": true} + ] + }, + { + "num": 344, + "libelle": "On risque surtout de rencontrer des turbulences :", + "answers": [ + {"index": "A", "libelle": "Par temps chaud et ensoleillé.", "correct": true}, + {"index": "B", "libelle": "Par ciel couvert.", "correct": false} + ] + }, + { + "num": 345, + "libelle": "On risque surtout de rencontrer des turbulences :", + "answers": [ + {"index": "A", "libelle": "Au dessus des surfaces froides.", "correct": false}, + {"index": "B", "libelle": "Au dessus des surfaces chaudes.", "correct": true}, + {"index": "C", "libelle": "La température du sol n’a pas d’influence sur les turbulences.", "correct": false} + ] + }, + { + "num": 346, + "libelle": "Avec un vent de 5 m/s, les turbulences derrière une haie d’arbres ou un bâtiment de même hauteur sont dangereuses :", + "answers": [ + {"index": "A", "libelle": "Juste derrière sur quelques mètres.", "correct": false}, + {"index": "B", "libelle": "Jusqu’à plus de 50 m.", "correct": true}, + {"index": "C", "libelle": "Ne sont pas dangereuse avec un vent de 5 m/s.", "correct": false} + ] + }, + { + "num": 347, + "libelle": "Les vents rabattants en montagne :", + "answers": [ + {"index": "A", "libelle": "Ne sont pas dangereux car ils nous font dévier en plaine.", "correct": false}, + {"index": "B", "libelle": "Sont seulement dangereux pour les avions.", "correct": false}, + {"index": "C", "libelle": "Sont dangereux et risquent de nous plaquer contre le relief.", "correct": true} + ] + }, + { + "num": 348, + "libelle": "En été par temps chaud et en présence de cumulus bien développés :", + "answers": [ + {"index": "A", "libelle": "Il n’y a pas de turbulences.", "correct": false}, + {"index": "B", "libelle": "Il y a probablement des turbulences.", "correct": true} + ] + }, + { + "num": 349, + "libelle": "L’aérologie en montagne :", + "answers": [ + {"index": "A", "libelle": "Est bien moins turbulente qu’en plaine car l’air est frais.", "correct": false}, + {"index": "B", "libelle": "Est souvent plus turbulentes qu’en plaine.", "correct": true} + ] + }, + { + "num": 350, + "libelle": "Par temps chaud, les turbulences sont plus importantes :", + "answers": [ + {"index": "A", "libelle": "Au dessus d’un terrain en herbe.", "correct": false}, + {"index": "B", "libelle": "Au dessus des hangars et des parkings goudronnés.", "correct": true} + ] + }, + { + "num": 351, + "libelle": "Le risque de rencontrer des courants ascendants est maximum :", + "answers": [ + {"index": "A", "libelle": "Au-dessus des surfaces froides par temps couvert.", "correct": false}, + {"index": "B", "libelle": "Au-dessus des surfaces froides par temps ensoleillé.", "correct": false}, + {"index": "C", "libelle": "Au-dessus des surfaces chaudes par temps couvert.", "correct": false}, + {"index": "D", "libelle": "Au-dessus des surfaces chaudes par temps ensoleillé.", "correct": true} + ] + }, + { + "num": 352, + "libelle": "On risque de rencontrer des courants ascendants.", + "answers": [ + {"index": "A", "libelle": "Sous le vent d’un relief.", "correct": false}, + {"index": "B", "libelle": "Au vent d’un relief.", "correct": true} + ] + }, + { + "num": 353, + "libelle": "Á quel étage rencontre-t-on les nuages dont le nom comporte le préfixe « Cirro. » ?", + "answers": [ + {"index": "A", "libelle": "Á l’étage supérieur.", "correct": true}, + {"index": "B", "libelle": "Á l’étage moyen.", "correct": false}, + {"index": "C", "libelle": "Á l’étage inférieur.", "correct": false} + ] + }, + { + "num": 354, + "libelle": "Á quel étage rencontre-t-on les nuages dont le nom comporte le préfixe « Strato. » ?", + "answers": [ + {"index": "A", "libelle": "Á l’étage supérieur.", "correct": false}, + {"index": "B", "libelle": "Á l’étage moyen.", "correct": false}, + {"index": "C", "libelle": "Á l’étage inférieur.", "correct": true} + ] + }, + { + "num": 355, + "libelle": "Les cumulus sont des nuages :", + "answers": [ + {"index": "A", "libelle": "Isolés et de forme bien marqués.", "correct": true}, + {"index": "B", "libelle": "En voile ou en nappe continue avec des contours flous.", "correct": false}, + {"index": "C", "libelle": "En filaments.", "correct": false} + ] + }, + { + "num": 356, + "libelle": "Les nuages de type « cumulo. » se forment :", + "answers": [ + {"index": "A", "libelle": "Dans des conditions d’instabilité verticale.", "correct": true}, + {"index": "B", "libelle": "Dans des conditions de stabilité verticale.", "correct": false} + ] + }, + { + "num": 357, + "libelle": "Les stratus sont des nuages :", + "answers": [ + {"index": "A", "libelle": "Isolés et de forme bien marqués.", "correct": false}, + {"index": "B", "libelle": "En voile ou en nappe continue avec des contours flous.", "correct": true}, + {"index": "C", "libelle": "En filaments.", "correct": false} + ] + }, + { + "num": 358, + "libelle": "Les nuages de type « strato. » se forment", + "answers": [ + {"index": "A", "libelle": "Dans des conditions d’instabilité verticale.", "correct": false}, + {"index": "B", "libelle": "Dans des conditions de stabilité verticale.", "correct": true} + ] + }, + { + "num": 359, + "libelle": "Les cirrus sont des nuages :", + "answers": [ + {"index": "A", "libelle": "Isolés et de forme bien marqués.", "correct": false}, + {"index": "B", "libelle": "En voile ou en nappe continue avec des contours flous.", "correct": false}, + {"index": "C", "libelle": "En filaments.", "correct": true} + ] + }, + { + "num": 360, + "libelle": "Le nimbostratus :", + "answers": [ + {"index": "A", "libelle": "Un nuage de beau temps.", "correct": false}, + {"index": "B", "libelle": "Est un nuage épais associé à des précipitations durables.", "correct": true} + ] + }, + { + "num": 361, + "libelle": "La présence d’une couche nuageuse en altitude (cirrocumulus ou cirrostratus) :", + "answers": [ + {"index": "A", "libelle": "Indique que le mauvais temps est passé.", "correct": false}, + {"index": "B", "libelle": "Annonce l ‘arrivée d’une perturbation.", "correct": true} + ] + }, + { + "num": 362, + "libelle": "Les strato-cumulus :", + "answers": [ + {"index": "A", "libelle": "Sont des nuages bas.", "correct": true}, + {"index": "B", "libelle": "Sont des nuages de l’étage moyen.", "correct": false}, + {"index": "C", "libelle": "Sont des nuages d’altitude.", "correct": false} + ] + }, + { + "num": 363, + "libelle": "Quel est le nuage le plus dangereux pour le parachutisme ?", + "answers": [ + {"index": "A", "libelle": "Le cumulonimbus.", "correct": true}, + {"index": "B", "libelle": "Le cirro-stratus.", "correct": false}, + {"index": "C", "libelle": "Le cumulus.", "correct": false} + ] + }, + { + "num": 364, + "libelle": "A l’approche d’un orage :", + "answers": [ + {"index": "A", "libelle": "Le vent est stable en vitesse et en direction.", "correct": false}, + {"index": "B", "libelle": "S’il y a une accalmie de vent, c’est que le risque d’orage a disparu.", "correct": false}, + {"index": "C", "libelle": "Le vent peut s’inverser très rapidement de 180°.", "correct": true} + ] + }, + { + "num": 365, + "libelle": "A l’approche d’un orage :", + "answers": [ + {"index": "A", "libelle": "Il faut arrêter immédiatement les largages s’il y a des éclairs ou du tonnerre.", "correct": true}, + {"index": "B", "libelle": "On peut sauter tant que le vent ne dépasse pas la limite réglementaire.", "correct": false}, + {"index": "C", "libelle": "On peut sauter tant qu’il ne pleut pas.", "correct": false} + ] + }, + { + "num": 366, + "libelle": "Le risque d’orage est plus important :", + "answers": [ + {"index": "A", "libelle": "Au printemps et en été.", "correct": true}, + {"index": "B", "libelle": "En hiver.", "correct": false} + ] + }, + { + "num": 367, + "libelle": "En saison chaude, le risque d’orage est plus important :", + "answers": [ + {"index": "A", "libelle": "L’après-midi.", "correct": true}, + {"index": "B", "libelle": "Le matin.", "correct": false}, + {"index": "C", "libelle": "La nuit.", "correct": false} + ] + }, + { + "num": 368, + "libelle": "Lequel de ces nuages est un nuage d’orage ?", + "answers": [ + {"index": "A", "libelle": "Le strato-cumulus.", "correct": false}, + {"index": "B", "libelle": "Le cumulonimbus.", "correct": true}, + {"index": "C", "libelle": "L’altocumulus.", "correct": false} + ] + }, + { + "num": 369, + "libelle": "Voler près d’un cumulonimbus :", + "answers": [ + {"index": "A", "libelle": "Peux se faire tout de suite après le moment le plus fort de l’orage.", "correct": false}, + {"index": "B", "libelle": "N’est jamais dangereux tant que l’orage n’a pas éclaté.", "correct": false}, + {"index": "C", "libelle": "Est très dangereux.", "correct": true} + ] + }, + { + "num": 370, + "libelle": "Un nuage d’orage :", + "answers": [ + {"index": "A", "libelle": "Evolue toujours très lentement.", "correct": false}, + {"index": "B", "libelle": "Peut évoluer rapidement.", "correct": true} + ] + }, + { + "num": 371, + "libelle": "Un nuage d’orage :", + "answers": [ + {"index": "A", "libelle": "Peut être masqué par d’autres nuages.", "correct": true}, + {"index": "B", "libelle": "Est toujours visible de loin.", "correct": false} + ] + }, + { + "num": 372, + "libelle": "A l’approche d’un orage, il faut cesser les sauts :", + "answers": [ + {"index": "A", "libelle": "Uniquement si le vent au sol dépasse la limite autorisée.", "correct": false}, + {"index": "B", "libelle": "Dès que l’on a un doute sur la situation.", "correct": true} + ] + }, + { + "num": 373, + "libelle": "A proximité d’un cumulonimbus :", + "answers": [ + {"index": "A", "libelle": "Il y a toujours de fortes turbulences.", "correct": true}, + {"index": "B", "libelle": "Il n’y a pas de turbulences.", "correct": false} + ] + }, + { + "num": 374, + "libelle": "En situation orageuse, on rencontre :", + "answers": [ + {"index": "A", "libelle": "Des vents forts et en rafales qui peuvent atteindre des vitesses très élevées.", "correct": true}, + {"index": "B", "libelle": "Des vents forts mais réguliers.", "correct": false}, + {"index": "C", "libelle": "Des vents faibles.", "correct": false} + ] + }, + { + "num": 375, + "libelle": "L’orage est un phénomène :", + "answers": [ + {"index": "A", "libelle": "Très dangereux pour toutes les activités aéronautiques.", "correct": true}, + {"index": "B", "libelle": "Dangereux pour le parachutisme mais pas pour les avions.", "correct": false} + ] + }, + { + "num": 376, + "libelle": "Un nuage d’orage :", + "answers": [ + {"index": "A", "libelle": "Se déplace parfois en sens contraire au vent dominant.", "correct": true}, + {"index": "B", "libelle": "Se déplace toujours dans le sens du vent dominant.", "correct": false} + ] + }, + { + "num": 377, + "libelle": "Un cumulonimbus :", + "answers": [ + {"index": "A", "libelle": "Dépasse rarement 5000 mètres d’altitude à son sommet.", "correct": false}, + {"index": "B", "libelle": "Peut dépasser 5000 mètres d’altitude mais jamais 10000 mètres.", "correct": false}, + {"index": "C", "libelle": "Peut dépasser 10000 mètres d’altitude.", "correct": true} + ] + }, + { + "num": 378, + "libelle": "Le vent donne-t-il une indication sur l’évolution d’un cumulonimbus ?", + "answers": [ + {"index": "A", "libelle": "Oui.", "correct": false}, + {"index": "B", "libelle": "Non.", "correct": true} + ] + }, + { + "num": 379, + "libelle": "Une station météo proche du terrain passe un avis de tempête :", + "answers": [ + {"index": "A", "libelle": "Il faut arrêter la séance quand le vent atteint la limite autorisée.", "correct": false}, + {"index": "B", "libelle": "On peut continuer à sauter encore quelques temps en surveillant le vent.", "correct": false}, + {"index": "C", "libelle": "Il faut arrêter immédiatement la séance de sauts.", "correct": true} + ] + }, + { + "num": 380, + "libelle": "Au passage d’un cumulonimbus, on peut s’attendre :", + "answers": [ + {"index": "A", "libelle": "A un renforcement soudain du vent sans changement de direction.", "correct": false}, + {"index": "B", "libelle": "A un renforcement soudain du vent faisant suite à un changement de direction.", "correct": true} + ] + }, + { + "num": 381, + "libelle": "Sous un cumulonimbus, les précipitations sont souvent :", + "answers": [ + {"index": "A", "libelle": "Faibles.", "correct": false}, + {"index": "B", "libelle": "Inexistantes.", "correct": false}, + {"index": "C", "libelle": "Violentes.", "correct": true} + ] + } + ] + }, + { + "num": 12, + "name": "Sauts spéciaux", + "questions": [ + { + "num": 382, + "libelle": "Pour effectuer un saut de nuit, il faut au minimum :", + "answers": [ + {"index": "A", "libelle": "Un altimètre fluorescent ou éclairé.", "correct": false}, + {"index": "B", "libelle": "Une lampe et un altimètre fluorescent ou éclairé.", "correct": true}, + {"index": "C", "libelle": "Une lampe.", "correct": false} + ] + }, + { + "num": 383, + "libelle": "Pour effectuer un saut de nuit, en plus de l’autorisation du directeur technique, il faut au minimum :", + "answers": [ + {"index": "A", "libelle": "Etre titulaire du brevet C ou D et avoir effectué 10 sauts dans les 3 derniers mois.", "correct": false}, + {"index": "B", "libelle": "Etre titulaire du BPA et avoir effectué 50 sauts dans les 12 derniers mois.", "correct": true}, + {"index": "C", "libelle": "Etre titulaire du BPA.", "correct": false} + ] + }, + { + "num": 384, + "libelle": "Pour effectuer un saut à haute altitude, outre l’autorisation du directeur technique, il faut au minimum :", + "answers": [ + {"index": "A", "libelle": "Etre titulaire du brevet C ou D et avoir effectué 10 sauts dans les 3 derniers mois.", "correct": false}, + {"index": "B", "libelle": "Etre titulaire du BPA et avoir effectué 50 sauts dans les 12 derniers mois.", "correct": true}, + {"index": "C", "libelle": "Etre titulaire du BPA.", "correct": false} + ] + }, + { + "num": 385, + "libelle": "Lors d’un saut à 4500 mètres, si l’on doit attendre 15 minutes à la hauteur de largage :", + "answers": [ + {"index": "A", "libelle": "Cela ne pose pas de problèmes particuliers.", "correct": false}, + {"index": "B", "libelle": "Les problèmes physiologiques dus à l’altitude sont beaucoup plus conséquents que si l’on n’a pas d’attente.", "correct": true} + ] + }, + { + "num": 386, + "libelle": "Pour effectuer un saut à 5000 mètres d’altitude, l’oxygène à bord :", + "answers": [ + {"index": "A", "libelle": "Est obligatoire.", "correct": true}, + {"index": "B", "libelle": "N’est pas obligatoire.", "correct": false} + ] + }, + { + "num": 387, + "libelle": "Lors d’un saut à 6000 mètres, l’oxygène à bord :", + "answers": [ + {"index": "A", "libelle": "Est obligatoire parce que la réglementation l’impose.", "correct": false}, + {"index": "B", "libelle": "N’est pas nécessaire.", "correct": false}, + {"index": "C", "libelle": "Est physiologiquement indispensable et réglementairement obligatoire.", "correct": true} + ] + }, + { + "num": 388, + "libelle": "Lors d’un saut à 6000 mètres, la prise d’oxygène à partir de 4000 mètres est :", + "answers": [ + {"index": "A", "libelle": "Nécessaire uniquement pour ceux qui en ressentent le besoin.", "correct": false}, + {"index": "B", "libelle": "Obligatoire uniquement pour les personnes mineures.", "correct": false}, + {"index": "C", "libelle": "Indispensable quel que soit le niveau des pratiquants.", "correct": true} + ] + }, + { + "num": 389, + "libelle": "L’emport à bord d’un aéronef d’un système individuel d’oxygène est-il obligatoire pour effectuer des sauts à haute altitude ?", + "answers": [ + {"index": "A", "libelle": "Uniquement pour les sauts s’effectuant au dessus de 5000 mètres.", "correct": false}, + {"index": "B", "libelle": "Uniquement pour les sauts s’effectuant au dessus de 6000 mètres.", "correct": false}, + {"index": "C", "libelle": "Oui.", "correct": true} + ] + }, + { + "num": 390, + "libelle": "Le contrôle des équipements au sol et avant la sortie à 6000 mètres doit être particulièrement rigoureux pour :", + "answers": [ + {"index": "A", "libelle": "Minimiser les risques d’ouverture en altitude.", "correct": true}, + {"index": "B", "libelle": "Ne pas risquer une ouverture intempestive à bord et payer un saut non fait.", "correct": false}, + {"index": "C", "libelle": "Cela n’est pas nécessaire.", "correct": false} + ] + }, + { + "num": 391, + "libelle": "Le temps de chute (à plat) pour un départ à 6000 m est d’environ", + "answers": [ + {"index": "A", "libelle": "1 minute et 40 secondes. ", "correct": true}, + {"index": "B", "libelle": "1 minute et 10 secondes.", "correct": false}, + {"index": "C", "libelle": "2 minutes et 30 secondes.", "correct": false} + ] + }, + { + "num": 392, + "libelle": "Quelle sera la dérive en chute lors d’un saut à 6000 mètres avec un vent de 10 m/s ?", + "answers": [ + {"index": "A", "libelle": "Environ 1500 m.", "correct": false}, + {"index": "B", "libelle": "Environ 1000 m.", "correct": true}, + {"index": "C", "libelle": "Environ 400 m.", "correct": false} + ] + }, + { + "num": 393, + "libelle": "Quelle sera la dérive en chute lors d’un saut à 6000 mètres avec un vent de 40 kts ?", + "answers": [ + {"index": "A", "libelle": "Environ 1200 m.", "correct": false}, + {"index": "B", "libelle": "Environ 2000 m.", "correct": true}, + {"index": "C", "libelle": "Environ 500 m.", "correct": false} + ] + }, + { + "num": 394, + "libelle": "Pour sauter d’un ULM il faut au minimum :", + "answers": [ + {"index": "A", "libelle": "Le brevet C ou D.", "correct": true}, + {"index": "B", "libelle": "Le BPA.", "correct": false}, + {"index": "C", "libelle": "Le brevet B.", "correct": false} + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/routes/api/aeronefs.js b/routes/api/aeronefs.js new file mode 100644 index 0000000..07e68d6 --- /dev/null +++ b/routes/api/aeronefs.js @@ -0,0 +1,143 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'); + + +router.get('/allByImat', auth.required, function (req, res, next) { + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = queries.getAeronefsByImatQuery(user._id.toString()); + Promise.all([ + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + //Aeronef.count(query) + ]).then(function (results) { + let aeronefs = results[0]; + //let aeronefsCount = results[1]; + return res.json({ + aeronefs: aeronefs.map(function (data) { + return { aeronef: data._id.aeronef, imat: data._id.imat, count: data.count }; + }), + aeronefsCount: aeronefs.length + }); + /* + return res.json({ + aeronefs: aeronefs.map(function (aeronef) { + return aeronef.toJSONFor(user); + }), + aeronefsCount: aeronefsCount + }); + */ + }).catch(next); + }).catch(next); +}); + +router.get('/allByImatByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 50; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getAeronefsByImatByYearQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let aeronefs = result.map(function (data) { + return { aeronef: data._id.aeronef, imat: data._id.imat, year: data._id.year, count: data.count }; + }); + return res.json({ + aeronefs: aeronefs, + aeronefsCount: aeronefs.length + }); + }).catch(next); + }).catch(next); + /* + let limit = 50; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': user._id.toString() } ] + } + } + }, { + '$project': { + '_id': 0, + 'aeronef': 1, + 'imat': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'aeronef': '$aeronef', + 'imat': '$imat', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + let user = results[0]; + let aeronefs = results[1]; + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return res.json({ + aeronefs: aeronefs, + aeronefsCount: aeronefs.length + }); + }).catch(next); + */ + +}); + +module.exports = router; diff --git a/routes/api/applications.js b/routes/api/applications.js new file mode 100644 index 0000000..409f43e --- /dev/null +++ b/routes/api/applications.js @@ -0,0 +1,173 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Application = mongoose.model('Application'), + User = mongoose.model('User'); +const auth = require('../auth'), + mailer = require('@sendgrid/mail'); + +mailer.setApiKey(process.env.SENDGRID_API_KEY); + +// Preload application objects on routes with ':application' +router.param('application', function (req, res, next, slug) { + Application.findOne({ slug: slug }) + .populate('author') + .then(function (application) { + if (!application) { + return res.sendStatus(404); + } + req.application = application; + return next(); + }).catch(next); +}); + +/** + * return all applications + */ +router.get('/', auth.required, function (req, res, next) { + let query = {}; + let limit = 25; + let offset = 0; + + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + if (typeof req.query.apikey !== 'undefined') { + query.apikey = req.query.apikey; + } + if (typeof req.query.maskedkey !== 'undefined') { + query.maskedkey = req.query.maskedkey; + } + + Promise.all([ + req.query.author ? User.findOne({ username: req.query.author }) : null + ]).then(function (author) { + if (author[0]) { + query.author = author[0]._id; + } + return Promise.all([ + Application.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .sort({ createdAt: 'desc' }) + .populate('author') + .exec(), + Application.count(query).exec(), + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let applications = results[0]; + let applicationsCount = results[1]; + let user = results[2]; + + return res.json({ + applications: applications.map(function (application) { + return application.toJSONFor(user); + }), + applicationsCount: applicationsCount + }); + }); + }).catch(next); +}); + +/** + * save an application + */ +router.post('/', auth.required, function (req, res, next) { + Promise.all([ + User.findById(req.payload.id), + auth.generateAPIKey() + ]).then(function (results) { + let user = results[0]; + let keys = results[1]; + if (!user) { + return res.sendStatus(401).json({message: "Unauthorized - You are not allowed to access this resource."}); + } + let application = new Application(req.body.application); + application.author = user; + application.apikey = keys.encrypted; + application.maskedkey = keys.masked; + return application.save().then(function () { + let msg = { + to: user.email, + from: process.env.SENDGRID_FROM_MAIL, + subject: `Api-Key ${application.title}`, + text: `Votre Api-Key: ${keys.key}\nAttention, cette Api-Key doit être conservée et ne sera plus affichée.\n\n${application.title}\n${application.description}`, + html: `

${application.title}

+

+ Votre Api-Key: ${keys.key}
+ Attention, cette Api-Key doit être conservée et ne sera plus affichée. +

+
+

${application.description}

` + }; + mailer.send(msg).then(() => { + return res.json({ application: application.toJSONFor(user) }); + }) + .catch(err => { + res.sendStatus(500).json({message: "A SendGrid error occured while sending an email", err: err}); + }); + }); + }).catch(next); +}); + +/** + * return an application + */ +router.get('/:application', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + req.application.populate('author') + ]).then(function (results) { + let user = results[0]; + return res.json({ application: req.application.toJSONFor(user) }); + }).catch(next); +}); + +/** + * update an application + */ +router.put('/:application', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (req.application.author._id.toString() === req.payload.id.toString()) { + if (typeof req.body.application.title !== 'undefined') { + req.application.title = req.body.application.title; + } + if (typeof req.body.application.description !== 'undefined') { + req.application.description = req.body.application.description; + } + if (typeof req.body.application.apikey !== 'undefined') { + req.application.apikey = req.body.application.apikey; + } + if (typeof req.body.application.maskedkey !== 'undefined') { + req.application.maskedkey = req.body.application.maskedkey; + } + req.application.save().then(function (application) { + return res.json({ application: application.toJSONFor(user) }); + }).catch(next); + } else { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + }); +}); + +/** + * delete an application + */ +router.delete('/:application', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role == 'Admin' || req.application.author._id.toString() === req.payload.id.toString()) { + return req.application.remove().then(function () { + return res.json({ deleted: true }); + }); + } else { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + }).catch(next); +}); + +module.exports = router; diff --git a/routes/api/articles.js b/routes/api/articles.js new file mode 100755 index 0000000..c9c0d46 --- /dev/null +++ b/routes/api/articles.js @@ -0,0 +1,283 @@ +var router = require('express').Router(); +var mongoose = require('mongoose'); +var Article = mongoose.model('Article'); +var Comment = mongoose.model('Comment'); +var User = mongoose.model('User'); +var auth = require('../auth'); + +// Preload article objects on routes with ':article' +router.param('article', function (req, res, next, slug) { + Article.findOne({ slug: slug }) + .populate('author') + .then(function (article) { + if (!article) { + return res.sendStatus(404); + } + req.article = article; + return next(); + }).catch(next); +}); + +router.param('comment', function (req, res, next, id) { + Comment.findById(id).then(function (comment) { + if (!comment) { + return res.sendStatus(404); + } + req.comment = comment; + return next(); + }).catch(next); +}); + +router.get('/', auth.optional, function (req, res, next) { + var query = {}; + var limit = 20; + var offset = 0; + + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + if (typeof req.query.membre !== 'undefined') { + query.membre = req.query.membre; + } + if (typeof req.query.tag !== 'undefined') { + query.tagList = { "$in": [req.query.tag] }; + } + + Promise.all([ + req.query.author ? User.findOne({ username: req.query.author }) : null, + req.query.favorited ? User.findOne({ username: req.query.favorited }) : null + ]).then(function (results) { + var author = results[0]; + var favoriter = results[1]; + + if (author) { + query.author = author._id; + } + + if (favoriter) { + query._id = { $in: favoriter.favorites }; + } else if (req.query.favorited) { + query._id = { $in: [] }; + } + + return Promise.all([ + Article.find(query) + .limit(Number(limit)) + .skip(Number(offset)) + .sort({ createdAt: 'desc' }) + .populate('author') + .exec(), + Article.count(query).exec(), + req.payload ? User.findById(req.payload.id) : null, + ]).then(function (results) { + var articles = results[0]; + var articlesCount = results[1]; + var user = results[2]; + + return res.json({ + articles: articles.map(function (article) { + return article.toJSONFor(user); + }), + articlesCount: articlesCount + }); + }); + }).catch(next); +}); + +router.get('/feed', auth.required, function (req, res, next) { + var limit = 20; + var offset = 0; + + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.sendStatus(401); + } + Promise.all([ + Article.find({ author: { $in: user.following } }) + .limit(Number(limit)) + .skip(Number(offset)) + .populate('author') + .exec(), + Article.count({ author: { $in: user.following } }) + ]).then(function (results) { + var articles = results[0]; + var articlesCount = results[1]; + return res.json({ + articles: articles.map(function (article) { + return article.toJSONFor(user); + }), + articlesCount: articlesCount + }); + }).catch(next); + }); +}); + +router.post('/', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.sendStatus(401); + } + var article = new Article(req.body.article); + article.author = user; + return article.save().then(function () { + return res.json({ article: article.toJSONFor(user) }); + }); + }).catch(next); +}); + +// return a article +router.get('/:article', auth.optional, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + req.article.populate('author') + ]).then(function (results) { + var user = results[0]; + return res.json({ article: req.article.toJSONFor(user) }); + }).catch(next); +}); + +// update article // 6440016ef84d788c1b352018 +router.put('/:article', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (req.article.author._id.toString() === req.payload.id.toString()) { + if (typeof req.body.article.title !== 'undefined') { + req.article.title = req.body.article.title; + } + if (typeof req.body.article.description !== 'undefined') { + req.article.description = req.body.article.description; + } + if (typeof req.body.article.body !== 'undefined') { + req.article.body = req.body.article.body; + } + if (typeof req.body.article.tagList !== 'undefined') { + req.article.tagList = req.body.article.tagList + } + if (typeof req.body.article.membre !== 'undefined') { + req.article.membre = req.body.article.membre; + } + req.article.save().then(function (article) { + return res.json({ article: article.toJSONFor(user) }); + }).catch(next); + } else { + return res.sendStatus(403); + } + }); +}); + +// delete article +router.delete('/:article', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.sendStatus(401); + } + if (req.article.author._id.toString() === req.payload.id.toString()) { + return req.article.remove().then(function () { + return res.sendStatus(204); + }); + } else { + return res.sendStatus(403); + } + }).catch(next); +}); + +// Favorite an article +router.post('/:article/favorite', auth.required, function (req, res, next) { + var articleId = req.article._id; + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.sendStatus(401); + } + return user.favorite(articleId).then(function () { + return req.article.updateFavoriteCount().then(function (article) { + return res.json({ article: article.toJSONFor(user) }); + }); + }); + }).catch(next); +}); + +// Unfavorite an article +router.delete('/:article/favorite', auth.required, function (req, res, next) { + var articleId = req.article._id; + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.sendStatus(401); + } + + return user.unfavorite(articleId).then(function () { + return req.article.updateFavoriteCount().then(function (article) { + return res.json({ article: article.toJSONFor(user) }); + }); + }); + }).catch(next); +}); + +// return an article's comments +router.get('/:article/comments', auth.optional, function (req, res, next) { + Promise.resolve(req.payload ? User.findById(req.payload.id) : null).then(function (user) { + return req.article.populate({ + path: 'comments', + populate: { + path: 'author' + }, + options: { + sort: { + createdAt: 'desc' + } + } + }).then(function (article) { + return res.json({ + comments: req.article.comments.map(function (comment) { + return comment.toJSONFor(user); + }) + }); + }); + }).catch(next); +}); + +// create a new comment +router.post('/:article/comments', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.sendStatus(401); + } + var comment = new Comment(req.body.comment); + comment.article = req.article; + comment.author = user; + + return comment.save().then(function () { + req.article.comments.push(comment); + + return req.article.save().then(function (article) { + res.json({ comment: comment.toJSONFor(user) }); + }); + }); + }).catch(next); +}); + +router.delete('/:article/comments/:comment', auth.required, function (req, res, next) { + if (req.comment.author.toString() === req.payload.id.toString()) { + req.article.comments.remove(req.comment._id); + req.article.save() + .then(Comment.find({ _id: req.comment._id }).remove().exec()) + .then(function () { + res.sendStatus(204); + }); + } else { + res.sendStatus(403); + } +}); + +module.exports = router; diff --git a/routes/api/canopies.js b/routes/api/canopies.js new file mode 100644 index 0000000..0cff862 --- /dev/null +++ b/routes/api/canopies.js @@ -0,0 +1,166 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'); + +router.get('/', auth.required, function (req, res, next) { + let query = {}; + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + if (typeof req.query.slug !== 'undefined') { + query.slug = req.query.slug; + } + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role == 'Admin') { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Jump.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result; + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySize', auth.required, function (req, res, next) { + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = queries.getCanopiesBySizeQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, count: data.count }; + }); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySizeByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getCanopiesBySizeByYearQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, year: data._id.year, count: data.count }; + }); + //console.log(dropzones); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySizeByModel', auth.required, function (req, res, next) { + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = queries.getCanopiesBySizeByModelQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, voile: data._id.voile, count: data.count }; + }); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allBySizeByModelByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getCanopiesBySizeByModelByYearQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let canopies = result.map(function (data) { + return { taille: data._id.taille, voile: data._id.voile, year: data._id.year, count: data.count }; + }); + return res.json({ + canopies: canopies, + canopiesCount: canopies.length + }); + }).catch(next); + }).catch(next); +}); + +module.exports = router; diff --git a/routes/api/comments.js b/routes/api/comments.js new file mode 100644 index 0000000..04430ff --- /dev/null +++ b/routes/api/comments.js @@ -0,0 +1,63 @@ +var router = require('express').Router(); +var mongoose = require('mongoose'); +var Comment = mongoose.model('Comment'); +var User = mongoose.model('User'); +var auth = require('../auth'); + +// return an article's comments +router.get('/:article/comments', auth.optional, function (req, res, next) { + Promise.resolve(req.payload ? User.findById(req.payload.id) : null).then(function (user) { + return req.article.populate({ + path: 'comments', + populate: { + path: 'author' + }, + options: { + sort: { + createdAt: 'desc' + } + } + }).then(function (article) { + return res.json({ + comments: req.article.comments.map(function (comment) { + return comment.toJSONFor(user); + }) + }); + }); + }).catch(next); +}); + +// create a new comment +router.post('/:article/comments', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.sendStatus(401); + } + var comment = new Comment(req.body.comment); + comment.article = req.article; + comment.author = user; + + return comment.save().then(function () { + req.article.comments.push(comment); + + return req.article.save().then(function (article) { + res.json({ comment: comment.toJSONFor(user) }); + }); + }); + }).catch(next); +}); + +router.delete('/:article/comments/:comment', auth.required, function (req, res, next) { + if (req.comment.author.toString() === req.payload.id.toString()) { + req.article.comments.remove(req.comment._id); + req.article.save() + .then(Comment.find({ _id: req.comment._id }).remove().exec()) + .then(function () { + res.sendStatus(204); + }); + } else { + res.sendStatus(403); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/api/dropzones.js b/routes/api/dropzones.js new file mode 100644 index 0000000..c51bebc --- /dev/null +++ b/routes/api/dropzones.js @@ -0,0 +1,69 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'); + + +router.get('/allByOaci', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getDropZonesByOaciQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let dropzones = result.map(function (data) { + return { lieu: data._id.lieu, oaci: data._id.oaci, count: data.count }; + }); + return res.json({ + dropzones: dropzones, + dropzonesCount: dropzones.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByOaciByYear', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getDropZonesByOaciByYearQuery(user._id.toString()); + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let dropzones = result.map(function (data) { + return { lieu: data._id.lieu, oaci: data._id.oaci, year: data._id.year, count: data.count }; + }); + return res.json({ + dropzones: dropzones, + dropzonesCount: dropzones.length + }); + }).catch(next); + }).catch(next); +}); + +module.exports = router; diff --git a/routes/api/index.js b/routes/api/index.js new file mode 100644 index 0000000..6a52f7f --- /dev/null +++ b/routes/api/index.js @@ -0,0 +1,28 @@ +var router = require('express').Router(); + +router.use('/', require('./users')); +router.use('/articles', require('./articles')); +router.use('/comments', require('./comments')); +router.use('/tags', require('./tags')); +router.use('/profiles', require('./profiles')); +router.use('/applications', require('./applications')); +router.use('/aeronefs', require('./aeronefs')); +router.use('/canopies', require('./canopies')); +router.use('/dropzones', require('./dropzones')); +router.use('/jumps', require('./jumps')); +router.use('/pages', require('./pages')); +router.use('/qcm', require('./qcm')); + +router.use(function (err, req, res, next) { + if (err.name === 'ValidationError') { + return res.status(422).json({ + errors: Object.keys(err.errors).reduce(function (errors, key) { + errors[key] = err.errors[key].message; + return errors; + }, {}) + }); + } + return next(err); +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/api/jumps.js b/routes/api/jumps.js new file mode 100644 index 0000000..ee58e88 --- /dev/null +++ b/routes/api/jumps.js @@ -0,0 +1,621 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + JumpFile = mongoose.model('JumpFile'), + User = mongoose.model('User'), + X2DataLog = mongoose.model('X2DataLog'); +const auth = require('../auth'), + chalk = require('chalk'), + queries = require('../queries'), + utils = require('../utils'); + +// Preload jump objects on routes with ':jump' +router.param('jump', function (req, res, next, slug) { + Jump.findOne({ slug: slug }) + .populate('author') + .populate('files') + .populate('x2data') + .then(function (jump) { + if (!jump) { + return res.sendStatus(404); + } + req.jump = jump; + return next(); + }).catch(next); +}); + +/** + * return all jumps + */ +router.get('/', auth.required, function (req, res, next) { + let query = {}; + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + if (typeof req.query.title !== 'undefined') { + const rgx = new RegExp(`.*${req.query.title}.*`); + query = { + $or: [ + { title: { $regex: rgx, $options: "i" } }, + { slug: { $regex: rgx, $options: "i" } }, + ], + } + } + if (typeof req.query.numeroRangeStart !== 'undefined' && typeof req.query.numeroRangeEnd !== 'undefined') { + query.numero = { + $gte: req.query.numeroRangeStart, + $lte: req.query.numeroRangeEnd + }; + } + if (typeof req.query.tailleRangeStart !== 'undefined' && typeof req.query.tailleRangeEnd !== 'undefined') { + query.taille = { + $gte: req.query.tailleRangeStart, + $lte: req.query.tailleRangeEnd + }; + } + if (typeof req.query.participantsRangeStart !== 'undefined' && typeof req.query.participantsRangeEnd !== 'undefined') { + query.participants = { + $gte: req.query.participantsRangeStart, + $lte: req.query.participantsRangeEnd + }; + } + if (typeof req.query.hauteurRangeStart !== 'undefined' && typeof req.query.hauteurRangeEnd !== 'undefined') { + query.hauteur = { + $gte: req.query.hauteurRangeStart, + $lte: req.query.hauteurRangeEnd + }; + } + if (typeof req.query.yearRangeStart !== 'undefined' && typeof req.query.yearRangeEnd !== 'undefined') { + query.date = { + $gte: new Date(`${req.query.yearRangeStart}-01-01 00:00:00`), + $lte: new Date(`${req.query.yearRangeEnd}-12-31 23:59:59`) + }; + } + if (typeof req.query.dateRangeStart !== 'undefined' && typeof req.query.dateRangeEnd !== 'undefined') { + query.date = { + $gte: new Date(`${req.query.dateRangeStart} 00:00:00`), + $lte: new Date(`${req.query.dateRangeEnd} 23:59:59`) + }; + } + + Promise.all([ + req.query.author ? User.findOne({ username: req.query.author }) : null, + req.query.favorited ? User.findOne({ username: req.query.favorited }) : null + ]).then(function (users) { + let author = users[0]; + + if (author) { + query.author = author._id; + } + + Promise.all([ + Jump.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.count(query).exec(), + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let jumps = results[0]; + let jumpsCount = results[1]; + let user = results[2]; + /* + Promise.all( + jumps.map(jump => { + if (jump.files[0] !== undefined && jump.files[0].type !== 'kml') { + console.log( chalk.green(`Fichier ${jump.files[0].type}`)) + //console.log( chalk.green(`Suppression du fichier ${jump.files[2]._id}`)) + //return jump.removeFile(jump.files[2]._id); + } + return; + }) + ).then(function () { + return res.json({ + jumps: jumps.map(function (jump) { + return jump.toJSONFor(user); + }), + jumpsCount: jumpsCount + }); + }); + */ + return res.json({ + jumps: jumps.map(function (jump) { + return jump.toJSONFor(user); + }), + jumpsCount: jumpsCount + }); + }); + }).catch(next); +}); + +router.get('/allByCategorie', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getJumpsByCategoryQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let jumps = result.map(function (data) { + return { categorie: data._id.categorie, count: data.count }; + }); + return res.json({ + jumps: jumps, + jumpsCount: jumps.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByDate', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getJumpsByDateQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let jumps = result.map(function (data) { + return { year: data._id.year, month: data._id.month, count: data.count }; + }); + return res.json({ + jumps: jumps, + jumpsCount: jumps.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByDay', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = {}; + let limit = 50; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + if (typeof req.query.dateRangeStart !== 'undefined' && typeof req.query.dateRangeEnd !== 'undefined') { + query = queries.getJumpsByDayQuery( + user._id.toString(), + req.query.dateRangeStart, + req.query.dateRangeEnd + ); + } else { + query = queries.getJumpsByDayQuery(user._id.toString()); + } + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let days = result.map(function (data) { + return { jumps: data.jumps, count: data.count }; + }); + return res.json({ + days: days, + daysCount: days.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/allByModule', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + let query = queries.getJumpsByModuleQuery(user._id.toString()); + + Jump.aggregate(query) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + .then(function (result) { + let jumps = result.map(function (data) { + return { categorie: data._id.categorie, module: data._id.module, count: data.count }; + }); + return res.json({ + jumps: jumps, + jumpsCount: jumps.length + }); + }).catch(next); + }).catch(next); +}); + +/** + * return a jump from SkydiverId API + */ +router.get('/allFromSkydiverIdApi', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + utils.fetchSkydiverIdApi('jumps', req.query).then(result => { + if (result.errors === undefined) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception des sauts SkydiverId`)); + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Une erreur ${result.errors.code} '${result.errors.type}' est survenue lors de la réception des sauts SkydiverId : ${result.errors.name} ${result.errors.message}`)); + } + return res.json({ + jumps: result, + jumpsCount: result.items.length + }); + }).catch(next); + }).catch(next); +}); + +router.get('/feed', auth.required, function (req, res, next) { + let limit = 25; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let query = { author: { $in: user.following } }; + Promise.all([ + Jump.find(query) + .skip(Number(offset)) + .limit(Number(limit)) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.count(query) + ]).then(function (results) { + let jumps = results[0]; + let jumpsCount = results[1]; + return res.json({ + jumps: jumps.map(function (jump) { + return jump.toJSONFor(user); + }), + jumpsCount: jumpsCount + }); + }).catch(next); + }); +}); + +/** + * return last jump + */ +router.get('/last', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + /*Jump.findOne({ slug: slug }) + .populate('author') + .then(function (jump) { + if (!jump) { + return res.sendStatus(404); + } + req.jump = jump; + return next(); + }).catch(next);*/ + Jump.find({}) + .limit(1) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec() + .then(function (jumps) { + if (!jumps) { + return res.sendStatus(404); + } + req.lastjump = jumps[0]; + if (req.lastjump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + return res.json({ jump: req.lastjump.toJSONFor(user) }); + }).catch(next); + }).catch(next); +}); + +/** + * return a jump + */ +router.get('/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Promise.all([ + Jump.findOne({numero: (req.jump.numero - 1)}).exec(), + Jump.findOne({numero: (req.jump.numero + 1)}).exec(), + ]).then(function (results) { + return res.json({ + jump: req.jump.toJSONFor(user), + prevJump: results[0], + nextJump: results[1] + }); + }).catch(next); + }).catch(next); +}); + +/** + * save a jump + */ +router.post('/', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + //let numero = (results[1][0].numero + 1); + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let jump = new Jump(req.body.jump); + jump.author = user; + //jump.numero = numero; + return jump.save().then(function () { + return res.json({ jump: jump.toJSONFor(user) }); + }); + }).catch(next); +}); + +/** + * save a jump file + */ +router.post('/data/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + /* + console.log(req.jump.files); + return res.json({ jump: req.jump.toJSONFor(user) }); + */ + Object.assign(req.body.file, {_id: new mongoose.Types.ObjectId()}); + let file = new JumpFile(req.body.file); + let files = req.jump.files ? req.jump.files : []; + file.author = user; + files.push(file); + return file.save().then(function () { + Object.assign(req.body.data, {_id: new mongoose.Types.ObjectId()}); + let x2data = new X2DataLog(req.body.data); + x2data.author = user; + return x2data.save().then(function () { + req.jump.files = files; + req.jump.x2data = x2data; + Jump.updateOne({_id: req.jump._id}, {files: files, x2data: x2data._id}).then(function () { + return res.json({ jump: req.jump.toJSONFor(user) }); + }).catch(next); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +/** + * save a jump file + */ +router.post('/file/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Object.assign(req.body.file, {_id: new mongoose.Types.ObjectId()}); + let file = new JumpFile(req.body.file); + let files = req.jump.files ? req.jump.files : []; + file.author = user; + files.push(file); + return file.save().then(function () { + Jump.updateOne({_id: req.jump._id}, {files: files}).then(function () { + return res.json({ file: file.toJSONForJump() }); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +/** + * save a jump file + */ +router.post('/kml/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + Object.assign(req.body.file, { + _id: new mongoose.Types.ObjectId(), + name: `${req.jump.x2data.name}.kml`, + path: `/Volumes/Storage/Skydive/X2_Kmls/${req.jump.date.getFullYear()}/`, + type: 'kml' + }); + let file = new JumpFile(req.body.file); + let files = req.jump.files ? req.jump.files : []; + file.author = user; + files.push(file); + //console.log(chalk.yellow(`jump/${req.jump.x2data.id}/kml`)); + return res.json({ file: file.toJSONForJump() }); + /* + utils.fetchSkydiverIdApi(`jump/${req.jump.x2data.id}/kml`, {}).then(result => { + if (result.errors === undefined) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception de l'url du fichier kml SkydiverId`)); + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Une erreur ${result.errors.code} '${result.errors.type}' est survenue lors de la réception de l'url du fichier kml SkydiverId : ${result.errors.name} ${result.errors.message}`)); + } + if (result.url !== undefined) { + console.log(chalk.green(result.url)); + } else { + console.log(chalk.red('result.url is undefined')); + } + return res.json({ file: file.toJSONForJump() }); + }).catch(next); + + + + return file.save().then(function () { + Jump.updateOne({_id: req.jump._id}, {files: files}).then(function () { + utils.fetchSkydiverIdApi(`jump/${req.jump.x2data.id}/kml`, {}).then(result => { + if (result.errors === undefined) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception de l'url du fichier kml SkydiverId`)); + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Une erreur ${result.errors.code} '${result.errors.type}' est survenue lors de la réception de l'url du fichier kml SkydiverId : ${result.errors.name} ${result.errors.message}`)); + } + if (result.url !== undefined) { + console.log(result.url); + } else { + console.log('result.url is undefined'); + } + return res.json({ file: file.toJSONForJump() }); + }).catch(next); + }).catch(next); + }).catch(next); + */ + }).catch(next); +}); + +/** + * update a jump + */ +router.put('/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() !== req.payload.id.toString()) { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + if (typeof req.body.jump.date !== 'undefined') { + req.jump.date = req.body.jump.date; + } + if (typeof req.body.jump.numero !== 'undefined') { + req.jump.numero = req.body.jump.numero; + } + if (typeof req.body.jump.lieu !== 'undefined') { + req.jump.lieu = req.body.jump.lieu; + } + if (typeof req.body.jump.oaci !== 'undefined') { + req.jump.oaci = req.body.jump.oaci; + } + if (typeof req.body.jump.aeronef !== 'undefined') { + req.jump.aeronef = req.body.jump.aeronef; + } + if (typeof req.body.jump.imat !== 'undefined') { + req.jump.imat = req.body.jump.imat; + } + if (typeof req.body.jump.hauteur !== 'undefined') { + req.jump.hauteur = req.body.jump.hauteur; + } + if (typeof req.body.jump.voile !== 'undefined') { + req.jump.voile = req.body.jump.voile; + } + if (typeof req.body.jump.taille !== 'undefined') { + req.jump.taille = req.body.jump.taille; + } + if (typeof req.body.jump.categorie !== 'undefined') { + req.jump.categorie = req.body.jump.categorie; + } + if (typeof req.body.jump.module !== 'undefined') { + req.jump.module = req.body.jump.module; + } + if (typeof req.body.jump.participants !== 'undefined') { + req.jump.participants = req.body.jump.participants; + } + if (typeof req.body.jump.sautants !== 'undefined') { + req.jump.sautants = req.body.jump.sautants; + } + if (typeof req.body.jump.programme !== 'undefined') { + req.jump.programme = req.body.jump.programme; + } + if (typeof req.body.jump.accessoires !== 'undefined') { + req.jump.accessoires = req.body.jump.accessoires; + } + if (typeof req.body.jump.zone !== 'undefined') { + req.jump.zone = req.body.jump.zone; + } + if (typeof req.body.jump.dossier !== 'undefined') { + req.jump.dossier = req.body.jump.dossier; + } + if (typeof req.body.jump.video !== 'undefined') { + req.jump.video = req.body.jump.video; + } + + return req.jump.save().then(function (jump) { + return res.json({ jump: jump.toJSONFor(user) }); + }); + }).catch(next); +}); + +/** + * delete a jump + */ +router.delete('/:jump', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (req.jump.author._id.toString() === req.payload.id.toString()) { + return req.jump.remove().then(function () { + return res.json({ deleted: true }); + }); + } else { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + }).catch(next); +}); + +module.exports = router; diff --git a/routes/api/pages.js b/routes/api/pages.js new file mode 100644 index 0000000..0d21ab9 --- /dev/null +++ b/routes/api/pages.js @@ -0,0 +1,285 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Jump = mongoose.model('Jump'), + User = mongoose.model('User'); +const auth = require('../auth'), + queries = require('../queries'), + utils = require('../utils'); + +router.get('/aeronefs', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getAeronefsByImatQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getAeronefsByImatByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let aeronefsByImat = results[1].map(function (data) { + return { aeronef: data._id.aeronef, imat: data._id.imat, count: data.count }; + }); + let aeronefsByImatByYear = results[2].map(function (data) { + return { + aeronef: data._id.aeronef, + imat: data._id.imat, + year: data._id.year, + count: data.count + }; + }); + return res.json({ + aeronefsByImat: aeronefsByImat, + aeronefsByImatByYear: aeronefsByImatByYear, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +router.get('/canopies', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getCanopiesBySizeQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getCanopiesBySizeByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getCanopiesBySizeByModelQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getCanopiesBySizeByModelByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let canopiesBySize = results[1].map(function (data) { + return { taille: data._id.taille, count: data.count }; + }); + let canopiesBySizeByYear = results[2].map(function (data) { + return { + taille: data._id.taille, + year: data._id.year, + count: data.count + }; + }); + let canopiesBySizeByModel = results[3].map(function (data) { + return { + taille: data._id.taille, + voile: data._id.voile, + count: data.count + }; + }); + let canopiesBySizeByModelByYear = results[4].map(function (data) { + return { + taille: data._id.taille, + voile: data._id.voile, + year: data._id.year, + count: data.count + }; + }); + return res.json({ + canopiesBySize: canopiesBySize, + canopiesBySizeByYear: canopiesBySizeByYear, + canopiesBySizeByModel: canopiesBySizeByModel, + canopiesBySizeByModelByYear: canopiesBySizeByModelByYear, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +router.get('/dropzones', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getDropZonesByOaciQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getDropZonesByOaciByYearQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let dropZonesByOaci = results[1].map(function (data) { + return { lieu: data._id.lieu, oaci: data._id.oaci, count: data.count }; + }); + let dropZonesByOaciByYear = results[2].map(function (data) { + return { + lieu: data._id.lieu, + oaci: data._id.oaci, + year: data._id.year, + count: data.count + }; + }); + return res.json({ + dropZonesByOaci: dropZonesByOaci, + dropZonesByOaciByYear: dropZonesByOaciByYear, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +router.get('/jumps', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + let limit = 120; + let offset = 0; + if (typeof req.query.limit !== 'undefined') { + limit = req.query.limit; + } + if (typeof req.query.offset !== 'undefined') { + offset = req.query.offset; + } + Promise.all([ + Jump.find({}) + .limit(1) + .skip(0) + .sort({ numero: 'desc' }) + .populate('author') + .populate('files') + .populate('x2data') + .exec(), + Jump.aggregate(queries.getJumpByYearsQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByCategoryQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByModuleQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByDateQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec(), + Jump.aggregate(queries.getJumpsByModuleByDateQuery(user._id.toString())) + .skip(Number(offset)) + .limit(Number(limit)) + .exec() + //utils.fetchSkydiverIdApi('jumps') + ]).then(function (results) { + if (results[0].length) { + let lastjump = results[0][0].toJSONFor(user); + let jumpsByYears = results[1].map(function (data) { + return { year: data._id.year, count: data.count }; + }); + let jumpsByCategory = results[2].map(function (data) { + return { categorie: data._id.categorie, count: data.count }; + }); + let jumpsByModule = results[3].map(function (data) { + return { categorie: data._id.categorie, module: data._id.module, count: data.count }; + }); + let jumpsByDate = results[4].map(function (data) { + return { year: data._id.year, month: data._id.month, count: data.count }; + }); + let jumpsByDateByModule = results[5].map(function (data) { + return { + categorie: data._id.categorie, + module: data._id.module, + year: data._id.year, + month: data._id.month, + count: data.count + }; + }); + //let jumpsFromSkydiverIdApi = results[6]; + return res.json({ + jumpsByCategory: jumpsByCategory, + jumpsByDate: jumpsByDate, + jumpsByDateByModule: jumpsByDateByModule, + jumpsByModule: jumpsByModule, + jumpsByYears: jumpsByYears, + //jumpsFromSkydiverIdApi: jumpsFromSkydiverIdApi, + lastjump: lastjump + }); + } else { + return res.status(422).json({ errors: { lastjump: "Aucun saut enregistré pour le moment" } }); + } + }).catch(next); + }).catch(next); +}); + +module.exports = router; diff --git a/routes/api/profiles.js b/routes/api/profiles.js new file mode 100644 index 0000000..3fb26be --- /dev/null +++ b/routes/api/profiles.js @@ -0,0 +1,57 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + User = mongoose.model('User'); +const auth = require('../auth'); + +// Preload user profile on routes with ':username' +router.param('username', function (req, res, next, username) { + User.findOne({ username: username }).then(function (user) { + if (!user) { + return res.sendStatus(404); + } + req.profile = user; + + return next(); + }).catch(next); +}); + +router.get('/:username', auth.optional, function (req, res) { + if (req.payload) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.json({ profile: req.profile.toProfileJSONFor(false) }); + } + return res.json({ profile: req.profile.toProfileJSONFor(user) }); + }); + } else { + return res.json({ profile: req.profile.toProfileJSONFor(false) }); + } +}); + +router.post('/:username/follow', auth.required, function (req, res, next) { + let profileId = req.profile._id; + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return user.follow(profileId).then(function () { + return res.json({ profile: req.profile.toProfileJSONFor(user) }); + }); + }).catch(next); +}); + +router.delete('/:username/follow', auth.required, function (req, res, next) { + let profileId = req.profile._id; + + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return user.unfollow(profileId).then(function () { + return res.json({ profile: req.profile.toProfileJSONFor(user) }); + }); + }).catch(next); +}); + +module.exports = router; diff --git a/routes/api/qcm.js b/routes/api/qcm.js new file mode 100644 index 0000000..3c2dad6 --- /dev/null +++ b/routes/api/qcm.js @@ -0,0 +1,157 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + Qcm = mongoose.model('Qcm'), + QcmCategory = mongoose.model('QcmCategory'), + QcmQuestion = mongoose.model('QcmQuestion'), + QcmChoice = mongoose.model('QcmChoice'), + User = mongoose.model('User'); +const auth = require('../auth'); + +// Preload qcm objects on routes with ':type' +router.param('type', function (req, res, next, type) { + Qcm.findOne({ name: type }) + .populate('categories') + .then(qcm => { + if (!qcm) { + return res.status(404).json({ errors: { "Not Found": "Le QCM est introuvable ou inexistant." } }); + } + req.qcm = qcm; + Promise.all( + req.qcm.categories.map(category => { + return category.populate('questions').then(() => { + return Promise.all( + category.questions.map(question => question.populate('choices')) + ).then(() => { + return category; + }).catch(next); + }); + }) + ).then(() => { + return next(); + }).catch(next); + }).catch(next); +}); + +/** + * return all qcm + */ +router.get('/', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let user = results[0]; + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return res.json({ qcm: [] }); + }).catch(next); +}); + +/** + * return a qcm + */ +router.get('/type/:type', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null + ]).then(function (results) { + let user = results[0]; + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return res.json({ qcm: req.qcm.toJSONFor() }); + }).catch(next); +}); + +/** + * save an array of qcm question choice + */ +router.post('/choices/', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + QcmQuestion + .findOne({num: req.body.question.num}) + .populate('choices') + .exec() + ]).then(async function (results) { + const user = results[0]; + //let numero = (results[1][0].numero + 1); + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role !== 'Admin') { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + const question = results[1]; + if (!question) { + return res.status(422).json({ errors: { question: "question introuvable" } }); + } + let choices = []; + Promise.all( + req.body.question.choices.map(data => { + const choiceId = new mongoose.Types.ObjectId(); + const choice = new QcmChoice({ _id: choiceId, index: data.index, libelle: data.libelle, correct: data.correct}); + choices.push(choiceId); + return choice.save(); + }) + ).then(function () { + question.choices = [...choices]; + question.save().then(function () { + QcmQuestion + .findOne({num: req.body.question.num}) + .populate('choices') + .exec() + .then(function (question) { + return res.json({ question: question.toJSONFor() }); + }).catch(next); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +/** + * save an array of qcm category questions + */ +router.post('/questions/', auth.required, function (req, res, next) { + Promise.all([ + req.payload ? User.findById(req.payload.id) : null, + QcmCategory + .findOne({num: req.body.category.num}) + .populate('questions') + .exec() + ]).then(async function (results) { + const user = results[0]; + //let numero = (results[1][0].numero + 1); + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (user.role !== 'Admin') { + return res.status(403).json({ errors: { "Forbidden": "Vous ne disposez pas des autorisations suffisantes" } }); + } + const category = results[1]; + if (!category) { + return res.status(422).json({ errors: { category: "catégorie introuvable" } }); + } + let questions = []; + Promise.all( + req.body.category.questions.map(data => { + const questionId = new mongoose.Types.ObjectId(); + const question = new QcmQuestion({ _id: questionId, num: data.num, libelle: data.libelle, choices: []}); + questions.push(questionId); + return question.save(); + }) + ).then(function () { + category.questions = [...questions]; + category.save().then(function () { + QcmCategory + .findOne({num: req.body.category.num}) + .populate('questions') + .exec() + .then(function (category) { + return res.json({ category: category.toJSONFor() }); + }).catch(next); + }).catch(next); + }).catch(next); + }).catch(next); +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/api/tags.js b/routes/api/tags.js new file mode 100755 index 0000000..8f9c4a6 --- /dev/null +++ b/routes/api/tags.js @@ -0,0 +1,12 @@ +var router = require('express').Router(); +var mongoose = require('mongoose'); +var Article = mongoose.model('Article'); + +// return a list of tags +router.get('/', function(req, res, next) { + Article.find().distinct('tagList').then( tags => { + return res.json({tags: tags}); + }).catch(next); +}); + +module.exports = router; diff --git a/routes/api/users.js b/routes/api/users.js new file mode 100644 index 0000000..f904be4 --- /dev/null +++ b/routes/api/users.js @@ -0,0 +1,126 @@ +var router = require('express').Router(), + mongoose = require('mongoose'), + User = mongoose.model('User'); +const passport = require('passport'), + auth = require('../auth'); + +router.get('/user', auth.required, function (req, res, next) { + //console.log(req.payload); + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + return res.json({ user: user.toAuthJSON() }); + }).catch(next); +}); + +router.put('/user', auth.required, function (req, res, next) { + User.findById(req.payload.id).then(function (user) { + if (!user) { + return res.status(401).json({ errors: { "Unauthorized": "autentification requise" } }); + } + if (typeof req.body.user.username !== 'undefined') { + user.username = req.body.user.username; + } + if (typeof req.body.user.email !== 'undefined') { + user.email = req.body.user.email; + } + if (typeof req.body.user.firstname !== 'undefined') { + user.firstname = req.body.user.firstname; + } + if (typeof req.body.user.lastname !== 'undefined') { + user.lastname = req.body.user.lastname; + } + if (typeof req.body.user.phone !== 'undefined') { + user.phone = req.body.user.phone; + } + if (typeof req.body.user.licence !== 'undefined') { + user.licence = req.body.user.licence; + } + if (typeof req.body.user.poids !== 'undefined') { + user.poids = req.body.user.poids; + } + if (typeof req.body.user.image !== 'undefined') { + user.image = req.body.user.image; + } + if (typeof req.body.user.bg_image !== 'undefined') { + user.bg_image = req.body.user.bg_image; + } + if (typeof req.body.user.password !== 'undefined') { + user.setPassword(req.body.user.password); + } + if (typeof req.body.user.role !== 'undefined') { + user.role = req.body.user.role; + } + + return user.save().then(function () { + return res.json({ user: user.toAuthJSON() }); + }); + }).catch(next); +}); + +router.post('/users/login', function (req, res, next) { + console.log(req.body.user); + if (!req.body.user.email) { + return res.status(422).json({ errors: { email: "email can't be blank" } }); + } + if (!req.body.user.password) { + return res.status(422).json({ errors: { password: " password can't be blank" } }); + } + passport.authenticate('local', { session: false }, function (err, user, info) { + if (err) { + return next(err); + } + if (user) { + user.token = user.generateJWT(); + return res.json({ user: user.toAuthJSON() }); + } else { + return res.status(422).json(info); + } + })(req, res, next); +}); + +router.get('/authenticate', function (req, res, next) { + passport.authenticate('headerapikey', { session: false }, function (err, application, info) { + if (err) { + return res.status(err.status || 500).json({message: "An authentication error occured.", err: err.message}); + //return next(err); + } + if (!application) { + return res.status(401).json({message: "Unauthorized - You are not allowed to access this resource.", err: err, info: info}); + } + if (application.author) { + application.author.token = application.author.generateJWT(); + return res.json({ user: application.author.toAuthJSON(), application: application.toAuthJSON() }); + } else { + return res.status(422).json(info); + } + })(req, res, next); +}); +router.post('/users', function (req, res, next) { + console.log('ici post users'); + let user = new User(); + if (typeof req.body.user.username !== 'undefined') { + user.username = req.body.user.username; + } else { + user.username = `${req.body.user.firstname}_${req.body.user.lastname}`; + } + user.email = req.body.user.email; + user.firstname = req.body.user.firstname; + user.lastname = req.body.user.lastname; + user.phone = req.body.user.phone; + if (typeof req.body.user.licence !== 'undefined') { + user.licence = req.body.user.licence; + } + if (typeof req.body.user.poids !== 'undefined') { + user.poids = req.body.user.poids; + } + user.setPassword(req.body.user.password); + user.role = 'User'; + + user.save().then(function () { + return res.json({ user: user.toAuthJSON() }); + }).catch(next); +}); + +module.exports = router; diff --git a/routes/auth.js b/routes/auth.js new file mode 100644 index 0000000..28107dc --- /dev/null +++ b/routes/auth.js @@ -0,0 +1,94 @@ + +//var jwt = require('express-jwt'); +var { expressjwt: jwt } = require("express-jwt"), + secret = require('../config').secret, + bcrypt = require('bcrypt'); +const { v4 } = require('uuid'), + passport = require('passport'), + auths = ['Api-Key', 'Basic', 'Bearer', 'Token']; + +function getTokenFromHeader(req) { + if(req.headers.authorization && auths.indexOf(req.headers.authorization.split(' ')[0]) !== -1) { + return req.headers.authorization.split(' ')[1]; + } + return null; +} + +const auth = { + requiredJwt: jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + getToken: getTokenFromHeader + }), + optional: jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + credentialsRequired: false, + getToken: getTokenFromHeader + }), + required: async (req, res, next) => { + if(req.headers.authorization && req.headers.authorization.split(' ')[0] === process.env.AUTHORIZATION_PREFIX) { + passport.authenticate('headerapikey', { session: false }, function (err, application, info) { + if (err) { + //return res.json({message: "An authentication error occured (required).", err: err.message}); + //return res.status(err.status || 500).json({message: "An authentication error occured (required).", err: err.message}); + return next({message: "An authentication error occured.", err: err.message}); + } + if (!application) { + return res.status(401).json({message: "Unauthorized - You are not allowed to access this resource.", err: err, info: info}); + } + req.application = application; + req.payload = {id: application.author._id}; + //console.log(application); + //console.log(application.author._id); + return next(); + /* + return jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + getToken: application.author.toAuthJSON().token + })(req, res, next); + */ + })(req, res, next); + } else { + return jwt({ + secret: secret, + algorithms: ['HS256'], + requestProperty: 'payload', + getToken: getTokenFromHeader + })(req, res, next); + } + }, + getAuthType: (req) => { + if(req.headers.authorization && auths.indexOf(req.headers.authorization.split(' ')[0]) !== -1) { + let value = req.headers.authorization.split(' ')[0]; + return value; + } + return null; + }, + generateAPIKey: async () => { + const key = v4().replace(/-/g, ''); + const salt = secret; + // Génération d'un salt aléatoire : const salt = await Promise.resolve(bcrypt.genSalt(10)); + const maskedKey = `${key.slice(0, 4)}...${key.slice(-4)}`; + const encryptedKey = await Promise.resolve(bcrypt.hash(key, salt)); + return { key: key, masked: maskedKey, encrypted: encryptedKey}; + }, + authenticateKey: async (req, res, next) => { + passport.authenticate('headerapikey', { session: false }, function (err, application, info) { + if (err) { + return res.status(err.status || 500).json({message: "An authentication error occured (authenticateKey).", err: err.message}); + } + if (!application) { + return res.status(401).json({message: "Unauthorized - You are not allowed to access this resource.", err: err, info: info}); + } + req.application = application; + return next(); + })(req, res, next); + } +}; + +module.exports = auth; diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..470acba --- /dev/null +++ b/routes/index.js @@ -0,0 +1,4 @@ +var router = require('express').Router(); +router.use('/api', require('./api')); + +module.exports = router; diff --git a/routes/queries.js b/routes/queries.js new file mode 100644 index 0000000..1ae0654 --- /dev/null +++ b/routes/queries.js @@ -0,0 +1,507 @@ +const queries = { + getJumpsByCategoryQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'categorie': '$categorie' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getJumpsByDateQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'year': { + '$year': '$date' + }, + 'month': { + '$month': '$date' + } + } + }, { + '$group': { + '_id': { + 'year': '$year', + 'month': '$month' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getJumpsByModuleByDateQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'module': 1, + 'categorie': 1, + 'year': { + '$year': '$date' + }, + 'month': { + '$month': '$date' + } + } + }, { + '$group': { + '_id': { + 'module': '$module', + 'categorie': '$categorie', + 'year': '$year', + 'month': '$month' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + return query; + }, + getJumpsByModuleQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'categorie': 1, + 'module': 1 + } + }, { + '$group': { + '_id': { + 'categorie': '$categorie', + 'module': '$module' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + return query; + }, + getJumpByYearsQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getAeronefsByImatQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'aeronef': '$aeronef', + 'imat': '$imat' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + 'count': -1 + }, + } + ]; + + return query; + }, + getAeronefsByImatByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'aeronef': 1, + 'imat': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'aeronef': '$aeronef', + 'imat': '$imat', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getCanopiesBySizeQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + '_id': 1 + }, + } + ]; + + return query; + }, + getCanopiesBySizeByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'taille': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getCanopiesBySizeByModelQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille', + 'voile': '$voile' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + '_id': 1 + }, + } + ]; + + return query; + }, + getCanopiesBySizeByModelByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'voile': 1, + 'taille': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'taille': '$taille', + 'voile': '$voile', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getDropZonesByOaciQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$group': { + '_id': { + 'lieu': '$lieu', + 'oaci': '$oaci' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': + { + '_id': 1 + }, + } + ]; + + return query; + }, + getDropZonesByOaciByYearQuery: (userId) => { + let query = [ + { + '$match': { + '$expr': { + '$eq': [ '$author' , { '$toObjectId': userId } ] + } + } + }, { + '$project': { + '_id': 0, + 'lieu': 1, + 'oaci': 1, + 'year': { + '$year': '$date' + } + } + }, { + '$group': { + '_id': { + 'lieu': '$lieu', + 'oaci': '$oaci', + 'year': '$year' + }, + 'count': { + '$sum': 1 + } + } + }, { + '$sort': { + '_id': 1 + } + } + ]; + + return query; + }, + getJumpsByDayQuery: (userId, dateRangeStart = null, dateRangeEnd = null) => { + if (dateRangeStart === null) { + dateRangeStart = '1970-01-01 00:00:00'; + } + if (dateRangeEnd === null) { + const year = new Date().getFullYear(); + dateRangeEnd = `${year}-12-31 23:59:59`; + } + let query = [ + { + $match: { + $expr: { + $and: [ + { + $eq: [ '$author' , { '$toObjectId': userId } ] + }, + { + $gte: ['$date', new Date(dateRangeStart)] + }, + { + $lte: ['$date', new Date(dateRangeEnd)] + } + ] + } + } + }, { + $project: { + _id: 1, + slug: "$slug", + numero: "$numero", + date: "$date", + year: { + $year: "$date" + }, + month: { + $month: "$date" + }, + day: { + $dayOfMonth: "$date" + } + } + }, + { + $group: { + _id: { + year: "$year", + month: "$month", + day: "$day" + }, + jumps: { + $addToSet: { + _id: "$_id", + numero: "$numero", + slug: "$slug", + date: "$date" + } + }, + count: { + $sum: 1 + } + } + }, + { + $sort: { + _id: 1, + } + }, + { + $project: { + _id: 0, + jumps: 1, + count: 1 + } + } + ]; + + return query; + } +}; + +module.exports = queries; diff --git a/routes/utils.js b/routes/utils.js new file mode 100644 index 0000000..caa5f0c --- /dev/null +++ b/routes/utils.js @@ -0,0 +1,84 @@ +const chalk = require('chalk'); +const utils = { + getDateString: () => { + let today = new Date(); + let dateNow = today.toLocaleDateString(); + return `${dateNow}`; + }, + getTimeString: () => { + let today = new Date(); + let timeNow = today.toLocaleTimeString(); + return `${timeNow}`; + }, + getDateTimeString: (delimiter = true) => { + let today = new Date(); + let dateString = `${today.toLocaleDateString()} ${today.toLocaleTimeString()}`; + if (delimiter) { + dateString = `[${dateString}]`; + } + return dateString; + }, + getDateTimeISOString: (delimiter = true) => { + let today = new Date(); + let dateString = today.toISOString(); + if (delimiter) { + dateString = `[${dateString}]`; + } + return dateString; + }, + async fetchSkydiverIdApi(path, query) { + let limit = 50; + let offset = 0; + let args = ''; + if (typeof query.limit !== 'undefined') { + limit = query.limit; + } + if (typeof query.offset !== 'undefined') { + offset = ((query.offset/limit)+1); + } + if (offset > 1) { + args += `&page=${offset}`; + } + if (typeof query.dateRangeStart !== 'undefined' && typeof query.dateRangeEnd !== 'undefined') { + args += `&filter[and][0][date][gte]=${query.dateRangeStart}`; + args += `&filter[and][0][date][lte]=${query.dateRangeEnd}`; + } + try { + let url = `${process.env.SKYDIVERID_API_URL}/${path}`; + if (typeof query.limit !== 'undefined') { + url += `?per-page=${limit}${args}`; + } + /* url pour provoquer une erreur en dev : url = `https://www.goldapi.ioppppp/api/${price.metal}/${price.currency}`; */ + let options = { + method: 'GET', + headers: { + 'Authorization': `Bearer ${process.env.SKYDIVERID_API_TOKEN}`, + 'Content-Type': 'application/json' + }, + redirect: 'follow' + }; + /* Pour tester le retour d'erreur : return { errors: { name: 'error name', message: 'error message', type: 'TYPE', code: 'CODE' } }; */ + //const response = await fetch(url, options); + return fetch(url, options).then(function (response) { + if (response.status >= 200 && response.status < 400) { + console.log(`${utils.getDateTimeISOString()}`, chalk.green(`Réception des sauts via SkydiverId API`), `${response.status} ${response.statusText}`); + const data = response.json(); + console.log(data); + return data; + } else { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`Erreur ${response.status} ${response.statusText}`)); + return { errors: { name: response.statusText, message: `Une erreur ${response.status} '${response.statusText}' est survenue lors de la récupération des sauts via SkydiverId API`, type: 'API Error', code: response.status } }; + } + }) + .catch(error => { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`A fetchSkydiverIdApi error occured ${error.code} ${error.type}`)); + return { errors: { name: error.name, message: `A fetchSkydiverIdApi error occured : ${error.message}`, type: error.type, code: error.code } }; + }); + } catch (error) { + console.log(`${utils.getDateTimeISOString()}`, chalk.red(`fetchSkydiverIdApi error`)); + return { errors: { name: error.name, message: error.message, type: error.type, code: error.code } }; + } + } +}; + +module.exports = utils; diff --git a/tests/api-tests.postman.json b/tests/api-tests.postman.json new file mode 100644 index 0000000..bff2fb7 --- /dev/null +++ b/tests/api-tests.postman.json @@ -0,0 +1,2015 @@ +{ + "variables": [], + "info": { + "name": "Ad Astra API Tests", + "_postman_id": "dda3e595-02d7-bf12-2a43-3daea0970192", + "description": "Collection for testing the Ad Astra API\n\nhttps://api.adastra-cbd.com/", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json" + }, + "item": [ + { + "name": "Auth", + "description": "", + "item": [ + { + "name": "Register", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/users", + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"anne@honime.com\", \"password\":\"annehonimepwd\", \"username\":\"annehonime\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Login", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/users/login", + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"anne@honime.com\", \"password\":\"annehonimepwd\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Login and Remember Token", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "", + "if(tests['User has \"token\" property']){", + " postman.setEnvironmentVariable('token', user.token);", + "}", + "", + "tests['Environment variable \"token\" has been set'] = environment.token === user.token;", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/users/login", + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"anne@honime.com\", \"password\":\"annehonimepwd\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Current User", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/user", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Update User", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"user\" property'] = responseJSON.hasOwnProperty('user');", + "", + "var user = responseJSON.user || {};", + "", + "tests['User has \"email\" property'] = user.hasOwnProperty('email');", + "tests['User has \"username\" property'] = user.hasOwnProperty('username');", + "tests['User has \"token\" property'] = user.hasOwnProperty('token');", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/user", + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"anne@honime.com\"}}" + }, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Articles with authentication", + "description": "", + "item": [ + { + "name": "Feed", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/feed", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "All Articles", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "All Articles with auth", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Author", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?author=annehonime", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "author", + "value": "annehonime" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Author with auth", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?author=annehonime", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "author", + "value": "annehonime", + "equals": true, + "description": "" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Articles Favorited by Username", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?favorited=jane", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "favorited", + "value": "jane" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles Favorited by Username with auth", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?favorited=jane", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "favorited", + "value": "jane" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Tag", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?tag=octopus", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "tag", + "value": "octopus" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Create Article", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "if(tests['Article has \"slug\" property']){", + " postman.setEnvironmentVariable('slug', article.slug);", + "}", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles", + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"article\":{\"title\":\"How to tame an octopus\", \"description\":\"Ever wonder how?\", \"body\":\"Very carefully.\", \"tagList\":[\"octopus\",\"training\"]}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Single Article by slug", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Update Article", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"article\":{\"body\":\"With two hands\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Favorite Article", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests[\"Article's 'favorited' property is true\"] = article.favorited === true;", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "tests[\"Article's 'favoritesCount' property is greater than 0\"] = article.favoritesCount > 0;", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/favorite", + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Unfavorite Article", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "tests[\"Article's \\\"favorited\\\" property is true\"] = article.favorited === false;", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/favorite", + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Articles", + "description": "", + "item": [ + { + "name": "All Articles", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Author", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?author=annehonime", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "author", + "value": "annehonime" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles Favorited by Username", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?favorited=jane", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "favorited", + "value": "jane" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Articles by Tag", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"articles\" property'] = responseJSON.hasOwnProperty('articles');", + " tests['Response contains \"articlesCount\" property'] = responseJSON.hasOwnProperty('articlesCount');", + " tests['articlesCount is an integer'] = Number.isInteger(responseJSON.articlesCount);", + "", + " if(responseJSON.articles.length){", + " var article = responseJSON.articles[0];", + "", + " tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + " tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + " tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + " tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + " tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + " tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + " tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + " tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + " tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + " tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + " tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + " tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + " tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + " tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + " } else {", + " tests['articlesCount is 0 when feed is empty'] = responseJSON.articlesCount === 0;", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": { + "raw": "{{apiUrl}}/articles?tag=octopus", + "host": [ + "{{apiUrl}}" + ], + "path": [ + "articles" + ], + "query": [ + { + "key": "tag", + "value": "octopus" + } + ], + "variable": [] + }, + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Single Article by slug", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"article\" property'] = responseJSON.hasOwnProperty('article');", + "", + "var article = responseJSON.article || {};", + "", + "tests['Article has \"title\" property'] = article.hasOwnProperty('title');", + "tests['Article has \"slug\" property'] = article.hasOwnProperty('slug');", + "tests['Article has \"body\" property'] = article.hasOwnProperty('body');", + "tests['Article has \"createdAt\" property'] = article.hasOwnProperty('createdAt');", + "tests['Article\\'s \"createdAt\" property is an ISO 8601 timestamp'] = new Date(article.createdAt).toISOString() === article.createdAt;", + "tests['Article has \"updatedAt\" property'] = article.hasOwnProperty('updatedAt');", + "tests['Article\\'s \"updatedAt\" property is an ISO 8601 timestamp'] = new Date(article.updatedAt).toISOString() === article.updatedAt;", + "tests['Article has \"description\" property'] = article.hasOwnProperty('description');", + "tests['Article has \"tagList\" property'] = article.hasOwnProperty('tagList');", + "tests['Article\\'s \"tagList\" property is an Array'] = Array.isArray(article.tagList);", + "tests['Article has \"author\" property'] = article.hasOwnProperty('author');", + "tests['Article has \"favorited\" property'] = article.hasOwnProperty('favorited');", + "tests['Article has \"favoritesCount\" property'] = article.hasOwnProperty('favoritesCount');", + "tests['favoritesCount is an integer'] = Number.isInteger(article.favoritesCount);", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Comments", + "description": "", + "item": [ + { + "name": "All Comments for Article", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"comments\" property'] = responseJSON.hasOwnProperty('comments');", + "", + " if(responseJSON.comments.length){", + " var comment = responseJSON.comments[0];", + "", + " tests['Comment has \"id\" property'] = comment.hasOwnProperty('id');", + " tests['Comment has \"body\" property'] = comment.hasOwnProperty('body');", + " tests['Comment has \"createdAt\" property'] = comment.hasOwnProperty('createdAt');", + " tests['\"createdAt\" property is an ISO 8601 timestamp'] = new Date(comment.createdAt).toISOString() === comment.createdAt;", + " tests['Comment has \"updatedAt\" property'] = comment.hasOwnProperty('updatedAt');", + " tests['\"updatedAt\" property is an ISO 8601 timestamp'] = new Date(comment.updatedAt).toISOString() === comment.updatedAt;", + " tests['Comment has \"author\" property'] = comment.hasOwnProperty('author');", + " }", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/comments", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Create Comment for Article", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var responseJSON = JSON.parse(responseBody);", + "", + "tests['Response contains \"comment\" property'] = responseJSON.hasOwnProperty('comment');", + "", + "var comment = responseJSON.comment || {};", + "", + "tests['Comment has \"id\" property'] = comment.hasOwnProperty('id');", + "tests['Comment has \"body\" property'] = comment.hasOwnProperty('body');", + "tests['Comment has \"createdAt\" property'] = comment.hasOwnProperty('createdAt');", + "tests['\"createdAt\" property is an ISO 8601 timestamp'] = new Date(comment.createdAt).toISOString() === comment.createdAt;", + "tests['Comment has \"author\" property'] = comment.hasOwnProperty('author');", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/comments", + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"comment\":{\"body\":\"Thank you so much!\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Delete Comment for Article", + "request": { + "url": "{{apiUrl}}/articles/{{slug}}/comments/1", + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Profiles", + "description": "", + "item": [ + { + "name": "Profile", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"profile\" property'] = responseJSON.hasOwnProperty('profile');", + " ", + " var profile = responseJSON.profile || {};", + " ", + " tests['Profile has \"username\" property'] = profile.hasOwnProperty('username');", + " tests['Profile has \"image\" property'] = profile.hasOwnProperty('image');", + " tests['Profile has \"following\" property'] = profile.hasOwnProperty('following');", + "}", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/profiles/annehonime", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + }, + { + "name": "Follow Profile", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"profile\" property'] = responseJSON.hasOwnProperty('profile');", + " ", + " var profile = responseJSON.profile || {};", + " ", + " tests['Profile has \"username\" property'] = profile.hasOwnProperty('username');", + " tests['Profile has \"image\" property'] = profile.hasOwnProperty('image');", + " tests['Profile has \"following\" property'] = profile.hasOwnProperty('following');", + " tests['Profile\\'s \"following\" property is true'] = profile.following === true;", + "}", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/profiles/annehonime/follow", + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "{\"user\":{\"email\":\"anne@honime.com\"}}" + }, + "description": "" + }, + "response": [] + }, + { + "name": "Unfollow Profile", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "if (!(environment.isIntegrationTest)) {", + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + "", + " tests['Response contains \"profile\" property'] = responseJSON.hasOwnProperty('profile');", + " ", + " var profile = responseJSON.profile || {};", + " ", + " tests['Profile has \"username\" property'] = profile.hasOwnProperty('username');", + " tests['Profile has \"image\" property'] = profile.hasOwnProperty('image');", + " tests['Profile has \"following\" property'] = profile.hasOwnProperty('following');", + " tests['Profile\\'s \"following\" property is false'] = profile.following === false;", + "}", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/profiles/annehonime/follow", + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": {}, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Tags", + "description": "", + "item": [ + { + "name": "All Tags", + "event": [ + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "var is200Response = responseCode.code === 200;", + "", + "tests['Response code is 200 OK'] = is200Response;", + "", + "if(is200Response){", + " var responseJSON = JSON.parse(responseBody);", + " ", + " tests['Response contains \"tags\" property'] = responseJSON.hasOwnProperty('tags');", + " tests['\"tags\" property returned as array'] = Array.isArray(responseJSON.tags);", + "}", + "" + ] + } + } + ], + "request": { + "url": "{{apiUrl}}/tags", + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + } + ] + }, + { + "name": "Cleanup", + "description": "", + "item": [ + { + "name": "Delete Article", + "request": { + "url": "{{apiUrl}}/articles/{{slug}}", + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "description": "" + }, + { + "key": "X-Requested-With", + "value": "XMLHttpRequest", + "description": "" + }, + { + "key": "Authorization", + "value": "Token {{token}}", + "description": "" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "description": "" + }, + "response": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/env-api-tests.postman.json b/tests/env-api-tests.postman.json new file mode 100644 index 0000000..cca4e4e --- /dev/null +++ b/tests/env-api-tests.postman.json @@ -0,0 +1,16 @@ +{ + "id": "4aa60b52-97fc-456d-4d4f-14a350e95dff", + "name": "Ad Astra API Tests - Environment", + "values": [ + { + "enabled": true, + "key": "apiUrl", + "value": "http://localhost:3200/api", + "type": "text" + } + ], + "timestamp": 1505871382668, + "_postman_variable_scope": "environment", + "_postman_exported_at": "2017-09-20T01:36:34.835Z", + "_postman_exported_using": "Postman/5.2.0" +} \ No newline at end of file