Newer
Older
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ([
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const {
BaseKonnector,
log,
errors,
addData,
hydrateAndFilter,
cozyClient,
} = __webpack_require__(1)
const axios = (__webpack_require__(1382)["default"])
const moment = __webpack_require__(1394)
__webpack_require__(1531)
moment.locale('fr') // set the language
moment.tz.setDefault('Europe/Paris') // set the timezone
const Sentry = __webpack_require__(1534)
// eslint-disable-next-line
const Tracing = __webpack_require__(1609) // Needed for tracking performance in Sentry
const { version } = __webpack_require__(1646)
const { isDev } = __webpack_require__(1647)
process.env.COZY_JOB_MANUAL_EXECUTION === 'true' ? true : false
.subtract(1, 'year')
.format('MM/DD/YYYY')
.subtract(3, 'year')
.format('MM/DD/YYYY')
const endDate = moment().format('MM/DD/YYYY')
doctype: 'com.grandlyon.egl.day',
keys: ['year', 'month', 'day'],
doctype: 'com.grandlyon.egl.month',
keys: ['year', 'month'],
doctype: 'com.grandlyon.egl.year',
keys: ['year'],
},
}
module.exports = new BaseKonnector(start)
/**
* Sentry
*/
Sentry.init({
dsn:
'https://3f97baf46c2b44c2bd9e0c371abe3e05@grandlyon.errors.cozycloud.cc/2',
// Set tracesSampleRate to 1.0 to capture 100%
// of transactions for performance monitoring.
// We recommend adjusting this value in production
tracesSampleRate: 1.0,
release: version,
environment: isDev() ? 'development' : 'production',
debug: isDev(),
integrations: [
// enable HTTP calls tracing
new Sentry.Integrations.Http({ tracing: true }),
],
})
// The start function is run by the BaseKonnector instance only when it got all the account
// information (fields). When you run this connector yourself in 'standalone' mode or 'dev' mode,
// the account information come from ./konnector-dev-config.json file
async function start(fields, cozyParameters) {
const transaction = Sentry.startTransaction({
op: 'konnector',
name: 'EGL Konnector',
})
transaction.startChild({ op: 'Konnector starting' })
// const baseUrl = fields.eglBaseURL
// const apiAuthKey = fields.eglAPIAuthKey
const baseUrl = cozyParameters.secret.eglBaseURL
const apiAuthKey = cozyParameters.secret.eglAPIAuthKey
log('info', 'Authenticating ...')
const response = await authenticate(
fields.login,
fields.password,
baseUrl,
apiAuthKey
)
log('info', 'Successfully logged in')
const eglData = await getData(response, baseUrl, apiAuthKey)
log('debug', 'Process egl daily data')
const processedLoadData = await processData(
eglData,
rangeDate.day.doctype,
rangeDate.day.keys
)
log('debug', 'Aggregate egl load data for month and year')
await aggregateMonthAndYearData(processedLoadData)
log('debug', 'No data found')
transaction.setStatus(Tracing.SpanStatus.Ok)
transaction.finish()
const errorMessage = `EGL konnector encountered an error. Response data: ${JSON.stringify(
error.message
)}`
Sentry.captureMessage(errorMessage, {
tags: {
section: 'start',
},
})
transaction.setStatus(Tracing.SpanStatus.Aborted)
transaction.finish()
await Sentry.flush()
throw error
/**
* Parse data
* Remove existing data from DB using hydrateAndFilter
* Store filtered data
* Return the list of filtered data
*/
async function processData(data, doctype, filterKeys) {
log('debug', 'processData - data formatted')
// Remove data for existing days into the DB
const filteredData = await hydrateAndFilter(data, doctype, {
keys: filterKeys,
})
log('debug', 'processData - data filtered')
await storeData(filteredData, doctype, filterKeys)
return filteredData
* Aggregate data from daily data to monthly and yearly data
async function aggregateMonthAndYearData(data) {
// Sum year and month values into object with year or year-month as keys
if (data && data.length !== 0) {
let monthData = {}
let yearData = {}
const monthDataKey = element.year + '-' + element.month
if (monthDataKey in monthData) {
monthData[monthDataKey] += element.load
} else {
monthData[monthDataKey] = element.load
}
const yearDataKey = element.year
if (yearDataKey in yearData) {
yearData[yearDataKey] += element.load
} else {
yearData[yearDataKey] = element.load
}
})
// Aggregation for Month data
const aggregatedMonthData = await buildAggregatedData(
'com.grandlyon.egl.month'
)
await storeData(aggregatedMonthData, 'com.grandlyon.egl.month', [
'year',
'month',
])
// Aggregation for Year data
const aggregatedYearData = await buildAggregatedData(
'com.grandlyon.egl.year'
)
await storeData(aggregatedYearData, 'com.grandlyon.egl.year', ['year'])
}
}
/**
* Retrieve and remove old data for a specific doctype
* Return an Array of aggregated data
async function buildAggregatedData(data, doctype) {
log('info', 'entering buildAggregatedData')
let aggregatedData = []
for (let [key, value] of Object.entries(data)) {
const data = await buildDataFromKey(doctype, key, value)
const oldValue = await resetInProgressAggregatedData(data, doctype)
log('info', 'Data load + old value is ' + data.load + ' + ' + oldValue)
data.load += oldValue
aggregatedData.push(data)
return aggregatedData
async function authenticate(login, password, baseUrl, apiAuthKey) {
const authRequest = {
method: 'post',
url: baseUrl + '/connect.aspx',
'Content-Type': 'application/x-www-form-urlencoded',
pass: password,
const resp = await axios(authRequest)
if (resp.data.codeRetour === 100) {
return resp.data
} else {
const errorMessage = `Authentication failed. Response data: ${resp.data.libelleRetour}`
throw new Error(`code retour ko : ${resp.data.codeRetour}`)
}
} catch (error) {
Sentry.captureException(error, {
extra: {
test: 'test',
who: login,
},
throw new Error(errors.LOGIN_FAILED)
}
}
async function getData(response, baseUrl, apiAuthKey) {
log('debug', 'Start date : ' + startDate)
log('debug', 'End date : ' + endDate)
method: 'post',
url: baseUrl + '/getAllAgregatsByAbonnement.aspx',
'Content-Type': 'application/x-www-form-urlencoded',
token: response.resultatRetour.token,
num_abt: response.resultatRetour.num_abt,
date_debut: startDate,
date_fin: endDate,
const resp = await axios(dataRequest)
resp.data.resultatRetour.sort(function(a, b) {
return new Date(a.DateReleve) - new Date(b.DateReleve)
switch (resp.data.codeRetour) {
return format(resp.data)
log(
'error',
`Get data failed. codeRetour -2. ${resp.data.libelleRetour}`
throw errors.LOGIN_FAILED
log(
'error',
`Get data failed. codeRetour -1. ${resp.data.libelleRetour}`
throw errors.VENDOR_DOWN
log(
'error',
`Get data failed. ${resp.data.codeRetour}. ${resp.data.libelleRetour}`
throw errors.UNKNOWN_ERROR
Sentry.captureException(`GetData failed: ${error.message}`, {
if (axios.isAxiosError(error)) {
throw new Error(errors.VENDOR_DOWN)
}
throw error
log('info', 'origin response size is: ' + response.resultatRetour.length)
// Store first value as reference for index processing
let refValue = response.resultatRetour[0]
// Create copy of data without first value
.filter(value => value.ValeurIndex)
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
log('info', 'filtered size is: ' + data.length)
try {
return data.map(value => {
const time = moment(value.DateReleve, moment.ISO_8601)
const processedLoad = value.ValeurIndex - refValue.ValeurIndex
if (processedLoad < 0) {
const errorMessage = `Processing load error for day ${parseInt(
time.format('D')
)}/${parseInt(time.format('M'))}/${parseInt(
time.format('YYYY')
)}, value is: ${processedLoad}`
log('debug', errorMessage)
throw errors.VENDOR_DOWN
}
// Change index ref value
refValue = value
return {
load: processedLoad,
year: parseInt(time.format('YYYY')),
month: parseInt(time.format('M')),
day: parseInt(time.format('D')),
hour: 0,
minute: 0,
type: value.TypeAgregat,
}
})
} catch (error) {
Sentry.captureException(`Format failed: ${error.message}`, {
tags: {
section: 'format',
},
})
throw error
}
/**
* Save data in the right doctype db and prevent duplicated keys
*/
async function storeData(data, doctype, filterKeys) {
log('debug', 'Store into ' + doctype)
log('debug', 'Store into keys : ' + filterKeys)
const filteredDocuments = await hydrateAndFilter(data, doctype, {
keys: filterKeys,
})
return await addData(filteredDocuments, doctype)
}
/**
* Format an entry for DB storage
* using key and value
* For year doctype: key = 'YYYY'
* For month doctype: key = 'YYYY-MM'
*/
async function buildDataFromKey(doctype, key, value) {
let year, month, day, hour
if (doctype === 'com.grandlyon.egl.year') {
year = key
month = 1
day = 0
hour = 0
} else if (doctype === 'com.grandlyon.egl.month') {
const split = key.split('-')
year = split[0]
month = split[1]
day = 0
hour = 0
const split = key.split('-')
year = split[0]
month = split[1]
day = split[2]
hour = split[3]
return {
load: Math.round(value * 10000) / 10000,
year: parseInt(year),
month: parseInt(month),
day: parseInt(day),
hour: parseInt(hour),
minute: 0,
}
/**
* Function handling special case.
* The temporary aggregated data need to be remove in order for the most recent one te be saved.
* { load: 76.712, month: 2020, ... } need to be replace by
* { load: 82.212, month: 2020, ... } after egl data reprocess
async function resetInProgressAggregatedData(data, doctype) {
// /!\ Warning: cannot use mongo queries because not supported for dev by cozy-konnectors-libs
log('debug', 'Remove aggregated data for ' + doctype)
const result = await cozyClient.data.findAll(doctype)
let filtered = []
if (doctype === 'com.grandlyon.egl.year') {
// Yearly case
filtered = result.filter(function(el) {
return el.year == data.year
})
} else if (doctype === 'com.grandlyon.egl.month') {
return el.year == data.year && el.month == data.month
})
filtered = result.filter(function(el) {
return (
el.year == data.year &&
el.month == data.month &&
el.day == data.day &&
el.hour == data.hour
)
})
let sum = 0.0
sum += doc.load
log('debug', 'Removing this entry for ' + doc.load)
await cozyClient.data.delete(doctype, doc)
return sum
return 0.0
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
const requestFactory = __webpack_require__(2);
const hydrateAndFilter = __webpack_require__(329);
const categorization = __webpack_require__(1275);
const log = __webpack_require__(1292);
BaseKonnector: __webpack_require__(1293),
CookieKonnector: __webpack_require__(1375),
cozyClient: __webpack_require__(461),
errors: __webpack_require__(1299),
saveFiles: __webpack_require__(1295),
saveBills: __webpack_require__(1294),
saveIdentity: __webpack_require__(1341),
linkBankOperations: __webpack_require__(1318),
addData: __webpack_require__(1317),
htmlToPDF: (__webpack_require__(1376).htmlToPDF),
createCozyPDFDocument: (__webpack_require__(1376).createCozyPDFDocument),
filterData: deprecate(hydrateAndFilter, 'Use hydrateAndFilter now. filterData will be removed in cozy-konnector-libs@4'),
updateOrCreate: __webpack_require__(1340),
request: deprecate(requestFactory, 'Use requestFactory instead of request. It will be removed in cozy-konnector-libs@4'),
requestFactory,
retry: __webpack_require__(1296),
wrapIfSentrySetUp: (__webpack_require__(1342).wrapIfSentrySetUp),
Document: __webpack_require__(1377),
signin: __webpack_require__(1337),
submitForm: __webpack_require__(1337),
scrape: __webpack_require__(1379),
mkdirp: __webpack_require__(1298),
normalizeFilename: __webpack_require__(1380),
utils: __webpack_require__(460),
solveCaptcha: __webpack_require__(1381),
createCategorizer: categorization.createCategorizer,
categorize: categorization.categorize,
manifest: __webpack_require__(912)
};
function deprecate(wrapped, message) {
return function () {
log('warn', message);
return wrapped.apply(this, arguments);
};
}
/***/ }),
/* 2 */
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
module.exports = __webpack_require__(3)["default"];
/***/ }),
/* 3 */
/***/ ((module, exports, __webpack_require__) => {
* This is a function which returns an instance of
* [request-promise](https://www.npmjs.com/package/request-promise) initialized with
* defaults often used in connector development.
* ```js
* // Showing defaults
* req = requestFactory({
* cheerio: false,
* jar: true,
* json: true
* })
* ```
* - `cheerio`: will parse automatically the `response.body` in a cheerio instance
* ```javascript
* req = requestFactory({ cheerio: true })
* req('http://github.com', $ => {
* const repos = $('#repo_listing .repo')
* })
* ```
* - `jar`: is passed to `request` options. Remembers cookies for future use.
* - `json`: will parse the `response.body` as JSON
* - `resolveWithFullResponse`: The full response will be return in the promise. It is compatible
* with cheerio and json options.
*
* ```javascript
* req = requestFactory({
* resolveWithFullResponse: true,
* cheerio: true
* })
* req('http://github.com', response => {
* console.log(response.statusCode)
* const $ = response.body
* const repos = $('#repo_listing .repo')
* })
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
* - `debug`: will display request and responses details in error output. Possible values :
* true : display request and response in normal request-debug json format
* 'json' : display request and response in full json format
* 'simple' : display main information about each request and response
* ```
* GET -> http://books.toscrape.com/media/cache/26/0c/260c6ae16bce31c8f8c95daddd9f4a1c.jpg
* <- 200 Content-Length: 7095
* ```
* 'full' : display comple information about each request and response
* ```
* GET -> http://quotes.toscrape.com/login
*
* BEGIN HEADERS
* host: quotes.toscrape.com
* END HEADERS
*
* <- 200 Content-Length: 1869
*
* BEGIN HEADERS
* server: nginx/1.12.1
* ...
* END HEADERS
*
* BEGIN BODY
* <html>....
* END BODY
* ```
*
* You can find the full list of available options in [request-promise](https://github.com/request/request-promise) and [request](https://github.com/request/request) documentations.
*
* @module requestFactory
let request = __webpack_require__(4);
const requestdebug = __webpack_require__(253); // Quickly found more UserAgent here
// https://www.whatismybrowser.com/guides/the-latest-user-agent/
const AGENTS_LIST = ['Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11.1; rv:84.0) Gecko/20100101 Firefox/84.0', 'Mozilla/5.0 (X11; Linux i686; rv:84.0) Gecko/20100101 Firefox/84.0', 'Mozilla/5.0 (Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0', 'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:84.0) Gecko/20100101 Firefox/84.0', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36 Edg/87.0.664.75'];
const DEFAULT_USER_AGENT = AGENTS_LIST[Math.floor(Math.random() * AGENTS_LIST.length)];
exports = module.exports = {
default: requestFactory,
mergeDefaultOptions,
transformWithCheerio,
getRequestOptions,
DEFAULT_USER_AGENT
};
function requestFactory({
debug,
...options
} = {
debug: false
}) {
const logFn = setDebugFunction(debug);
debug && requestdebug(request, logFn);
return request.defaults(getRequestOptions(mergeDefaultOptions(options)));
function setDebugFunction(debug) {
/* eslint no-console: off */
if (debug === 'simple') {
return (type, data) => console.error(requestToStrings(type, data).oneline);
} else if (debug === 'json') {
return (type, data) => console.error(JSON.stringify({
type,
data
}));
} else if (debug === 'full') {
return (type, data) => {
const {
oneline,
headers,
body
} = requestToStrings(type, data);
console.error(`${oneline}
BEGIN HEADERS
${headers}
END HEADERS
` + (body ? `BEGIN BODY
${body}
END BODY
` : ''));
};
} else if (typeof debug === 'function') {
return (type, data, resp) => debug({
strings: requestToStrings(type, data),
type,
data,
resp
});
function requestToStrings(type, data) {
const result = {};
if (type === 'request') {
result.oneline = `${data.method} -> ${data.uri} ${data.headers['content-length'] ? 'Content-Length: ' + data.headers['content-length'] : ''}`;
} else if (type === 'response') {
result.oneline = `<- ${data.statusCode} ${data.headers['content-length'] ? 'Content-Length: ' + data.headers['content-length'] : ''}`;
} else {
result.oneline = `<- ${data.statusCode} ${data.uri}`;
}
result.headers = Object.keys(data.headers).map(key => `${key}: ${data.headers[key]}`).join('\n');
result.body = data.body;
return result;
function mergeDefaultOptions(options = {}) {
const defaultOptions = {
debug: false,
json: true,
cheerio: false,
headers: {},
followAllRedirects: true
};
if (options.cheerio === true) {
options.json = false;
}
return { ...defaultOptions,
...options
};
function transformWithCheerio(body, response, resolveWithFullResponse) {
const result = (__webpack_require__(255).load)(body);
return { ...response,
function getRequestOptions({
cheerio,
userAgent,
...options
}) {
const userAgentOption = options.headers['User-Agent'];
return cheerio ? { ...options,
headers: { ...options.headers,
'User-Agent': userAgentOption ? userAgentOption : userAgent === false ? undefined : DEFAULT_USER_AGENT
}
} : { ...options,
headers: { ...options.headers,
'User-Agent': userAgent ? DEFAULT_USER_AGENT : options.headers['User-Agent']
}
};
/* 4 */
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
"use strict";
/* module decorator */ module = __webpack_require__.nmd(module);
var Bluebird = (__webpack_require__(5).getNewLibraryCopy)(),
configure = __webpack_require__(42),
stealthyRequire = __webpack_require__(57);
// Load Request freshly - so that users can require an unaltered request instance!
var request = stealthyRequire(__webpack_require__.c, function () {
return __webpack_require__(58);
},
function () {
__webpack_require__(61);
}, module);
} catch (err) {
/* istanbul ignore next */
var EOL = (__webpack_require__(252).EOL);
/* istanbul ignore next */
console.error(EOL + '###' + EOL + '### The "request" library is not installed automatically anymore.' + EOL + '### But is a dependency of "request-promise".' + EOL + '### Please install it with:' + EOL + '### npm install request --save' + EOL + '###' + EOL);
/* istanbul ignore next */
throw err;
Bluebird.config({cancellation: true});
configure({
request: request,
PromiseImpl: Bluebird,
expose: [
'then',
'catch',
'finally',
'cancel',
'promise'
// Would you like to expose more Bluebird methods? Try e.g. `rp(...).promise().tap(...)` first. `.promise()` returns the full-fledged Bluebird promise.
],
constructorMixin: function (resolve, reject, onCancel) {
var self = this;
onCancel(function () {
self.abort();
});
}
});
request.bindCLS = function RP$bindCLS() {
throw new Error('CLS support was dropped. To get it back read: https://github.com/request/request-promise/wiki/Getting-Back-Support-for-Continuation-Local-Storage');
};
/***/ }),
/* 5 */
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
var old;
if (typeof Promise !== "undefined") old = Promise;
function noConflict() {
try { if (Promise === bluebird) Promise = old; }
catch (e) {}
return bluebird;
var bluebird = __webpack_require__(6)();
bluebird.noConflict = noConflict;
module.exports = bluebird;
/* 6 */
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
module.exports = function() {
var makeSelfResolutionError = function () {
return new TypeError("circular promise resolution chain\u000a\u000a See http://goo.gl/MqrFmX\u000a");
};
var reflectHandler = function() {
return new Promise.PromiseInspection(this._target());
};
var apiRejection = function(msg) {
return Promise.reject(new TypeError(msg));
};
function Proxyable() {}
var UNDEFINED_BINDING = {};
var util = __webpack_require__(7);
util.setReflectHandler(reflectHandler);
var getDomain = function() {
var domain = process.domain;
if (domain === undefined) {
return null;
}
return domain;
};
var getContextDefault = function() {
return null;
};
var getContextDomain = function() {
return {
domain: getDomain(),
async: null
};
};
var AsyncResource = util.isNode && util.nodeSupportsAsyncResource ?
(__webpack_require__(9).AsyncResource) : null;
var getContextAsyncHooks = function() {
return {
domain: getDomain(),
async: new AsyncResource("Bluebird::Promise")
};
};
var getContext = util.isNode ? getContextDomain : getContextDefault;
util.notEnumerableProp(Promise, "_getContext", getContext);
var enableAsyncHooks = function() {
getContext = getContextAsyncHooks;
util.notEnumerableProp(Promise, "_getContext", getContextAsyncHooks);
};
var disableAsyncHooks = function() {
getContext = getContextDomain;
util.notEnumerableProp(Promise, "_getContext", getContextDomain);
};
var es5 = __webpack_require__(8);
var Async = __webpack_require__(10);
var async = new Async();
es5.defineProperty(Promise, "_async", {value: async});
var errors = __webpack_require__(13);
var TypeError = Promise.TypeError = errors.TypeError;
Promise.RangeError = errors.RangeError;
var CancellationError = Promise.CancellationError = errors.CancellationError;
Promise.TimeoutError = errors.TimeoutError;
Promise.OperationalError = errors.OperationalError;
Promise.RejectionError = errors.OperationalError;
Promise.AggregateError = errors.AggregateError;
var INTERNAL = function(){};
var APPLY = {};
var NEXT_FILTER = {};
var tryConvertToPromise = __webpack_require__(14)(Promise, INTERNAL);
var PromiseArray =
__webpack_require__(15)(Promise, INTERNAL,
tryConvertToPromise, apiRejection, Proxyable);
var Context = __webpack_require__(16)(Promise);
/*jshint unused:false*/
var createContext = Context.create;
var debug = __webpack_require__(17)(Promise, Context,
enableAsyncHooks, disableAsyncHooks);
var CapturedTrace = debug.CapturedTrace;
var PassThroughHandlerContext =
__webpack_require__(18)(Promise, tryConvertToPromise, NEXT_FILTER);
var catchFilter = __webpack_require__(19)(NEXT_FILTER);
var nodebackForPromise = __webpack_require__(20);
var errorObj = util.errorObj;
var tryCatch = util.tryCatch;
function check(self, executor) {
if (self == null || self.constructor !== Promise) {
throw new TypeError("the promise constructor cannot be invoked directly\u000a\u000a See http://goo.gl/MqrFmX\u000a");
}
if (typeof executor !== "function") {
throw new TypeError("expecting a function but got " + util.classString(executor));
}
function Promise(executor) {
if (executor !== INTERNAL) {
check(this, executor);
}
this._bitField = 0;
this._fulfillmentHandler0 = undefined;
this._rejectionHandler0 = undefined;
this._promise0 = undefined;
this._receiver0 = undefined;
this._resolveFromExecutor(executor);
this._promiseCreated();
this._fireEvent("promiseCreated", this);
Promise.prototype.toString = function () {
return "[object Promise]";
Promise.prototype.caught = Promise.prototype["catch"] = function (fn) {
var len = arguments.length;
if (len > 1) {
var catchInstances = new Array(len - 1),
j = 0, i;
for (i = 0; i < len - 1; ++i) {
var item = arguments[i];
if (util.isObject(item)) {
catchInstances[j++] = item;
} else {
return apiRejection("Catch statement predicate: " +
"expecting an object but got " + util.classString(item));
}
}
catchInstances.length = j;
fn = arguments[i];
if (typeof fn !== "function") {
throw new TypeError("The last argument to .catch() " +
"must be a function, got " + util.toString(fn));
}
return this.then(undefined, catchFilter(catchInstances, fn, this));
}
return this.then(undefined, fn);
};
Promise.prototype.reflect = function () {
return this._then(reflectHandler,
reflectHandler, undefined, this, undefined);
};
Promise.prototype.then = function (didFulfill, didReject) {
if (debug.warnings() && arguments.length > 0 &&
typeof didFulfill !== "function" &&
typeof didReject !== "function") {
var msg = ".then() only accepts functions but was passed: " +
util.classString(didFulfill);
if (arguments.length > 1) {
msg += ", " + util.classString(didReject);
}
this._warn(msg);
}
return this._then(didFulfill, didReject, undefined, undefined, undefined);
};
Promise.prototype.done = function (didFulfill, didReject) {
var promise =
this._then(didFulfill, didReject, undefined, undefined, undefined);
promise._setIsFinal();
};
Promise.prototype.spread = function (fn) {
if (typeof fn !== "function") {
return apiRejection("expecting a function but got " + util.classString(fn));
}
return this.all()._then(fn, undefined, undefined, APPLY, undefined);
};
Promise.prototype.toJSON = function () {
var ret = {
isFulfilled: false,
isRejected: false,
fulfillmentValue: undefined,
rejectionReason: undefined
};
if (this.isFulfilled()) {
ret.fulfillmentValue = this.value();
ret.isFulfilled = true;
} else if (this.isRejected()) {
ret.rejectionReason = this.reason();
ret.isRejected = true;
}
return ret;
};
Promise.prototype.all = function () {
if (arguments.length > 0) {
this._warn(".all() was passed arguments but it does not take any");
}
return new PromiseArray(this).promise();
};
Promise.prototype.error = function (fn) {
return this.caught(util.originatesFromRejection, fn);
};
Promise.getNewLibraryCopy = module.exports;
Promise.is = function (val) {
return val instanceof Promise;
};