From 1899d360584e281e027c537d2df0f75a1115776e Mon Sep 17 00:00:00 2001 From: Matt Love Date: Thu, 27 May 2021 12:19:46 -0700 Subject: [PATCH] download report.xml to local filesystem even when DTP publishing is disabled --- README.md | 12 ++++- __tests__/main.test.ts | 2 +- dist/index.js | 104 ++++++++++++++++------------------------- dist/index.js.map | 2 +- package.json | 2 +- src/main.ts | 75 ++++++++++++----------------- src/report.ts | 29 +++++------- src/service.ts | 2 +- 8 files changed, 96 insertions(+), 132 deletions(-) diff --git a/README.md b/README.md index 83eab20..513f7f1 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,20 @@ Add the following entry to your Github workflow YAML file with the required inpu ```yaml uses: parasoft/execute-job-action@v1 with: - ctpUrl: 'http://exampleUrl' + ctpUrl: 'http://ctp.mycompany.org:8080/em/' ctpUsername: 'username' ctpPassword: ${{ secrets.password }} ctpJob: 'Example Job' + abortOnTimeout: false + timeoutInMinutes: 5 + publishReport: false + dtpUrl: 'http://dtp.mycompany.org:8080/grs/' + dtpUsername: 'username' + dtpPassword: ${{ secrets.password }} + dtpProject: 'My Project' + buildId: ${{ github.run_number }} + sessionTag: ${{ github.workflow }} + appendEnvironment: false ``` ### Required Inputs The following inputs are required: diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index df62e52..4ae669b 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -60,7 +60,7 @@ test('test runs', () => { process.env['INPUT_CTPUSERNAME'] = 'demo' process.env['INPUT_CTPPASSWORD'] = 'demo-user' process.env['INPUT_CTPJOB'] = 'P1 Smoke Tests' - process.env['INPUT_PUBLISHREPORT'] = 'true' + process.env['INPUT_PUBLISHREPORT'] = 'false' process.env['INPUT_DTPURL'] = 'http://18.236.243.147:8080/grs/' process.env['INPUT_DTPUSERNAME'] = 'demo' process.env['INPUT_DTPPASSWORD'] = 'demo-user' diff --git a/dist/index.js b/dist/index.js index e5ddf2f..9d4fb88 100644 --- a/dist/index.js +++ b/dist/index.js @@ -68,23 +68,20 @@ function run() { let dtpService = null; const publish = core.getInput('publishReport') === 'true'; const dtpEndpoint = core.getInput('dtpUrl', { required: false }); - var dtpAuthorization = null; - if (dtpEndpoint) { - dtpAuthorization = { username: core.getInput('dtpUsername'), password: core.getInput('dtpPassword') }; - } const dtpProject = core.getInput('dtpProject'); const dtpBuildId = core.getInput('buildId'); let dtpSessionTag = core.getInput('sessionTag'); const appendEnvironment = core.getInput('appendEnvironment') === 'true'; + let metaData = { + dtpProject: dtpProject, + dtpBuildId: dtpBuildId, + dtpSessionTag: dtpSessionTag, + appendEnvironment: appendEnvironment + }; if (dtpEndpoint && publish) { - let metaData = { - dtpProject: dtpProject, - dtpBuildId: dtpBuildId, - dtpSessionTag: dtpSessionTag, - appendEnvironment: appendEnvironment - }; - dtpService = new report.ReportPublisher(dtpEndpoint, 'grs', ctpService, metaData, dtpAuthorization); + dtpService = new service.WebService(dtpEndpoint, 'grs', { username: core.getInput('dtpUsername'), password: core.getInput('dtpPassword') }); } + let reportController = new report.ReportController(ctpService, dtpService, metaData); const abortOnTimout = core.getInput('abortOnTimeout') === 'true'; const timeout = core.getInput('timeoutInMinutes'); const jobName = core.getInput('ctpJob', { required: true }); @@ -126,49 +123,35 @@ function run() { if (status === 'RUNNING' || status === 'WAITING') { setTimeout(checkStatus, 1000); } - else if (status === 'PASSED') { - core.info('All tests passed.'); - if (dtpService) { - let environmentNames = extractEnvironmentNames(job); - res.reportIds.forEach((reportId, index) => { - dtpService.publishReport(reportId, index, environmentNames.length > 0 ? environmentNames.shift() : null).catch((err) => { - core.error("Failed to publish report to DTP"); - }).then(() => { - if (index === 0) { - console.log(' View results in DTP: ' + dtpService.getBaseURL() + '/dtp/explorers/test?buildId=' + dtpBuildId); - } - }); - }); - } - else { - res.reportIds.forEach((reportId, index) => { - core.info(` View report in CTP: ${ctpService.getBaseURL()}/testreport/${reportId}/report.html`); - }); - } - } else if (status === 'CANCELED') { core.warning('Test execution was canceled.'); } else { - core.error('Some tests failed.'); - if (dtpService) { - res.reportIds.forEach((reportId, index) => { - let environmentNames = extractEnvironmentNames(job); - dtpService.publishReport(reportId, index, environmentNames.length > 0 ? environmentNames.shift() : null).catch((err) => { - core.error("Failed to publish report to DTP"); - }).then(() => { - if (index === 0) { - console.log(' View results in DTP: ' + dtpService.getBaseURL() + '/dtp/explorers/test?buildId=' + dtpBuildId); - } - }); - }); + if (status === 'PASSED') { + core.info('All tests passed.'); } else { - res.reportIds.forEach((reportId, index) => { - core.info(` View report in CTP: ${ctpService.getBaseURL()}/testreport/${reportId}/report.html`); - }); + core.setFailed('Some tests failed.'); } - core.setFailed('Job "' + jobName + '" failed.'); + let environmentNames = extractEnvironmentNames(job); + res.reportIds.forEach((reportId, index) => { + let downloadPromise = reportController.downloadReport(reportId, index, environmentNames.length > 0 ? environmentNames.shift() : null).catch((err) => { + core.error("Failed to download report from CTP"); + }); + if (dtpService) { + downloadPromise.then(() => { + reportController.uploadFile(reportId).then(response => { + core.debug(` report.xml file upload successful: ${response}`); + if (index === 0) { + core.info(' View results in DTP: ' + dtpService.getBaseURL() + '/dtp/explorers/test?buildId=' + dtpBuildId); + } + }).catch((error) => { + core.error(`Error while uploading report.xml file: ${error}`); + core.error("Failed to publish report to DTP"); + }); + }); + } + }); } }); }); @@ -216,22 +199,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.ReportPublisher = void 0; -const service = __importStar(__nccwpck_require__(511)); +exports.ReportController = void 0; const q_1 = __importDefault(__nccwpck_require__(172)); const form_data_1 = __importDefault(__nccwpck_require__(334)); const fs_1 = __importDefault(__nccwpck_require__(747)); const url_1 = __importDefault(__nccwpck_require__(835)); const core = __importStar(__nccwpck_require__(186)); -class ReportPublisher extends service.WebService { - constructor(endpoint, context, ctpService, metaData, authorization) { - super(endpoint, context, authorization); +class ReportController { + constructor(ctpService, dtpService, metaData) { this.ctpService = ctpService; + this.dtpService = dtpService; this.metaData = metaData; } uploadFile(reportId) { let def = q_1.default.defer(); - this.performGET('/api/v1.6/services').then((response) => { + this.dtpService.performGET('/api/v1.6/services').then((response) => { let dataCollectorURL = url_1.default.parse(response.services.dataCollectorV2); let form = new form_data_1.default(); let protocol = dataCollectorURL.protocol === 'https:' ? 'https:' : 'http:'; @@ -247,8 +229,8 @@ class ReportPublisher extends service.WebService { if (protocol === 'https:') { options['rejectUnauthorized'] = false; options['agent'] = false; - if (this.authorization && this.authorization['username']) { - options.auth = this.authorization['username'] + ':' + this.authorization['password']; + if (this.dtpService.authorization && this.dtpService.authorization['username']) { + options.auth = this.dtpService.authorization['username'] + ':' + this.dtpService.authorization['password']; } } core.debug(`POST ${options.protocol}//${options.host}${options.port ? `:${options.port}` : ""}${options.path}`); @@ -271,7 +253,7 @@ class ReportPublisher extends service.WebService { }); return def.promise; } - publishReport(reportId, index, environmentName) { + downloadReport(reportId, index, environmentName) { let def = q_1.default.defer(), firstCallback = true; this.ctpService.performGET(`/testreport/${reportId}/report.xml`, (res, def, responseStr) => { def.resolve(responseStr); @@ -303,13 +285,7 @@ class ReportPublisher extends service.WebService { }).then(() => { core.info(` Saved XML report: target/parasoft/soatest/${reportId}/report.xml`); core.info(` View report in CTP: ${this.ctpService.getBaseURL()}/testreport/${reportId}/report.html`); - this.uploadFile(reportId).then(response => { - core.debug(` report.xml file upload successful: ${response}`); - def.resolve(); - }).catch((error) => { - core.error(`Error while uploading report.xml file: ${error}`); - def.reject(error); - }); + def.resolve(); }); return def.promise; } @@ -337,7 +313,7 @@ class ReportPublisher extends service.WebService { return source.replace(regEx, attribute + '="' + newValue + '"'); } } -exports.ReportPublisher = ReportPublisher; +exports.ReportController = ReportController; /***/ }), diff --git a/dist/index.js.map b/dist/index.js.map index 0704773..c0a7a30 100644 --- a/dist/index.js.map +++ b/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["../webpack://execute-job-action/./lib/main.js","../webpack://execute-job-action/./lib/report.js","../webpack://execute-job-action/./lib/service.js","../webpack://execute-job-action/./node_modules/@actions/core/lib/command.js","../webpack://execute-job-action/./node_modules/@actions/core/lib/core.js","../webpack://execute-job-action/./node_modules/@actions/core/lib/file-command.js","../webpack://execute-job-action/./node_modules/@actions/core/lib/utils.js","../webpack://execute-job-action/./node_modules/asynckit/index.js","../webpack://execute-job-action/./node_modules/asynckit/lib/abort.js","../webpack://execute-job-action/./node_modules/asynckit/lib/async.js","../webpack://execute-job-action/./node_modules/asynckit/lib/defer.js","../webpack://execute-job-action/./node_modules/asynckit/lib/iterate.js","../webpack://execute-job-action/./node_modules/asynckit/lib/state.js","../webpack://execute-job-action/./node_modules/asynckit/lib/terminator.js","../webpack://execute-job-action/./node_modules/asynckit/parallel.js","../webpack://execute-job-action/./node_modules/asynckit/serial.js","../webpack://execute-job-action/./node_modules/asynckit/serialOrdered.js","../webpack://execute-job-action/./node_modules/combined-stream/lib/combined_stream.js","../webpack://execute-job-action/./node_modules/delayed-stream/lib/delayed_stream.js","../webpack://execute-job-action/./node_modules/form-data/lib/form_data.js","../webpack://execute-job-action/./node_modules/form-data/lib/populate.js","../webpack://execute-job-action/./node_modules/mime-db/index.js","../webpack://execute-job-action/./node_modules/mime-types/index.js","../webpack://execute-job-action/./node_modules/q/q.js","../webpack://execute-job-action/external \"fs\"","../webpack://execute-job-action/external \"http\"","../webpack://execute-job-action/external \"https\"","../webpack://execute-job-action/external \"os\"","../webpack://execute-job-action/external \"path\"","../webpack://execute-job-action/external \"stream\"","../webpack://execute-job-action/external \"url\"","../webpack://execute-job-action/external \"util\"","../webpack://execute-job-action/webpack/bootstrap","../webpack://execute-job-action/webpack/runtime/compat","../webpack://execute-job-action/webpack/startup"],"sourcesContent":["\"use strict\";\r\n/// \r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.run = void 0;\r\nconst core = __importStar(require(\"@actions/core\"));\r\nconst service = __importStar(require(\"./service\"));\r\nconst report = __importStar(require(\"./report\"));\r\nfunction extractEnvironmentNames(job) {\r\n let separate = job.fork, lastTestId = null, environmentNames = [];\r\n job.testScenarioInstances.forEach((instance => {\r\n let testScenarioId = instance.testScenarioId, variableset = instance.variableSet;\r\n if (separate || (lastTestId == null || lastTestId === testScenarioId)) {\r\n environmentNames.push(variableset);\r\n }\r\n lastTestId = testScenarioId;\r\n }));\r\n return environmentNames;\r\n}\r\nfunction run() {\r\n return __awaiter(this, void 0, void 0, function* () {\r\n const ctpEndpoint = core.getInput('ctpUrl', { required: true });\r\n const ctpUsername = core.getInput('ctpUsername', { required: true });\r\n const ctpPassword = core.getInput('ctpPassword', { required: true });\r\n const ctpService = new service.WebService(ctpEndpoint, 'em', { username: ctpUsername, password: ctpPassword });\r\n let dtpService = null;\r\n const publish = core.getInput('publishReport') === 'true';\r\n const dtpEndpoint = core.getInput('dtpUrl', { required: false });\r\n var dtpAuthorization = null;\r\n if (dtpEndpoint) {\r\n dtpAuthorization = { username: core.getInput('dtpUsername'), password: core.getInput('dtpPassword') };\r\n }\r\n const dtpProject = core.getInput('dtpProject');\r\n const dtpBuildId = core.getInput('buildId');\r\n let dtpSessionTag = core.getInput('sessionTag');\r\n const appendEnvironment = core.getInput('appendEnvironment') === 'true';\r\n if (dtpEndpoint && publish) {\r\n let metaData = {\r\n dtpProject: dtpProject,\r\n dtpBuildId: dtpBuildId,\r\n dtpSessionTag: dtpSessionTag,\r\n appendEnvironment: appendEnvironment\r\n };\r\n dtpService = new report.ReportPublisher(dtpEndpoint, 'grs', ctpService, metaData, dtpAuthorization);\r\n }\r\n const abortOnTimout = core.getInput('abortOnTimeout') === 'true';\r\n const timeout = core.getInput('timeoutInMinutes');\r\n const jobName = core.getInput('ctpJob', { required: true });\r\n let job;\r\n ctpService.performGET('/api/v2/jobs', (res, def, responseStr) => {\r\n core.debug(` response ${res.statusCode}: ${responseStr}`);\r\n let allJobs = JSON.parse(responseStr);\r\n if (typeof allJobs.jobs === 'undefined') {\r\n def.reject('jobs' + ' does not exist in response object from /api/v2/jobs');\r\n return;\r\n }\r\n let match = allJobs.jobs.find(job => job.name === jobName);\r\n if (match) {\r\n def.resolve(match);\r\n return;\r\n }\r\n def.reject(`Could not find name ${jobName} in jobs from /api/v2/jobs`);\r\n }).then((response) => {\r\n core.info(`Executing \"${response.name}\" on ${ctpService.getBaseURL()}`);\r\n job = response;\r\n return ctpService.performPOST(`/api/v2/jobs/${job.id}/histories?async=true`, {});\r\n }).then((res) => {\r\n let historyId = res.id;\r\n let status = res.status;\r\n let startTime = new Date().getTime();\r\n let checkStatus = function () {\r\n return __awaiter(this, void 0, void 0, function* () {\r\n ctpService.performGET(`/api/v2/jobs/${job.id}/histories/${historyId}`).then((res) => {\r\n status = res.status;\r\n if (abortOnTimout) {\r\n let timespent = (new Date().getTime() - startTime) / 60000, timeoutNum = parseInt(timeout);\r\n if (timespent > timeoutNum) {\r\n ctpService.performPUT(`/api/v2/jobs/${job.id}/histories/${historyId}`, { status: 'CANCELED' });\r\n core.error(`Test execution job timed out after ${timeoutNum} minute\"${timeoutNum > 1 ? 's' : \"\"}.`);\r\n core.setFailed('Job \"' + jobName + '\" timed out.');\r\n return;\r\n }\r\n }\r\n if (status === 'RUNNING' || status === 'WAITING') {\r\n setTimeout(checkStatus, 1000);\r\n }\r\n else if (status === 'PASSED') {\r\n core.info('All tests passed.');\r\n if (dtpService) {\r\n let environmentNames = extractEnvironmentNames(job);\r\n res.reportIds.forEach((reportId, index) => {\r\n dtpService.publishReport(reportId, index, environmentNames.length > 0 ? environmentNames.shift() : null).catch((err) => {\r\n core.error(\"Failed to publish report to DTP\");\r\n }).then(() => {\r\n if (index === 0) {\r\n console.log(' View results in DTP: ' + dtpService.getBaseURL() + '/dtp/explorers/test?buildId=' + dtpBuildId);\r\n }\r\n });\r\n });\r\n }\r\n else {\r\n res.reportIds.forEach((reportId, index) => {\r\n core.info(` View report in CTP: ${ctpService.getBaseURL()}/testreport/${reportId}/report.html`);\r\n });\r\n }\r\n }\r\n else if (status === 'CANCELED') {\r\n core.warning('Test execution was canceled.');\r\n }\r\n else {\r\n core.error('Some tests failed.');\r\n if (dtpService) {\r\n res.reportIds.forEach((reportId, index) => {\r\n let environmentNames = extractEnvironmentNames(job);\r\n dtpService.publishReport(reportId, index, environmentNames.length > 0 ? environmentNames.shift() : null).catch((err) => {\r\n core.error(\"Failed to publish report to DTP\");\r\n }).then(() => {\r\n if (index === 0) {\r\n console.log(' View results in DTP: ' + dtpService.getBaseURL() + '/dtp/explorers/test?buildId=' + dtpBuildId);\r\n }\r\n });\r\n });\r\n }\r\n else {\r\n res.reportIds.forEach((reportId, index) => {\r\n core.info(` View report in CTP: ${ctpService.getBaseURL()}/testreport/${reportId}/report.html`);\r\n });\r\n }\r\n core.setFailed('Job \"' + jobName + '\" failed.');\r\n }\r\n });\r\n });\r\n };\r\n if (status === 'RUNNING' || status === 'WAITING') {\r\n setTimeout(checkStatus, 1000);\r\n }\r\n }).catch((e) => {\r\n core.error(e);\r\n core.setFailed(e);\r\n });\r\n });\r\n}\r\nexports.run = run;\r\nrun();\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.ReportPublisher = void 0;\r\nconst service = __importStar(require(\"./service\"));\r\nconst q_1 = __importDefault(require(\"q\"));\r\nconst form_data_1 = __importDefault(require(\"form-data\"));\r\nconst fs_1 = __importDefault(require(\"fs\"));\r\nconst url_1 = __importDefault(require(\"url\"));\r\nconst core = __importStar(require(\"@actions/core\"));\r\nclass ReportPublisher extends service.WebService {\r\n constructor(endpoint, context, ctpService, metaData, authorization) {\r\n super(endpoint, context, authorization);\r\n this.ctpService = ctpService;\r\n this.metaData = metaData;\r\n }\r\n uploadFile(reportId) {\r\n let def = q_1.default.defer();\r\n this.performGET('/api/v1.6/services').then((response) => {\r\n let dataCollectorURL = url_1.default.parse(response.services.dataCollectorV2);\r\n let form = new form_data_1.default();\r\n let protocol = dataCollectorURL.protocol === 'https:' ? 'https:' : 'http:';\r\n form.append('file', fs_1.default.createReadStream(`target/parasoft/soatest/${reportId}/report.xml`));\r\n let options = {\r\n host: dataCollectorURL.hostname,\r\n port: parseInt(dataCollectorURL.port),\r\n path: dataCollectorURL.path,\r\n method: 'POST',\r\n protocol: protocol,\r\n headers: form.getHeaders()\r\n };\r\n if (protocol === 'https:') {\r\n options['rejectUnauthorized'] = false;\r\n options['agent'] = false;\r\n if (this.authorization && this.authorization['username']) {\r\n options.auth = this.authorization['username'] + ':' + this.authorization['password'];\r\n }\r\n }\r\n core.debug(`POST ${options.protocol}//${options.host}${options.port ? `:${options.port}` : \"\"}${options.path}`);\r\n form.submit(options, (err, res) => {\r\n if (err) {\r\n return def.reject(new Error(err.message));\r\n }\r\n if (res.statusCode < 200 || res.statusCode > 299) {\r\n return def.reject(new Error(`HTTP status code ${res.statusCode}`));\r\n }\r\n let body = [];\r\n res.on('data', (chunk) => body.push(chunk));\r\n res.on('end', () => {\r\n let resString = Buffer.concat(body).toString();\r\n def.resolve(resString);\r\n });\r\n });\r\n }).catch((error) => {\r\n def.reject(error);\r\n });\r\n return def.promise;\r\n }\r\n publishReport(reportId, index, environmentName) {\r\n let def = q_1.default.defer(), firstCallback = true;\r\n this.ctpService.performGET(`/testreport/${reportId}/report.xml`, (res, def, responseStr) => {\r\n def.resolve(responseStr);\r\n }, (response) => {\r\n let fileData = response;\r\n if (firstCallback) {\r\n fileData = this.injectMetaData(fileData, index, this.metaData.appendEnvironment ? environmentName : null);\r\n firstCallback = false;\r\n }\r\n if (!fs_1.default.existsSync('target')) {\r\n fs_1.default.mkdirSync('target');\r\n }\r\n if (!fs_1.default.existsSync('target/parasoft')) {\r\n fs_1.default.mkdirSync('target/parasoft');\r\n }\r\n if (!fs_1.default.existsSync('target/parasoft/soatest')) {\r\n fs_1.default.mkdirSync('target/parasoft/soatest');\r\n }\r\n if (!fs_1.default.existsSync(`target/parasoft/soatest/${reportId}`)) {\r\n fs_1.default.mkdirSync(`target/parasoft/soatest/${reportId}`);\r\n }\r\n try {\r\n fs_1.default.appendFileSync(`target/parasoft/soatest/${reportId}/report.xml`, fileData);\r\n }\r\n catch (error) {\r\n core.error(`Error writing report.xml: ${error.message}`);\r\n }\r\n return '';\r\n }).then(() => {\r\n core.info(` Saved XML report: target/parasoft/soatest/${reportId}/report.xml`);\r\n core.info(` View report in CTP: ${this.ctpService.getBaseURL()}/testreport/${reportId}/report.html`);\r\n this.uploadFile(reportId).then(response => {\r\n core.debug(` report.xml file upload successful: ${response}`);\r\n def.resolve();\r\n }).catch((error) => {\r\n core.error(`Error while uploading report.xml file: ${error}`);\r\n def.reject(error);\r\n });\r\n });\r\n return def.promise;\r\n }\r\n injectMetaData(source, index, environmentName) {\r\n let dtpSessionTag = this.metaData.dtpSessionTag;\r\n if (environmentName) {\r\n if (dtpSessionTag == null) {\r\n dtpSessionTag = \"\";\r\n }\r\n if (dtpSessionTag.length != 0) {\r\n dtpSessionTag += '-';\r\n }\r\n dtpSessionTag += environmentName;\r\n }\r\n else if ((dtpSessionTag != null) && dtpSessionTag.length !== 0 && (index > 0)) {\r\n dtpSessionTag += `-${index + 1}`; // unique session tag in DTP for each report\r\n }\r\n source = this.replaceAttributeValue(source, 'project', this.metaData.dtpProject);\r\n source = this.replaceAttributeValue(source, 'buildId', this.metaData.dtpBuildId);\r\n source = this.replaceAttributeValue(source, 'tag', dtpSessionTag);\r\n return this.replaceAttributeValue(source, 'execEnv', environmentName);\r\n }\r\n replaceAttributeValue(source, attribute, newValue) {\r\n let regEx = new RegExp(attribute + '\\=\\\"[^\"]*\\\"');\r\n return source.replace(regEx, attribute + '=\"' + newValue + '\"');\r\n }\r\n}\r\nexports.ReportPublisher = ReportPublisher;\r\n","\"use strict\";\r\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n}));\r\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n});\r\nvar __importStar = (this && this.__importStar) || function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n};\r\nvar __importDefault = (this && this.__importDefault) || function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n};\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.WebService = void 0;\r\nconst core = __importStar(require(\"@actions/core\"));\r\nconst http_1 = __importDefault(require(\"http\"));\r\nconst https_1 = __importDefault(require(\"https\"));\r\nconst url_1 = __importDefault(require(\"url\"));\r\nconst q_1 = __importDefault(require(\"q\"));\r\nclass WebService {\r\n constructor(endpoint, context, authorization) {\r\n this.baseURL = url_1.default.parse(endpoint);\r\n if (this.baseURL.path === '/') {\r\n this.baseURL.path += context;\r\n }\r\n else if (this.baseURL.path === `/${context}/`) {\r\n this.baseURL.path = `/${context}`;\r\n }\r\n this.authorization = authorization;\r\n this.protocol = this.baseURL.protocol === 'https:' ? https_1.default : http_1.default;\r\n this.protocolLabel = this.baseURL.protocol || 'http:';\r\n }\r\n performTest(path) {\r\n return new Promise((resolve, reject) => {\r\n resolve('value');\r\n });\r\n }\r\n performGET(path, handler, dataHandler) {\r\n let def = q_1.default.defer();\r\n let promise = new Promise((resolve, reject) => {\r\n def.resolve = resolve;\r\n def.reject = reject;\r\n });\r\n let options = {\r\n host: this.baseURL.hostname,\r\n path: this.baseURL.path + path,\r\n auth: undefined,\r\n headers: {\r\n 'Accept': 'application/json'\r\n }\r\n };\r\n if (this.baseURL.port) {\r\n options.port = parseInt(this.baseURL.port);\r\n }\r\n if (this.protocolLabel === 'https:') {\r\n options['rejectUnauthorized'] = false;\r\n options['agent'] = false;\r\n }\r\n if (this.authorization && this.authorization['username']) {\r\n options.auth = this.authorization['username'] + ':' + this.authorization['password'];\r\n }\r\n core.debug(`GET ${this.protocolLabel}//${options.host}${options.port ? `:${options.port}` : \"\"}${options.path}`);\r\n let responseString = \"\";\r\n this.protocol.get(options, (res) => {\r\n res.setEncoding('utf8');\r\n res.on('data', (chunk) => {\r\n if (dataHandler) {\r\n responseString += dataHandler(chunk);\r\n }\r\n else {\r\n responseString += chunk;\r\n }\r\n });\r\n res.on('end', () => {\r\n if (res.statusCode === 302) {\r\n let redirectPath = res.headers.location;\r\n if (redirectPath.startsWith(this.baseURL.path)) {\r\n redirectPath = redirectPath.substring(3);\r\n }\r\n core.debug(' redirect to \"' + redirectPath + '\"');\r\n this.performGET(redirectPath, handler, dataHandler).then(response => def.resolve(response));\r\n }\r\n else if (handler) {\r\n handler(res, def, responseString);\r\n }\r\n else {\r\n core.debug(` response ${res.statusCode}: ${responseString}`);\r\n let responseObject = JSON.parse(responseString);\r\n def.resolve(responseObject);\r\n }\r\n });\r\n }).on('error', (e) => {\r\n def.reject(e);\r\n });\r\n return promise;\r\n }\r\n getBaseURL() {\r\n return this.protocolLabel + '//' + this.baseURL.hostname +\r\n (this.baseURL.port ? ':' + this.baseURL.port : \"\") + this.baseURL.path;\r\n }\r\n performPUT(path, data) {\r\n return this.performRequest(path, data, 'PUT');\r\n }\r\n performPOST(path, data) {\r\n return this.performRequest(path, data, 'POST');\r\n }\r\n performRequest(path, data, method) {\r\n let def = q_1.default.defer();\r\n let promise = new Promise((resolve, reject) => {\r\n def.resolve = resolve;\r\n def.reject = reject;\r\n });\r\n let options = {\r\n host: this.baseURL.hostname,\r\n path: this.baseURL.path + path,\r\n method: method,\r\n auth: undefined,\r\n headers: {\r\n 'Accept': 'application/json',\r\n 'Content-Type': 'application/json'\r\n }\r\n };\r\n if (this.baseURL.port) {\r\n options.port = parseInt(this.baseURL.port);\r\n }\r\n if (this.protocolLabel === 'https:') {\r\n options['rejectUnauthorized'] = false;\r\n options['agent'] = false;\r\n }\r\n if (this.authorization && this.authorization['username']) {\r\n options.auth = this.authorization['username'] + ':' + this.authorization['password'];\r\n }\r\n core.debug(`${method} ${this.protocolLabel}//${options.host}${options.port ? `:${options.port}` : \"\"}${options.path}`);\r\n let responseString = \"\";\r\n let req = this.protocol.request(options, (res) => {\r\n res.setEncoding('utf8');\r\n res.on('data', (chunk) => {\r\n responseString += chunk;\r\n });\r\n res.on('end', () => {\r\n core.debug(` response ${res.statusCode}: ${responseString}`);\r\n let responseObject = JSON.parse(responseString);\r\n def.resolve(responseObject);\r\n });\r\n }).on('error', (e) => {\r\n def.reject(e);\r\n });\r\n req.write(JSON.stringify(data));\r\n req.end();\r\n return promise;\r\n }\r\n}\r\nexports.WebService = WebService;\r\n","\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.issue = exports.issueCommand = void 0;\nconst os = __importStar(require(\"os\"));\nconst utils_1 = require(\"./utils\");\n/**\n * Commands\n *\n * Command Format:\n * ::name key=value,key=value::message\n *\n * Examples:\n * ::warning::This is the message\n * ::set-env name=MY_VAR::some value\n */\nfunction issueCommand(command, properties, message) {\n const cmd = new Command(command, properties, message);\n process.stdout.write(cmd.toString() + os.EOL);\n}\nexports.issueCommand = issueCommand;\nfunction issue(name, message = '') {\n issueCommand(name, {}, message);\n}\nexports.issue = issue;\nconst CMD_STRING = '::';\nclass Command {\n constructor(command, properties, message) {\n if (!command) {\n command = 'missing.command';\n }\n this.command = command;\n this.properties = properties;\n this.message = message;\n }\n toString() {\n let cmdStr = CMD_STRING + this.command;\n if (this.properties && Object.keys(this.properties).length > 0) {\n cmdStr += ' ';\n let first = true;\n for (const key in this.properties) {\n if (this.properties.hasOwnProperty(key)) {\n const val = this.properties[key];\n if (val) {\n if (first) {\n first = false;\n }\n else {\n cmdStr += ',';\n }\n cmdStr += `${key}=${escapeProperty(val)}`;\n }\n }\n }\n }\n cmdStr += `${CMD_STRING}${escapeData(this.message)}`;\n return cmdStr;\n }\n}\nfunction escapeData(s) {\n return utils_1.toCommandValue(s)\n .replace(/%/g, '%25')\n .replace(/\\r/g, '%0D')\n .replace(/\\n/g, '%0A');\n}\nfunction escapeProperty(s) {\n return utils_1.toCommandValue(s)\n .replace(/%/g, '%25')\n .replace(/\\r/g, '%0D')\n .replace(/\\n/g, '%0A')\n .replace(/:/g, '%3A')\n .replace(/,/g, '%2C');\n}\n//# sourceMappingURL=command.js.map","\"use strict\";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.getState = exports.saveState = exports.group = exports.endGroup = exports.startGroup = exports.info = exports.warning = exports.error = exports.debug = exports.isDebug = exports.setFailed = exports.setCommandEcho = exports.setOutput = exports.getBooleanInput = exports.getInput = exports.addPath = exports.setSecret = exports.exportVariable = exports.ExitCode = void 0;\nconst command_1 = require(\"./command\");\nconst file_command_1 = require(\"./file-command\");\nconst utils_1 = require(\"./utils\");\nconst os = __importStar(require(\"os\"));\nconst path = __importStar(require(\"path\"));\n/**\n * The code to exit an action\n */\nvar ExitCode;\n(function (ExitCode) {\n /**\n * A code indicating that the action was successful\n */\n ExitCode[ExitCode[\"Success\"] = 0] = \"Success\";\n /**\n * A code indicating that the action was a failure\n */\n ExitCode[ExitCode[\"Failure\"] = 1] = \"Failure\";\n})(ExitCode = exports.ExitCode || (exports.ExitCode = {}));\n//-----------------------------------------------------------------------\n// Variables\n//-----------------------------------------------------------------------\n/**\n * Sets env variable for this action and future actions in the job\n * @param name the name of the variable to set\n * @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction exportVariable(name, val) {\n const convertedVal = utils_1.toCommandValue(val);\n process.env[name] = convertedVal;\n const filePath = process.env['GITHUB_ENV'] || '';\n if (filePath) {\n const delimiter = '_GitHubActionsFileCommandDelimeter_';\n const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`;\n file_command_1.issueCommand('ENV', commandValue);\n }\n else {\n command_1.issueCommand('set-env', { name }, convertedVal);\n }\n}\nexports.exportVariable = exportVariable;\n/**\n * Registers a secret which will get masked from logs\n * @param secret value of the secret\n */\nfunction setSecret(secret) {\n command_1.issueCommand('add-mask', {}, secret);\n}\nexports.setSecret = setSecret;\n/**\n * Prepends inputPath to the PATH (for this action and future actions)\n * @param inputPath\n */\nfunction addPath(inputPath) {\n const filePath = process.env['GITHUB_PATH'] || '';\n if (filePath) {\n file_command_1.issueCommand('PATH', inputPath);\n }\n else {\n command_1.issueCommand('add-path', {}, inputPath);\n }\n process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;\n}\nexports.addPath = addPath;\n/**\n * Gets the value of an input.\n * Unless trimWhitespace is set to false in InputOptions, the value is also trimmed.\n * Returns an empty string if the value is not defined.\n *\n * @param name name of the input to get\n * @param options optional. See InputOptions.\n * @returns string\n */\nfunction getInput(name, options) {\n const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';\n if (options && options.required && !val) {\n throw new Error(`Input required and not supplied: ${name}`);\n }\n if (options && options.trimWhitespace === false) {\n return val;\n }\n return val.trim();\n}\nexports.getInput = getInput;\n/**\n * Gets the input value of the boolean type in the YAML 1.2 \"core schema\" specification.\n * Support boolean input list: `true | True | TRUE | false | False | FALSE` .\n * The return value is also in boolean type.\n * ref: https://yaml.org/spec/1.2/spec.html#id2804923\n *\n * @param name name of the input to get\n * @param options optional. See InputOptions.\n * @returns boolean\n */\nfunction getBooleanInput(name, options) {\n const trueValue = ['true', 'True', 'TRUE'];\n const falseValue = ['false', 'False', 'FALSE'];\n const val = getInput(name, options);\n if (trueValue.includes(val))\n return true;\n if (falseValue.includes(val))\n return false;\n throw new TypeError(`Input does not meet YAML 1.2 \"Core Schema\" specification: ${name}\\n` +\n `Support boolean input list: \\`true | True | TRUE | false | False | FALSE\\``);\n}\nexports.getBooleanInput = getBooleanInput;\n/**\n * Sets the value of an output.\n *\n * @param name name of the output to set\n * @param value value to store. Non-string values will be converted to a string via JSON.stringify\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction setOutput(name, value) {\n process.stdout.write(os.EOL);\n command_1.issueCommand('set-output', { name }, value);\n}\nexports.setOutput = setOutput;\n/**\n * Enables or disables the echoing of commands into stdout for the rest of the step.\n * Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.\n *\n */\nfunction setCommandEcho(enabled) {\n command_1.issue('echo', enabled ? 'on' : 'off');\n}\nexports.setCommandEcho = setCommandEcho;\n//-----------------------------------------------------------------------\n// Results\n//-----------------------------------------------------------------------\n/**\n * Sets the action status to failed.\n * When the action exits it will be with an exit code of 1\n * @param message add error issue message\n */\nfunction setFailed(message) {\n process.exitCode = ExitCode.Failure;\n error(message);\n}\nexports.setFailed = setFailed;\n//-----------------------------------------------------------------------\n// Logging Commands\n//-----------------------------------------------------------------------\n/**\n * Gets whether Actions Step Debug is on or not\n */\nfunction isDebug() {\n return process.env['RUNNER_DEBUG'] === '1';\n}\nexports.isDebug = isDebug;\n/**\n * Writes debug message to user log\n * @param message debug message\n */\nfunction debug(message) {\n command_1.issueCommand('debug', {}, message);\n}\nexports.debug = debug;\n/**\n * Adds an error issue\n * @param message error issue message. Errors will be converted to string via toString()\n */\nfunction error(message) {\n command_1.issue('error', message instanceof Error ? message.toString() : message);\n}\nexports.error = error;\n/**\n * Adds an warning issue\n * @param message warning issue message. Errors will be converted to string via toString()\n */\nfunction warning(message) {\n command_1.issue('warning', message instanceof Error ? message.toString() : message);\n}\nexports.warning = warning;\n/**\n * Writes info to log with console.log.\n * @param message info message\n */\nfunction info(message) {\n process.stdout.write(message + os.EOL);\n}\nexports.info = info;\n/**\n * Begin an output group.\n *\n * Output until the next `groupEnd` will be foldable in this group\n *\n * @param name The name of the output group\n */\nfunction startGroup(name) {\n command_1.issue('group', name);\n}\nexports.startGroup = startGroup;\n/**\n * End an output group.\n */\nfunction endGroup() {\n command_1.issue('endgroup');\n}\nexports.endGroup = endGroup;\n/**\n * Wrap an asynchronous function call in a group.\n *\n * Returns the same type as the function itself.\n *\n * @param name The name of the group\n * @param fn The function to wrap in the group\n */\nfunction group(name, fn) {\n return __awaiter(this, void 0, void 0, function* () {\n startGroup(name);\n let result;\n try {\n result = yield fn();\n }\n finally {\n endGroup();\n }\n return result;\n });\n}\nexports.group = group;\n//-----------------------------------------------------------------------\n// Wrapper action state\n//-----------------------------------------------------------------------\n/**\n * Saves state for current action, the state can only be retrieved by this action's post job execution.\n *\n * @param name name of the state to store\n * @param value value to store. Non-string values will be converted to a string via JSON.stringify\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction saveState(name, value) {\n command_1.issueCommand('save-state', { name }, value);\n}\nexports.saveState = saveState;\n/**\n * Gets the value of an state set by this action's main execution.\n *\n * @param name name of the state to get\n * @returns string\n */\nfunction getState(name) {\n return process.env[`STATE_${name}`] || '';\n}\nexports.getState = getState;\n//# sourceMappingURL=core.js.map","\"use strict\";\n// For internal use, subject to change.\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\n}) : function(o, v) {\n o[\"default\"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.issueCommand = void 0;\n// We use any as a valid input type\n/* eslint-disable @typescript-eslint/no-explicit-any */\nconst fs = __importStar(require(\"fs\"));\nconst os = __importStar(require(\"os\"));\nconst utils_1 = require(\"./utils\");\nfunction issueCommand(command, message) {\n const filePath = process.env[`GITHUB_${command}`];\n if (!filePath) {\n throw new Error(`Unable to find environment variable for file command ${command}`);\n }\n if (!fs.existsSync(filePath)) {\n throw new Error(`Missing file at path: ${filePath}`);\n }\n fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, {\n encoding: 'utf8'\n });\n}\nexports.issueCommand = issueCommand;\n//# sourceMappingURL=file-command.js.map","\"use strict\";\n// We use any as a valid input type\n/* eslint-disable @typescript-eslint/no-explicit-any */\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.toCommandValue = void 0;\n/**\n * Sanitizes an input into a string so it can be passed into issueCommand safely\n * @param input input to sanitize into a string\n */\nfunction toCommandValue(input) {\n if (input === null || input === undefined) {\n return '';\n }\n else if (typeof input === 'string' || input instanceof String) {\n return input;\n }\n return JSON.stringify(input);\n}\nexports.toCommandValue = toCommandValue;\n//# sourceMappingURL=utils.js.map","module.exports =\n{\n parallel : require('./parallel.js'),\n serial : require('./serial.js'),\n serialOrdered : require('./serialOrdered.js')\n};\n","// API\nmodule.exports = abort;\n\n/**\n * Aborts leftover active jobs\n *\n * @param {object} state - current state object\n */\nfunction abort(state)\n{\n Object.keys(state.jobs).forEach(clean.bind(state));\n\n // reset leftover jobs\n state.jobs = {};\n}\n\n/**\n * Cleans up leftover job by invoking abort function for the provided job id\n *\n * @this state\n * @param {string|number} key - job id to abort\n */\nfunction clean(key)\n{\n if (typeof this.jobs[key] == 'function')\n {\n this.jobs[key]();\n }\n}\n","var defer = require('./defer.js');\n\n// API\nmodule.exports = async;\n\n/**\n * Runs provided callback asynchronously\n * even if callback itself is not\n *\n * @param {function} callback - callback to invoke\n * @returns {function} - augmented callback\n */\nfunction async(callback)\n{\n var isAsync = false;\n\n // check if async happened\n defer(function() { isAsync = true; });\n\n return function async_callback(err, result)\n {\n if (isAsync)\n {\n callback(err, result);\n }\n else\n {\n defer(function nextTick_callback()\n {\n callback(err, result);\n });\n }\n };\n}\n","module.exports = defer;\n\n/**\n * Runs provided function on next iteration of the event loop\n *\n * @param {function} fn - function to run\n */\nfunction defer(fn)\n{\n var nextTick = typeof setImmediate == 'function'\n ? setImmediate\n : (\n typeof process == 'object' && typeof process.nextTick == 'function'\n ? process.nextTick\n : null\n );\n\n if (nextTick)\n {\n nextTick(fn);\n }\n else\n {\n setTimeout(fn, 0);\n }\n}\n","var async = require('./async.js')\n , abort = require('./abort.js')\n ;\n\n// API\nmodule.exports = iterate;\n\n/**\n * Iterates over each job object\n *\n * @param {array|object} list - array or object (named list) to iterate over\n * @param {function} iterator - iterator to run\n * @param {object} state - current job status\n * @param {function} callback - invoked when all elements processed\n */\nfunction iterate(list, iterator, state, callback)\n{\n // store current index\n var key = state['keyedList'] ? state['keyedList'][state.index] : state.index;\n\n state.jobs[key] = runJob(iterator, key, list[key], function(error, output)\n {\n // don't repeat yourself\n // skip secondary callbacks\n if (!(key in state.jobs))\n {\n return;\n }\n\n // clean up jobs\n delete state.jobs[key];\n\n if (error)\n {\n // don't process rest of the results\n // stop still active jobs\n // and reset the list\n abort(state);\n }\n else\n {\n state.results[key] = output;\n }\n\n // return salvaged results\n callback(error, state.results);\n });\n}\n\n/**\n * Runs iterator over provided job element\n *\n * @param {function} iterator - iterator to invoke\n * @param {string|number} key - key/index of the element in the list of jobs\n * @param {mixed} item - job description\n * @param {function} callback - invoked after iterator is done with the job\n * @returns {function|mixed} - job abort function or something else\n */\nfunction runJob(iterator, key, item, callback)\n{\n var aborter;\n\n // allow shortcut if iterator expects only two arguments\n if (iterator.length == 2)\n {\n aborter = iterator(item, async(callback));\n }\n // otherwise go with full three arguments\n else\n {\n aborter = iterator(item, key, async(callback));\n }\n\n return aborter;\n}\n","// API\nmodule.exports = state;\n\n/**\n * Creates initial state object\n * for iteration over list\n *\n * @param {array|object} list - list to iterate over\n * @param {function|null} sortMethod - function to use for keys sort,\n * or `null` to keep them as is\n * @returns {object} - initial state object\n */\nfunction state(list, sortMethod)\n{\n var isNamedList = !Array.isArray(list)\n , initState =\n {\n index : 0,\n keyedList: isNamedList || sortMethod ? Object.keys(list) : null,\n jobs : {},\n results : isNamedList ? {} : [],\n size : isNamedList ? Object.keys(list).length : list.length\n }\n ;\n\n if (sortMethod)\n {\n // sort array keys based on it's values\n // sort object's keys just on own merit\n initState.keyedList.sort(isNamedList ? sortMethod : function(a, b)\n {\n return sortMethod(list[a], list[b]);\n });\n }\n\n return initState;\n}\n","var abort = require('./abort.js')\n , async = require('./async.js')\n ;\n\n// API\nmodule.exports = terminator;\n\n/**\n * Terminates jobs in the attached state context\n *\n * @this AsyncKitState#\n * @param {function} callback - final callback to invoke after termination\n */\nfunction terminator(callback)\n{\n if (!Object.keys(this.jobs).length)\n {\n return;\n }\n\n // fast forward iteration index\n this.index = this.size;\n\n // abort jobs\n abort(this);\n\n // send back results we have so far\n async(callback)(null, this.results);\n}\n","var iterate = require('./lib/iterate.js')\n , initState = require('./lib/state.js')\n , terminator = require('./lib/terminator.js')\n ;\n\n// Public API\nmodule.exports = parallel;\n\n/**\n * Runs iterator over provided array elements in parallel\n *\n * @param {array|object} list - array or object (named list) to iterate over\n * @param {function} iterator - iterator to run\n * @param {function} callback - invoked when all elements processed\n * @returns {function} - jobs terminator\n */\nfunction parallel(list, iterator, callback)\n{\n var state = initState(list);\n\n while (state.index < (state['keyedList'] || list).length)\n {\n iterate(list, iterator, state, function(error, result)\n {\n if (error)\n {\n callback(error, result);\n return;\n }\n\n // looks like it's the last one\n if (Object.keys(state.jobs).length === 0)\n {\n callback(null, state.results);\n return;\n }\n });\n\n state.index++;\n }\n\n return terminator.bind(state, callback);\n}\n","var serialOrdered = require('./serialOrdered.js');\n\n// Public API\nmodule.exports = serial;\n\n/**\n * Runs iterator over provided array elements in series\n *\n * @param {array|object} list - array or object (named list) to iterate over\n * @param {function} iterator - iterator to run\n * @param {function} callback - invoked when all elements processed\n * @returns {function} - jobs terminator\n */\nfunction serial(list, iterator, callback)\n{\n return serialOrdered(list, iterator, null, callback);\n}\n","var iterate = require('./lib/iterate.js')\n , initState = require('./lib/state.js')\n , terminator = require('./lib/terminator.js')\n ;\n\n// Public API\nmodule.exports = serialOrdered;\n// sorting helpers\nmodule.exports.ascending = ascending;\nmodule.exports.descending = descending;\n\n/**\n * Runs iterator over provided sorted array elements in series\n *\n * @param {array|object} list - array or object (named list) to iterate over\n * @param {function} iterator - iterator to run\n * @param {function} sortMethod - custom sort function\n * @param {function} callback - invoked when all elements processed\n * @returns {function} - jobs terminator\n */\nfunction serialOrdered(list, iterator, sortMethod, callback)\n{\n var state = initState(list, sortMethod);\n\n iterate(list, iterator, state, function iteratorHandler(error, result)\n {\n if (error)\n {\n callback(error, result);\n return;\n }\n\n state.index++;\n\n // are we there yet?\n if (state.index < (state['keyedList'] || list).length)\n {\n iterate(list, iterator, state, iteratorHandler);\n return;\n }\n\n // done here\n callback(null, state.results);\n });\n\n return terminator.bind(state, callback);\n}\n\n/*\n * -- Sort methods\n */\n\n/**\n * sort helper to sort array elements in ascending order\n *\n * @param {mixed} a - an item to compare\n * @param {mixed} b - an item to compare\n * @returns {number} - comparison result\n */\nfunction ascending(a, b)\n{\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/**\n * sort helper to sort array elements in descending order\n *\n * @param {mixed} a - an item to compare\n * @param {mixed} b - an item to compare\n * @returns {number} - comparison result\n */\nfunction descending(a, b)\n{\n return -1 * ascending(a, b);\n}\n","var util = require('util');\nvar Stream = require('stream').Stream;\nvar DelayedStream = require('delayed-stream');\n\nmodule.exports = CombinedStream;\nfunction CombinedStream() {\n this.writable = false;\n this.readable = true;\n this.dataSize = 0;\n this.maxDataSize = 2 * 1024 * 1024;\n this.pauseStreams = true;\n\n this._released = false;\n this._streams = [];\n this._currentStream = null;\n this._insideLoop = false;\n this._pendingNext = false;\n}\nutil.inherits(CombinedStream, Stream);\n\nCombinedStream.create = function(options) {\n var combinedStream = new this();\n\n options = options || {};\n for (var option in options) {\n combinedStream[option] = options[option];\n }\n\n return combinedStream;\n};\n\nCombinedStream.isStreamLike = function(stream) {\n return (typeof stream !== 'function')\n && (typeof stream !== 'string')\n && (typeof stream !== 'boolean')\n && (typeof stream !== 'number')\n && (!Buffer.isBuffer(stream));\n};\n\nCombinedStream.prototype.append = function(stream) {\n var isStreamLike = CombinedStream.isStreamLike(stream);\n\n if (isStreamLike) {\n if (!(stream instanceof DelayedStream)) {\n var newStream = DelayedStream.create(stream, {\n maxDataSize: Infinity,\n pauseStream: this.pauseStreams,\n });\n stream.on('data', this._checkDataSize.bind(this));\n stream = newStream;\n }\n\n this._handleErrors(stream);\n\n if (this.pauseStreams) {\n stream.pause();\n }\n }\n\n this._streams.push(stream);\n return this;\n};\n\nCombinedStream.prototype.pipe = function(dest, options) {\n Stream.prototype.pipe.call(this, dest, options);\n this.resume();\n return dest;\n};\n\nCombinedStream.prototype._getNext = function() {\n this._currentStream = null;\n\n if (this._insideLoop) {\n this._pendingNext = true;\n return; // defer call\n }\n\n this._insideLoop = true;\n try {\n do {\n this._pendingNext = false;\n this._realGetNext();\n } while (this._pendingNext);\n } finally {\n this._insideLoop = false;\n }\n};\n\nCombinedStream.prototype._realGetNext = function() {\n var stream = this._streams.shift();\n\n\n if (typeof stream == 'undefined') {\n this.end();\n return;\n }\n\n if (typeof stream !== 'function') {\n this._pipeNext(stream);\n return;\n }\n\n var getStream = stream;\n getStream(function(stream) {\n var isStreamLike = CombinedStream.isStreamLike(stream);\n if (isStreamLike) {\n stream.on('data', this._checkDataSize.bind(this));\n this._handleErrors(stream);\n }\n\n this._pipeNext(stream);\n }.bind(this));\n};\n\nCombinedStream.prototype._pipeNext = function(stream) {\n this._currentStream = stream;\n\n var isStreamLike = CombinedStream.isStreamLike(stream);\n if (isStreamLike) {\n stream.on('end', this._getNext.bind(this));\n stream.pipe(this, {end: false});\n return;\n }\n\n var value = stream;\n this.write(value);\n this._getNext();\n};\n\nCombinedStream.prototype._handleErrors = function(stream) {\n var self = this;\n stream.on('error', function(err) {\n self._emitError(err);\n });\n};\n\nCombinedStream.prototype.write = function(data) {\n this.emit('data', data);\n};\n\nCombinedStream.prototype.pause = function() {\n if (!this.pauseStreams) {\n return;\n }\n\n if(this.pauseStreams && this._currentStream && typeof(this._currentStream.pause) == 'function') this._currentStream.pause();\n this.emit('pause');\n};\n\nCombinedStream.prototype.resume = function() {\n if (!this._released) {\n this._released = true;\n this.writable = true;\n this._getNext();\n }\n\n if(this.pauseStreams && this._currentStream && typeof(this._currentStream.resume) == 'function') this._currentStream.resume();\n this.emit('resume');\n};\n\nCombinedStream.prototype.end = function() {\n this._reset();\n this.emit('end');\n};\n\nCombinedStream.prototype.destroy = function() {\n this._reset();\n this.emit('close');\n};\n\nCombinedStream.prototype._reset = function() {\n this.writable = false;\n this._streams = [];\n this._currentStream = null;\n};\n\nCombinedStream.prototype._checkDataSize = function() {\n this._updateDataSize();\n if (this.dataSize <= this.maxDataSize) {\n return;\n }\n\n var message =\n 'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.';\n this._emitError(new Error(message));\n};\n\nCombinedStream.prototype._updateDataSize = function() {\n this.dataSize = 0;\n\n var self = this;\n this._streams.forEach(function(stream) {\n if (!stream.dataSize) {\n return;\n }\n\n self.dataSize += stream.dataSize;\n });\n\n if (this._currentStream && this._currentStream.dataSize) {\n this.dataSize += this._currentStream.dataSize;\n }\n};\n\nCombinedStream.prototype._emitError = function(err) {\n this._reset();\n this.emit('error', err);\n};\n","var Stream = require('stream').Stream;\nvar util = require('util');\n\nmodule.exports = DelayedStream;\nfunction DelayedStream() {\n this.source = null;\n this.dataSize = 0;\n this.maxDataSize = 1024 * 1024;\n this.pauseStream = true;\n\n this._maxDataSizeExceeded = false;\n this._released = false;\n this._bufferedEvents = [];\n}\nutil.inherits(DelayedStream, Stream);\n\nDelayedStream.create = function(source, options) {\n var delayedStream = new this();\n\n options = options || {};\n for (var option in options) {\n delayedStream[option] = options[option];\n }\n\n delayedStream.source = source;\n\n var realEmit = source.emit;\n source.emit = function() {\n delayedStream._handleEmit(arguments);\n return realEmit.apply(source, arguments);\n };\n\n source.on('error', function() {});\n if (delayedStream.pauseStream) {\n source.pause();\n }\n\n return delayedStream;\n};\n\nObject.defineProperty(DelayedStream.prototype, 'readable', {\n configurable: true,\n enumerable: true,\n get: function() {\n return this.source.readable;\n }\n});\n\nDelayedStream.prototype.setEncoding = function() {\n return this.source.setEncoding.apply(this.source, arguments);\n};\n\nDelayedStream.prototype.resume = function() {\n if (!this._released) {\n this.release();\n }\n\n this.source.resume();\n};\n\nDelayedStream.prototype.pause = function() {\n this.source.pause();\n};\n\nDelayedStream.prototype.release = function() {\n this._released = true;\n\n this._bufferedEvents.forEach(function(args) {\n this.emit.apply(this, args);\n }.bind(this));\n this._bufferedEvents = [];\n};\n\nDelayedStream.prototype.pipe = function() {\n var r = Stream.prototype.pipe.apply(this, arguments);\n this.resume();\n return r;\n};\n\nDelayedStream.prototype._handleEmit = function(args) {\n if (this._released) {\n this.emit.apply(this, args);\n return;\n }\n\n if (args[0] === 'data') {\n this.dataSize += args[1].length;\n this._checkIfMaxDataSizeExceeded();\n }\n\n this._bufferedEvents.push(args);\n};\n\nDelayedStream.prototype._checkIfMaxDataSizeExceeded = function() {\n if (this._maxDataSizeExceeded) {\n return;\n }\n\n if (this.dataSize <= this.maxDataSize) {\n return;\n }\n\n this._maxDataSizeExceeded = true;\n var message =\n 'DelayedStream#maxDataSize of ' + this.maxDataSize + ' bytes exceeded.'\n this.emit('error', new Error(message));\n};\n","var CombinedStream = require('combined-stream');\nvar util = require('util');\nvar path = require('path');\nvar http = require('http');\nvar https = require('https');\nvar parseUrl = require('url').parse;\nvar fs = require('fs');\nvar Stream = require('stream').Stream;\nvar mime = require('mime-types');\nvar asynckit = require('asynckit');\nvar populate = require('./populate.js');\n\n// Public API\nmodule.exports = FormData;\n\n// make it a Stream\nutil.inherits(FormData, CombinedStream);\n\n/**\n * Create readable \"multipart/form-data\" streams.\n * Can be used to submit forms\n * and file uploads to other web applications.\n *\n * @constructor\n * @param {Object} options - Properties to be added/overriden for FormData and CombinedStream\n */\nfunction FormData(options) {\n if (!(this instanceof FormData)) {\n return new FormData(options);\n }\n\n this._overheadLength = 0;\n this._valueLength = 0;\n this._valuesToMeasure = [];\n\n CombinedStream.call(this);\n\n options = options || {};\n for (var option in options) {\n this[option] = options[option];\n }\n}\n\nFormData.LINE_BREAK = '\\r\\n';\nFormData.DEFAULT_CONTENT_TYPE = 'application/octet-stream';\n\nFormData.prototype.append = function(field, value, options) {\n\n options = options || {};\n\n // allow filename as single option\n if (typeof options == 'string') {\n options = {filename: options};\n }\n\n var append = CombinedStream.prototype.append.bind(this);\n\n // all that streamy business can't handle numbers\n if (typeof value == 'number') {\n value = '' + value;\n }\n\n // https://github.com/felixge/node-form-data/issues/38\n if (util.isArray(value)) {\n // Please convert your array into string\n // the way web server expects it\n this._error(new Error('Arrays are not supported.'));\n return;\n }\n\n var header = this._multiPartHeader(field, value, options);\n var footer = this._multiPartFooter();\n\n append(header);\n append(value);\n append(footer);\n\n // pass along options.knownLength\n this._trackLength(header, value, options);\n};\n\nFormData.prototype._trackLength = function(header, value, options) {\n var valueLength = 0;\n\n // used w/ getLengthSync(), when length is known.\n // e.g. for streaming directly from a remote server,\n // w/ a known file a size, and not wanting to wait for\n // incoming file to finish to get its size.\n if (options.knownLength != null) {\n valueLength += +options.knownLength;\n } else if (Buffer.isBuffer(value)) {\n valueLength = value.length;\n } else if (typeof value === 'string') {\n valueLength = Buffer.byteLength(value);\n }\n\n this._valueLength += valueLength;\n\n // @check why add CRLF? does this account for custom/multiple CRLFs?\n this._overheadLength +=\n Buffer.byteLength(header) +\n FormData.LINE_BREAK.length;\n\n // empty or either doesn't have path or not an http response or not a stream\n if (!value || ( !value.path && !(value.readable && value.hasOwnProperty('httpVersion')) && !(value instanceof Stream))) {\n return;\n }\n\n // no need to bother with the length\n if (!options.knownLength) {\n this._valuesToMeasure.push(value);\n }\n};\n\nFormData.prototype._lengthRetriever = function(value, callback) {\n\n if (value.hasOwnProperty('fd')) {\n\n // take read range into a account\n // `end` = Infinity –> read file till the end\n //\n // TODO: Looks like there is bug in Node fs.createReadStream\n // it doesn't respect `end` options without `start` options\n // Fix it when node fixes it.\n // https://github.com/joyent/node/issues/7819\n if (value.end != undefined && value.end != Infinity && value.start != undefined) {\n\n // when end specified\n // no need to calculate range\n // inclusive, starts with 0\n callback(null, value.end + 1 - (value.start ? value.start : 0));\n\n // not that fast snoopy\n } else {\n // still need to fetch file size from fs\n fs.stat(value.path, function(err, stat) {\n\n var fileSize;\n\n if (err) {\n callback(err);\n return;\n }\n\n // update final size based on the range options\n fileSize = stat.size - (value.start ? value.start : 0);\n callback(null, fileSize);\n });\n }\n\n // or http response\n } else if (value.hasOwnProperty('httpVersion')) {\n callback(null, +value.headers['content-length']);\n\n // or request stream http://github.com/mikeal/request\n } else if (value.hasOwnProperty('httpModule')) {\n // wait till response come back\n value.on('response', function(response) {\n value.pause();\n callback(null, +response.headers['content-length']);\n });\n value.resume();\n\n // something else\n } else {\n callback('Unknown stream');\n }\n};\n\nFormData.prototype._multiPartHeader = function(field, value, options) {\n // custom header specified (as string)?\n // it becomes responsible for boundary\n // (e.g. to handle extra CRLFs on .NET servers)\n if (typeof options.header == 'string') {\n return options.header;\n }\n\n var contentDisposition = this._getContentDisposition(value, options);\n var contentType = this._getContentType(value, options);\n\n var contents = '';\n var headers = {\n // add custom disposition as third element or keep it two elements if not\n 'Content-Disposition': ['form-data', 'name=\"' + field + '\"'].concat(contentDisposition || []),\n // if no content type. allow it to be empty array\n 'Content-Type': [].concat(contentType || [])\n };\n\n // allow custom headers.\n if (typeof options.header == 'object') {\n populate(headers, options.header);\n }\n\n var header;\n for (var prop in headers) {\n if (!headers.hasOwnProperty(prop)) continue;\n header = headers[prop];\n\n // skip nullish headers.\n if (header == null) {\n continue;\n }\n\n // convert all headers to arrays.\n if (!Array.isArray(header)) {\n header = [header];\n }\n\n // add non-empty headers.\n if (header.length) {\n contents += prop + ': ' + header.join('; ') + FormData.LINE_BREAK;\n }\n }\n\n return '--' + this.getBoundary() + FormData.LINE_BREAK + contents + FormData.LINE_BREAK;\n};\n\nFormData.prototype._getContentDisposition = function(value, options) {\n\n var filename\n , contentDisposition\n ;\n\n if (typeof options.filepath === 'string') {\n // custom filepath for relative paths\n filename = path.normalize(options.filepath).replace(/\\\\/g, '/');\n } else if (options.filename || value.name || value.path) {\n // custom filename take precedence\n // formidable and the browser add a name property\n // fs- and request- streams have path property\n filename = path.basename(options.filename || value.name || value.path);\n } else if (value.readable && value.hasOwnProperty('httpVersion')) {\n // or try http response\n filename = path.basename(value.client._httpMessage.path || '');\n }\n\n if (filename) {\n contentDisposition = 'filename=\"' + filename + '\"';\n }\n\n return contentDisposition;\n};\n\nFormData.prototype._getContentType = function(value, options) {\n\n // use custom content-type above all\n var contentType = options.contentType;\n\n // or try `name` from formidable, browser\n if (!contentType && value.name) {\n contentType = mime.lookup(value.name);\n }\n\n // or try `path` from fs-, request- streams\n if (!contentType && value.path) {\n contentType = mime.lookup(value.path);\n }\n\n // or if it's http-reponse\n if (!contentType && value.readable && value.hasOwnProperty('httpVersion')) {\n contentType = value.headers['content-type'];\n }\n\n // or guess it from the filepath or filename\n if (!contentType && (options.filepath || options.filename)) {\n contentType = mime.lookup(options.filepath || options.filename);\n }\n\n // fallback to the default content type if `value` is not simple value\n if (!contentType && typeof value == 'object') {\n contentType = FormData.DEFAULT_CONTENT_TYPE;\n }\n\n return contentType;\n};\n\nFormData.prototype._multiPartFooter = function() {\n return function(next) {\n var footer = FormData.LINE_BREAK;\n\n var lastPart = (this._streams.length === 0);\n if (lastPart) {\n footer += this._lastBoundary();\n }\n\n next(footer);\n }.bind(this);\n};\n\nFormData.prototype._lastBoundary = function() {\n return '--' + this.getBoundary() + '--' + FormData.LINE_BREAK;\n};\n\nFormData.prototype.getHeaders = function(userHeaders) {\n var header;\n var formHeaders = {\n 'content-type': 'multipart/form-data; boundary=' + this.getBoundary()\n };\n\n for (header in userHeaders) {\n if (userHeaders.hasOwnProperty(header)) {\n formHeaders[header.toLowerCase()] = userHeaders[header];\n }\n }\n\n return formHeaders;\n};\n\nFormData.prototype.setBoundary = function(boundary) {\n this._boundary = boundary;\n};\n\nFormData.prototype.getBoundary = function() {\n if (!this._boundary) {\n this._generateBoundary();\n }\n\n return this._boundary;\n};\n\nFormData.prototype.getBuffer = function() {\n var dataBuffer = new Buffer.alloc( 0 );\n var boundary = this.getBoundary();\n\n // Create the form content. Add Line breaks to the end of data.\n for (var i = 0, len = this._streams.length; i < len; i++) {\n if (typeof this._streams[i] !== 'function') {\n\n // Add content to the buffer.\n if(Buffer.isBuffer(this._streams[i])) {\n dataBuffer = Buffer.concat( [dataBuffer, this._streams[i]]);\n }else {\n dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(this._streams[i])]);\n }\n\n // Add break after content.\n if (typeof this._streams[i] !== 'string' || this._streams[i].substring( 2, boundary.length + 2 ) !== boundary) {\n dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(FormData.LINE_BREAK)] );\n }\n }\n }\n\n // Add the footer and return the Buffer object.\n return Buffer.concat( [dataBuffer, Buffer.from(this._lastBoundary())] );\n};\n\nFormData.prototype._generateBoundary = function() {\n // This generates a 50 character boundary similar to those used by Firefox.\n // They are optimized for boyer-moore parsing.\n var boundary = '--------------------------';\n for (var i = 0; i < 24; i++) {\n boundary += Math.floor(Math.random() * 10).toString(16);\n }\n\n this._boundary = boundary;\n};\n\n// Note: getLengthSync DOESN'T calculate streams length\n// As workaround one can calculate file size manually\n// and add it as knownLength option\nFormData.prototype.getLengthSync = function() {\n var knownLength = this._overheadLength + this._valueLength;\n\n // Don't get confused, there are 3 \"internal\" streams for each keyval pair\n // so it basically checks if there is any value added to the form\n if (this._streams.length) {\n knownLength += this._lastBoundary().length;\n }\n\n // https://github.com/form-data/form-data/issues/40\n if (!this.hasKnownLength()) {\n // Some async length retrievers are present\n // therefore synchronous length calculation is false.\n // Please use getLength(callback) to get proper length\n this._error(new Error('Cannot calculate proper length in synchronous way.'));\n }\n\n return knownLength;\n};\n\n// Public API to check if length of added values is known\n// https://github.com/form-data/form-data/issues/196\n// https://github.com/form-data/form-data/issues/262\nFormData.prototype.hasKnownLength = function() {\n var hasKnownLength = true;\n\n if (this._valuesToMeasure.length) {\n hasKnownLength = false;\n }\n\n return hasKnownLength;\n};\n\nFormData.prototype.getLength = function(cb) {\n var knownLength = this._overheadLength + this._valueLength;\n\n if (this._streams.length) {\n knownLength += this._lastBoundary().length;\n }\n\n if (!this._valuesToMeasure.length) {\n process.nextTick(cb.bind(this, null, knownLength));\n return;\n }\n\n asynckit.parallel(this._valuesToMeasure, this._lengthRetriever, function(err, values) {\n if (err) {\n cb(err);\n return;\n }\n\n values.forEach(function(length) {\n knownLength += length;\n });\n\n cb(null, knownLength);\n });\n};\n\nFormData.prototype.submit = function(params, cb) {\n var request\n , options\n , defaults = {method: 'post'}\n ;\n\n // parse provided url if it's string\n // or treat it as options object\n if (typeof params == 'string') {\n\n params = parseUrl(params);\n options = populate({\n port: params.port,\n path: params.pathname,\n host: params.hostname,\n protocol: params.protocol\n }, defaults);\n\n // use custom params\n } else {\n\n options = populate(params, defaults);\n // if no port provided use default one\n if (!options.port) {\n options.port = options.protocol == 'https:' ? 443 : 80;\n }\n }\n\n // put that good code in getHeaders to some use\n options.headers = this.getHeaders(params.headers);\n\n // https if specified, fallback to http in any other case\n if (options.protocol == 'https:') {\n request = https.request(options);\n } else {\n request = http.request(options);\n }\n\n // get content length and fire away\n this.getLength(function(err, length) {\n if (err && err !== 'Unknown stream') {\n this._error(err);\n return;\n }\n\n // add content length\n if (length) {\n request.setHeader('Content-Length', length);\n }\n\n this.pipe(request);\n if (cb) {\n var onResponse;\n\n var callback = function (error, responce) {\n request.removeListener('error', callback);\n request.removeListener('response', onResponse);\n\n return cb.call(this, error, responce);\n };\n\n onResponse = callback.bind(this, null);\n\n request.on('error', callback);\n request.on('response', onResponse);\n }\n }.bind(this));\n\n return request;\n};\n\nFormData.prototype._error = function(err) {\n if (!this.error) {\n this.error = err;\n this.pause();\n this.emit('error', err);\n }\n};\n\nFormData.prototype.toString = function () {\n return '[object FormData]';\n};\n","// populates missing values\nmodule.exports = function(dst, src) {\n\n Object.keys(src).forEach(function(prop)\n {\n dst[prop] = dst[prop] || src[prop];\n });\n\n return dst;\n};\n","/*!\n * mime-db\n * Copyright(c) 2014 Jonathan Ong\n * MIT Licensed\n */\n\n/**\n * Module exports.\n */\n\nmodule.exports = require('./db.json')\n","/*!\n * mime-types\n * Copyright(c) 2014 Jonathan Ong\n * Copyright(c) 2015 Douglas Christopher Wilson\n * MIT Licensed\n */\n\n'use strict'\n\n/**\n * Module dependencies.\n * @private\n */\n\nvar db = require('mime-db')\nvar extname = require('path').extname\n\n/**\n * Module variables.\n * @private\n */\n\nvar EXTRACT_TYPE_REGEXP = /^\\s*([^;\\s]*)(?:;|\\s|$)/\nvar TEXT_TYPE_REGEXP = /^text\\//i\n\n/**\n * Module exports.\n * @public\n */\n\nexports.charset = charset\nexports.charsets = { lookup: charset }\nexports.contentType = contentType\nexports.extension = extension\nexports.extensions = Object.create(null)\nexports.lookup = lookup\nexports.types = Object.create(null)\n\n// Populate the extensions/types maps\npopulateMaps(exports.extensions, exports.types)\n\n/**\n * Get the default charset for a MIME type.\n *\n * @param {string} type\n * @return {boolean|string}\n */\n\nfunction charset (type) {\n if (!type || typeof type !== 'string') {\n return false\n }\n\n // TODO: use media-typer\n var match = EXTRACT_TYPE_REGEXP.exec(type)\n var mime = match && db[match[1].toLowerCase()]\n\n if (mime && mime.charset) {\n return mime.charset\n }\n\n // default text/* to utf-8\n if (match && TEXT_TYPE_REGEXP.test(match[1])) {\n return 'UTF-8'\n }\n\n return false\n}\n\n/**\n * Create a full Content-Type header given a MIME type or extension.\n *\n * @param {string} str\n * @return {boolean|string}\n */\n\nfunction contentType (str) {\n // TODO: should this even be in this module?\n if (!str || typeof str !== 'string') {\n return false\n }\n\n var mime = str.indexOf('/') === -1\n ? exports.lookup(str)\n : str\n\n if (!mime) {\n return false\n }\n\n // TODO: use content-type or other module\n if (mime.indexOf('charset') === -1) {\n var charset = exports.charset(mime)\n if (charset) mime += '; charset=' + charset.toLowerCase()\n }\n\n return mime\n}\n\n/**\n * Get the default extension for a MIME type.\n *\n * @param {string} type\n * @return {boolean|string}\n */\n\nfunction extension (type) {\n if (!type || typeof type !== 'string') {\n return false\n }\n\n // TODO: use media-typer\n var match = EXTRACT_TYPE_REGEXP.exec(type)\n\n // get extensions\n var exts = match && exports.extensions[match[1].toLowerCase()]\n\n if (!exts || !exts.length) {\n return false\n }\n\n return exts[0]\n}\n\n/**\n * Lookup the MIME type for a file path/extension.\n *\n * @param {string} path\n * @return {boolean|string}\n */\n\nfunction lookup (path) {\n if (!path || typeof path !== 'string') {\n return false\n }\n\n // get the extension (\"ext\" or \".ext\" or full path)\n var extension = extname('x.' + path)\n .toLowerCase()\n .substr(1)\n\n if (!extension) {\n return false\n }\n\n return exports.types[extension] || false\n}\n\n/**\n * Populate the extensions and types maps.\n * @private\n */\n\nfunction populateMaps (extensions, types) {\n // source preference (least -> most)\n var preference = ['nginx', 'apache', undefined, 'iana']\n\n Object.keys(db).forEach(function forEachMimeType (type) {\n var mime = db[type]\n var exts = mime.extensions\n\n if (!exts || !exts.length) {\n return\n }\n\n // mime -> extensions\n extensions[type] = exts\n\n // extension -> mime\n for (var i = 0; i < exts.length; i++) {\n var extension = exts[i]\n\n if (types[extension]) {\n var from = preference.indexOf(db[types[extension]].source)\n var to = preference.indexOf(mime.source)\n\n if (types[extension] !== 'application/octet-stream' &&\n (from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) {\n // skip the remapping\n continue\n }\n }\n\n // set the extension -> mime\n types[extension] = type\n }\n })\n}\n","// vim:ts=4:sts=4:sw=4:\n/*!\n *\n * Copyright 2009-2017 Kris Kowal under the terms of the MIT\n * license found at https://github.com/kriskowal/q/blob/v1/LICENSE\n *\n * With parts by Tyler Close\n * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found\n * at http://www.opensource.org/licenses/mit-license.html\n * Forked at ref_send.js version: 2009-05-11\n *\n * With parts by Mark Miller\n * Copyright (C) 2011 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n(function (definition) {\n \"use strict\";\n\n // This file will function properly as a