<commit_before>var UUID = require('../uuid').UUID,
    TimeUUID = require('../uuid').UUID;

/**
 * Deserializers for various types
 * @class
 */
var Deserializers = {};

Deserializers.decodeInteger = function(bits, val){
  var hex = new Buffer(val, 'binary').toString('hex');
  return parseInt(hex, 16);
};

/**
 * Does binary decoding
 * @static
 * @param {String} val The binary string to decode
 * @returns {Buffer} a buffer containing the bytes decoded from the string
 */
Deserializers.decodeBinary = function(val){
  return new Buffer(val, 'binary');
};

/**
 * Decodes a Long (UInt64)
 * @static
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeLong = function(val){
  return Deserializers.decodeInteger(64, val);
};

/**
 * Decodes a 16bit Unsinged Integer
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeInt16 = function(val){
  return Deserializers.decodeInteger(16, val);
};

/**
 * Decodes a 32bit Unsinged Integer
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeInt32 = function(val){
  return Deserializers.decodeInteger(32, val);
};

/**
 * Decodes for UTF8
 * @param {String} val The binary string to decode
 * @returns {String} The utf8 value decoded from the binary string
 */
Deserializers.decodeUTF8 = function(val){
  return new Buffer(val, 'binary').toString('utf8');
};

/**
 * Decodes for Ascii
 * @param {String} val The binary string to decode
 * @returns {String} The ascii value decoded from the binary string
 */
Deserializers.decodeAscii = function(val){
  return new Buffer(val, 'binary').toString('ascii');
};

/**
 * Decode a Double Precision Floating Point Type
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeDouble = function(val){
  var buf = new Buffer(val, 'binary');
  return buf.readDoubleBE(0);
};

/**
 * Decode a Single Precision Floating Point Type
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeFloat = function(val){
  var buf = new Buffer(val, 'binary');
  return buf.readFloatBE(0);
};

/**
 * Decodes a boolean type
 * @param {String} val The binary string to decode
 * @returns {Boolean} The boolean value decoded from the binary string
 */
Deserializers.decodeBoolean = function(val){
  var buf = new Buffer(val, 'binary');

  if(buf[0] === 0){
    return false;
  } else if(buf[0] === 1) {
    return true;
  }
};

/**
 * Decodes a Date object
 * @param {String} val The binary string to decode
 * @returns {Date} The date value decoded from the binary string
 */
Deserializers.decodeDate = function(val){
  var date = Deserializers.decodeLong(val);
  return new Date(date / 1000);
};

/**
 * Decodes a UUID Object
 * @param {String} val The binary string to decode
 * @returns {UUID} The uuid value decoded from the binary string
 */
Deserializers.decodeUUID = function(val){
  return UUID.fromBinary(val);
};

/**
 * Decodes a TimeUUID Object
 * @param {String} val The binary string to decode
 * @returns {TimeUUID} The uuid value decoded from the binary string
 */
Deserializers.decodeTimeUUID = function(val){
  return TimeUUID.fromBinary(val);
};
module.exports = Deserializers;<commit_msg>reference timeuuid rather than uuid<commit_after>var UUID = require('../uuid').UUID,
    TimeUUID = require('../uuid').TimeUUID;

/**
 * Deserializers for various types
 * @class
 */
var Deserializers = {};

Deserializers.decodeInteger = function(bits, val){
  var hex = new Buffer(val, 'binary').toString('hex');
  return parseInt(hex, 16);
};

/**
 * Does binary decoding
 * @static
 * @param {String} val The binary string to decode
 * @returns {Buffer} a buffer containing the bytes decoded from the string
 */
Deserializers.decodeBinary = function(val){
  return new Buffer(val, 'binary');
};

/**
 * Decodes a Long (UInt64)
 * @static
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeLong = function(val){
  return Deserializers.decodeInteger(64, val);
};

/**
 * Decodes a 16bit Unsinged Integer
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeInt16 = function(val){
  return Deserializers.decodeInteger(16, val);
};

/**
 * Decodes a 32bit Unsinged Integer
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeInt32 = function(val){
  return Deserializers.decodeInteger(32, val);
};

/**
 * Decodes for UTF8
 * @param {String} val The binary string to decode
 * @returns {String} The utf8 value decoded from the binary string
 */
Deserializers.decodeUTF8 = function(val){
  return new Buffer(val, 'binary').toString('utf8');
};

/**
 * Decodes for Ascii
 * @param {String} val The binary string to decode
 * @returns {String} The ascii value decoded from the binary string
 */
Deserializers.decodeAscii = function(val){
  return new Buffer(val, 'binary').toString('ascii');
};

/**
 * Decode a Double Precision Floating Point Type
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeDouble = function(val){
  var buf = new Buffer(val, 'binary');
  return buf.readDoubleBE(0);
};

/**
 * Decode a Single Precision Floating Point Type
 * @param {String} val The binary string to decode
 * @returns {Number} The number value decoded from the binary string
 */
Deserializers.decodeFloat = function(val){
  var buf = new Buffer(val, 'binary');
  return buf.readFloatBE(0);
};

/**
 * Decodes a boolean type
 * @param {String} val The binary string to decode
 * @returns {Boolean} The boolean value decoded from the binary string
 */
Deserializers.decodeBoolean = function(val){
  var buf = new Buffer(val, 'binary');

  if(buf[0] === 0){
    return false;
  } else if(buf[0] === 1) {
    return true;
  }
};

/**
 * Decodes a Date object
 * @param {String} val The binary string to decode
 * @returns {Date} The date value decoded from the binary string
 */
Deserializers.decodeDate = function(val){
  var date = Deserializers.decodeLong(val);
  return new Date(date / 1000);
};

/**
 * Decodes a UUID Object
 * @param {String} val The binary string to decode
 * @returns {UUID} The uuid value decoded from the binary string
 */
Deserializers.decodeUUID = function(val){
  return UUID.fromBinary(val);
};

/**
 * Decodes a TimeUUID Object
 * @param {String} val The binary string to decode
 * @returns {TimeUUID} The uuid value decoded from the binary string
 */
Deserializers.decodeTimeUUID = function(val){
  return TimeUUID.fromBinary(val);
};
module.exports = Deserializers;<|endoftext|>


<commit_before>import moment from 'moment';
import _ from 'lodash';
import retry from 'promise-retry';

import { parsers } from '../../utils';
import getBookingFromUr from '../../utils/get-booking-from-ur';
import airService from './AirService';
import createTerminalService from '../Terminal/Terminal';
import { AirRuntimeError } from './AirErrors';
import validateServiceSettings from '../../utils/validate-service-settings';

module.exports = (settings) => {
  const service = airService(validateServiceSettings(settings));
  return {
    shop(options) {
      return service.searchLowFares(options);
    },

    fareRules(options) {
      // add request for fare rules
      const request = Object.assign(options,
        {
          fetchFareRules: true,
        }
      );
      return service.lookupFareRules(request);
    },

    toQueue(options) {
      return service.gdsQueue(options);
    },

    book(options) {
      return service.airPricePricingSolutionXML(options).then((data) => {
        const bookingParams = Object.assign({}, {
          ticketDate: moment().add(3, 'hours').format(),
          ActionStatusType: 'TAU',
        }, data, options);
        return service.createReservation(bookingParams).catch((err) => {
          if (err instanceof AirRuntimeError.SegmentBookingFailed
              || err instanceof AirRuntimeError.NoValidFare) {
            if (options.allowWaitlist) { // will not have a UR if waitlisting restricted
              const code = err.data['universal:UniversalRecord'].LocatorCode;
              return service.cancelUR({
                LocatorCode: code,
              }).then(() => Promise.reject(err));
            }
            return Promise.reject(err);
          }
          return Promise.reject(err);
        });
      });
    },

    getPNR(options) {
      return this.getUniversalRecordByPNR(options)
        .then(
          ur =>
            getBookingFromUr(ur, options.pnr) ||
            Promise.reject(new AirRuntimeError.NoPNRFoundInUR(ur))
        );
    },

    importPNR(options) {
      return this.getPNR(options)
        .then(response => [response]);
    },

    getUniversalRecordByPNR(options) {
      return service.getUniversalRecordByPNR(options)
        .catch((err) => {
          // Checking for error type
          if (!(err instanceof AirRuntimeError.NoReservationToImport)) {
            return Promise.reject(err);
          }
          // Creating passive segment to import PNR
          const terminal = createTerminalService(settings);
          const segment = {
            date: moment().add(42, 'days').format('DDMMM'),
            airline: 'OK',
            from: 'DOH',
            to: 'ODM',
            comment: 'NO1',
            class: 'Y',
          };
          const segmentCommand = (
            `0${segment.airline}OPEN${segment.class}${segment.date}${segment.from}${segment.to}${segment.comment}`
          ).toUpperCase();
          const segmentResult = (
            `1. ${segment.airline} OPEN ${segment.class}  ${segment.date} ${segment.from}${segment.to} ${segment.comment}`
          ).toUpperCase();
          const pnrRegExp = new RegExp(`^(?:\\*\\* THIS BF IS CURRENTLY IN USE \\*\\*\\s*)?${options.pnr}`);
          return terminal.executeCommand(`*${options.pnr}`)
            .then((response) => {
              if (!response.match(pnrRegExp)) {
                return Promise.reject(new AirRuntimeError.UnableToOpenPNRInTerminal());
              }
              return Promise.resolve();
            })
            .then(() => terminal.executeCommand(segmentCommand))
            .then((response) => {
              if (response.indexOf(segmentResult) === -1) {
                return Promise.reject(new AirRuntimeError.UnableToAddExtraSegment());
              }
              return Promise.resolve();
            })
            .then(() => {
              const ticketingDate = moment().add(10, 'days').format('DDMMM');
              const command = `T.TAU/${ticketingDate}`;
              return terminal.executeCommand(command)
                .then(() => terminal.executeCommand('R.UAPI+ER'))
                .then(() => terminal.executeCommand('ER'));
            })
            .then((response) => {
              if (
                (!response.match(pnrRegExp)) ||
                (response.indexOf(segmentResult) === -1)
              ) {
                return Promise.reject(new AirRuntimeError.UnableToSaveBookingWithExtraSegment());
              }
              return Promise.resolve();
            })
            .catch(
              importErr => terminal.closeSession().then(
                () => Promise.reject(
                  new AirRuntimeError.UnableToImportPnr(options, importErr)
                )
              )
            )
            .then(() => terminal.closeSession())
            .then(() => service.getUniversalRecordByPNR(options))
            .then(ur => service.cancelPNR(getBookingFromUr(ur, options.pnr)))
            .then(() => service.getUniversalRecordByPNR(options));
        });
    },

    ticket(options) {
      return retry({ retries: 3 }, (again, number) => {
        if (settings.debug && number > 1) console.log(`ticket ${options.pnr} retry number ${number}`);
        return (options.ReservationLocator
            ? Promise.resolve(options)
            : this.getPNR(options).then((booking) => {
              const ticketParams = Object.assign({}, options, {
                ReservationLocator: booking.uapi_reservation_locator,
              });
              return ticketParams;
            })
        ).then(
          ticketParams => service.ticket(ticketParams)
            .then(result => result, (err) => {
              if (err instanceof AirRuntimeError.TicketingFoidRequired) {
                return this.getPNR(options)
                  .then(updatedBooking => service.foid(updatedBooking))
                  .then(() => this.ticket(ticketParams));
              }
              if (err instanceof AirRuntimeError.TicketingPNRBusy) {
                return again(err);
              }
              return Promise.reject(err);
            }));
      });
    },

    flightInfo(options) {
      const parameters = {
        flightInfoCriteria: _.isArray(options) ? options : [options],
      };
      return service.flightInfo(parameters);
    },

    getTicket(options) {
      return service.getTicket(options)
        .catch((err) => {
          if (!(err instanceof AirRuntimeError.TicketInfoIncomplete)
            && !(err instanceof AirRuntimeError.DuplicateTicketFound)) {
            return Promise.reject(err);
          }
          return this.getPNRByTicketNumber({
            ticketNumber: options.ticketNumber,
          })
            .then(pnr => this.getPNR({ pnr }))
            .then(booking => service.getTicket({
              ...options,
              pnr: booking.pnr,
              uapi_ur_locator: booking.uapi_ur_locator,
            }));
        });
    },

    getPNRByTicketNumber(options) {
      const terminal = createTerminalService(settings);
      return terminal.executeCommand(`*TE/${options.ticketNumber}`)
        .then(
          response => terminal.closeSession()
            .then(() => response.match(/RLOC [^\s]{2} ([^\s]{6})/)[1])
            .catch(() => Promise.reject(new AirRuntimeError.PnrParseError(response)))
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.GetPnrError(options, err))
        );
    },

    getTickets(options) {
      return this.getPNR(options)
        .then(
           booking => Promise.all(
             booking.tickets.map(
               ticket => this.getTicket({
                 pnr: booking.pnr,
                 uapi_ur_locator: booking.uapi_ur_locator,
                 ticketNumber: ticket.number,
               })
             )
           )
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.UnableToRetrieveTickets(options, err))
        );
    },

    searchBookingsByPassengerName(options) {
      const terminal = createTerminalService(settings);
      return terminal.executeCommand(`*-${options.searchPhrase}`)
        .then((firstScreen) => {
          const list = parsers.searchPassengersList(firstScreen);
          if (list) {
            return Promise
              .all(list.map((line) => {
                const localTerminal = createTerminalService(settings);
                return localTerminal
                  .executeCommand(`*-${options.searchPhrase}`)
                  .then((firstScreenAgain) => {
                    if (firstScreenAgain !== firstScreen) {
                      return Promise.reject(
                        new AirRuntimeError.RequestInconsistency({
                          firstScreen,
                          firstScreenAgain,
                        })
                      );
                    }

                    return localTerminal.executeCommand(`*${line.id}`);
                  })
                  .then(parsers.bookingPnr)
                  .then(pnr => localTerminal.closeSession()
                    .then(() => ({ ...line, pnr }))
                  );
              }))
              .then(data => ({ type: 'list', data }));
          }

          const pnr = parsers.bookingPnr(firstScreen);
          if (pnr) {
            return {
              type: 'pnr',
              data: pnr,
            };
          }

          return Promise.reject(
            new AirRuntimeError.MissingPaxListAndBooking(firstScreen)
          );
        })
        .then(results =>
          terminal.closeSession()
            .then(() => results)
            .catch(() => results)
        );
    },

    cancelTicket(options) {
      return this.getTicket(options)
        .then(
          ticketData => service.cancelTicket({
            pnr: ticketData.pnr,
            ticketNumber: options.ticketNumber,
          })
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.FailedToCancelTicket(options, err))
        );
    },

    cancelPNR(options) {
      return this.getTickets(options)
        .then(
          tickets => Promise.all(tickets.map(
            (ticketData) => {
              // Check for VOID
              const allTicketsVoid = ticketData.tickets.every(
                ticket => ticket.coupons.every(
                  coupon => coupon.status === 'V'
                )
              );
              if (allTicketsVoid) {
                return Promise.resolve(true);
              }
              // Check for cancelTicket option
              if (options.cancelTickets !== true) {
                return Promise.reject(new AirRuntimeError.PNRHasOpenTickets());
              }
              // Check for not OPEN/VOID segments
              const hasNotOpenSegment = ticketData.tickets.some(
                ticket => ticket.coupons.some(
                  coupon => 'OV'.indexOf(coupon.status) === -1
                )
              );
              if (hasNotOpenSegment) {
                return Promise.reject(new AirRuntimeError.UnableToCancelTicketStatusNotOpen());
              }
              return Promise.all(
                ticketData.tickets.map(
                  ticket => (
                    ticket.coupons[0].status !== 'V'
                      ? service.cancelTicket({
                        pnr: options.pnr,
                        ticketNumber: ticket.ticketNumber,
                      })
                      : Promise.resolve(true)
                  )
                )
              );
            }
          ))
        )
        .then(() => this.getPNR(options))
        .then(booking => service.cancelPNR(booking))
        .catch(
          err => Promise.reject(new AirRuntimeError.FailedToCancelPnr(options, err))
        );
    },

    getExchangeInformation(options) {
      return this.getPNR(options)
        .then(booking => service.exchangeQuote({
          ...options,
          bookingDate: moment(booking.createdAt).format('YYYY-MM-DD'),
        }));
    },

    exchangeBooking(options) {
      return this.getPNR(options)
        .then(booking => service.exchangeBooking({
          ...options,
          uapi_reservation_locator: booking.uapi_reservation_locator,
        }));
    },
  };
};
<commit_msg>#147 reformat if and then.catch<commit_after>import moment from 'moment';
import _ from 'lodash';
import retry from 'promise-retry';

import { parsers } from '../../utils';
import getBookingFromUr from '../../utils/get-booking-from-ur';
import airService from './AirService';
import createTerminalService from '../Terminal/Terminal';
import { AirRuntimeError } from './AirErrors';
import validateServiceSettings from '../../utils/validate-service-settings';

module.exports = (settings) => {
  const service = airService(validateServiceSettings(settings));
  return {
    shop(options) {
      return service.searchLowFares(options);
    },

    fareRules(options) {
      // add request for fare rules
      const request = Object.assign(options,
        {
          fetchFareRules: true,
        }
      );
      return service.lookupFareRules(request);
    },

    toQueue(options) {
      return service.gdsQueue(options);
    },

    book(options) {
      return service.airPricePricingSolutionXML(options).then((data) => {
        const bookingParams = Object.assign({}, {
          ticketDate: moment().add(3, 'hours').format(),
          ActionStatusType: 'TAU',
        }, data, options);
        return service.createReservation(bookingParams).catch((err) => {
          if (err instanceof AirRuntimeError.SegmentBookingFailed
              || err instanceof AirRuntimeError.NoValidFare) {
            if (options.allowWaitlist) { // will not have a UR if waitlisting restricted
              const code = err.data['universal:UniversalRecord'].LocatorCode;
              return service.cancelUR({
                LocatorCode: code,
              }).then(() => Promise.reject(err));
            }
            return Promise.reject(err);
          }
          return Promise.reject(err);
        });
      });
    },

    getPNR(options) {
      return this.getUniversalRecordByPNR(options)
        .then(
          ur =>
            getBookingFromUr(ur, options.pnr) ||
            Promise.reject(new AirRuntimeError.NoPNRFoundInUR(ur))
        );
    },

    importPNR(options) {
      return this.getPNR(options)
        .then(response => [response]);
    },

    getUniversalRecordByPNR(options) {
      return service.getUniversalRecordByPNR(options)
        .catch((err) => {
          // Checking for error type
          if (!(err instanceof AirRuntimeError.NoReservationToImport)) {
            return Promise.reject(err);
          }
          // Creating passive segment to import PNR
          const terminal = createTerminalService(settings);
          const segment = {
            date: moment().add(42, 'days').format('DDMMM'),
            airline: 'OK',
            from: 'DOH',
            to: 'ODM',
            comment: 'NO1',
            class: 'Y',
          };
          const segmentCommand = (
            `0${segment.airline}OPEN${segment.class}${segment.date}${segment.from}${segment.to}${segment.comment}`
          ).toUpperCase();
          const segmentResult = (
            `1. ${segment.airline} OPEN ${segment.class}  ${segment.date} ${segment.from}${segment.to} ${segment.comment}`
          ).toUpperCase();
          const pnrRegExp = new RegExp(`^(?:\\*\\* THIS BF IS CURRENTLY IN USE \\*\\*\\s*)?${options.pnr}`);
          return terminal.executeCommand(`*${options.pnr}`)
            .then((response) => {
              if (!response.match(pnrRegExp)) {
                return Promise.reject(new AirRuntimeError.UnableToOpenPNRInTerminal());
              }
              return Promise.resolve();
            })
            .then(() => terminal.executeCommand(segmentCommand))
            .then((response) => {
              if (response.indexOf(segmentResult) === -1) {
                return Promise.reject(new AirRuntimeError.UnableToAddExtraSegment());
              }
              return Promise.resolve();
            })
            .then(() => {
              const ticketingDate = moment().add(10, 'days').format('DDMMM');
              const command = `T.TAU/${ticketingDate}`;
              return terminal.executeCommand(command)
                .then(() => terminal.executeCommand('R.UAPI+ER'))
                .then(() => terminal.executeCommand('ER'));
            })
            .then((response) => {
              if (
                (!response.match(pnrRegExp)) ||
                (response.indexOf(segmentResult) === -1)
              ) {
                return Promise.reject(new AirRuntimeError.UnableToSaveBookingWithExtraSegment());
              }
              return Promise.resolve();
            })
            .catch(
              importErr => terminal.closeSession().then(
                () => Promise.reject(
                  new AirRuntimeError.UnableToImportPnr(options, importErr)
                )
              )
            )
            .then(() => terminal.closeSession())
            .then(() => service.getUniversalRecordByPNR(options))
            .then(ur => service.cancelPNR(getBookingFromUr(ur, options.pnr)))
            .then(() => service.getUniversalRecordByPNR(options));
        });
    },

    ticket(options) {
      return retry({ retries: 3 }, (again, number) => {
        if (settings.debug && number > 1) {
          console.log(`ticket ${options.pnr} retry number ${number}`);
        }
        return (options.ReservationLocator
            ? Promise.resolve(options)
            : this.getPNR(options).then((booking) => {
              const ticketParams = Object.assign({}, options, {
                ReservationLocator: booking.uapi_reservation_locator,
              });
              return ticketParams;
            })
        ).then(
          ticketParams => service.ticket(ticketParams)
            .catch((err) => {
              if (err instanceof AirRuntimeError.TicketingFoidRequired) {
                return this.getPNR(options)
                  .then(updatedBooking => service.foid(updatedBooking))
                  .then(() => this.ticket(ticketParams));
              }
              if (err instanceof AirRuntimeError.TicketingPNRBusy) {
                return again(err);
              }
              return Promise.reject(err);
            })
        );
      });
    },

    flightInfo(options) {
      const parameters = {
        flightInfoCriteria: _.isArray(options) ? options : [options],
      };
      return service.flightInfo(parameters);
    },

    getTicket(options) {
      return service.getTicket(options)
        .catch((err) => {
          if (!(err instanceof AirRuntimeError.TicketInfoIncomplete)
            && !(err instanceof AirRuntimeError.DuplicateTicketFound)) {
            return Promise.reject(err);
          }
          return this.getPNRByTicketNumber({
            ticketNumber: options.ticketNumber,
          })
            .then(pnr => this.getPNR({ pnr }))
            .then(booking => service.getTicket({
              ...options,
              pnr: booking.pnr,
              uapi_ur_locator: booking.uapi_ur_locator,
            }));
        });
    },

    getPNRByTicketNumber(options) {
      const terminal = createTerminalService(settings);
      return terminal.executeCommand(`*TE/${options.ticketNumber}`)
        .then(
          response => terminal.closeSession()
            .then(() => response.match(/RLOC [^\s]{2} ([^\s]{6})/)[1])
            .catch(() => Promise.reject(new AirRuntimeError.PnrParseError(response)))
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.GetPnrError(options, err))
        );
    },

    getTickets(options) {
      return this.getPNR(options)
        .then(
           booking => Promise.all(
             booking.tickets.map(
               ticket => this.getTicket({
                 pnr: booking.pnr,
                 uapi_ur_locator: booking.uapi_ur_locator,
                 ticketNumber: ticket.number,
               })
             )
           )
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.UnableToRetrieveTickets(options, err))
        );
    },

    searchBookingsByPassengerName(options) {
      const terminal = createTerminalService(settings);
      return terminal.executeCommand(`*-${options.searchPhrase}`)
        .then((firstScreen) => {
          const list = parsers.searchPassengersList(firstScreen);
          if (list) {
            return Promise
              .all(list.map((line) => {
                const localTerminal = createTerminalService(settings);
                return localTerminal
                  .executeCommand(`*-${options.searchPhrase}`)
                  .then((firstScreenAgain) => {
                    if (firstScreenAgain !== firstScreen) {
                      return Promise.reject(
                        new AirRuntimeError.RequestInconsistency({
                          firstScreen,
                          firstScreenAgain,
                        })
                      );
                    }

                    return localTerminal.executeCommand(`*${line.id}`);
                  })
                  .then(parsers.bookingPnr)
                  .then(pnr => localTerminal.closeSession()
                    .then(() => ({ ...line, pnr }))
                  );
              }))
              .then(data => ({ type: 'list', data }));
          }

          const pnr = parsers.bookingPnr(firstScreen);
          if (pnr) {
            return {
              type: 'pnr',
              data: pnr,
            };
          }

          return Promise.reject(
            new AirRuntimeError.MissingPaxListAndBooking(firstScreen)
          );
        })
        .then(results =>
          terminal.closeSession()
            .then(() => results)
            .catch(() => results)
        );
    },

    cancelTicket(options) {
      return this.getTicket(options)
        .then(
          ticketData => service.cancelTicket({
            pnr: ticketData.pnr,
            ticketNumber: options.ticketNumber,
          })
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.FailedToCancelTicket(options, err))
        );
    },

    cancelPNR(options) {
      return this.getTickets(options)
        .then(
          tickets => Promise.all(tickets.map(
            (ticketData) => {
              // Check for VOID
              const allTicketsVoid = ticketData.tickets.every(
                ticket => ticket.coupons.every(
                  coupon => coupon.status === 'V'
                )
              );
              if (allTicketsVoid) {
                return Promise.resolve(true);
              }
              // Check for cancelTicket option
              if (options.cancelTickets !== true) {
                return Promise.reject(new AirRuntimeError.PNRHasOpenTickets());
              }
              // Check for not OPEN/VOID segments
              const hasNotOpenSegment = ticketData.tickets.some(
                ticket => ticket.coupons.some(
                  coupon => 'OV'.indexOf(coupon.status) === -1
                )
              );
              if (hasNotOpenSegment) {
                return Promise.reject(new AirRuntimeError.UnableToCancelTicketStatusNotOpen());
              }
              return Promise.all(
                ticketData.tickets.map(
                  ticket => (
                    ticket.coupons[0].status !== 'V'
                      ? service.cancelTicket({
                        pnr: options.pnr,
                        ticketNumber: ticket.ticketNumber,
                      })
                      : Promise.resolve(true)
                  )
                )
              );
            }
          ))
        )
        .then(() => this.getPNR(options))
        .then(booking => service.cancelPNR(booking))
        .catch(
          err => Promise.reject(new AirRuntimeError.FailedToCancelPnr(options, err))
        );
    },

    getExchangeInformation(options) {
      return this.getPNR(options)
        .then(booking => service.exchangeQuote({
          ...options,
          bookingDate: moment(booking.createdAt).format('YYYY-MM-DD'),
        }));
    },

    exchangeBooking(options) {
      return this.getPNR(options)
        .then(booking => service.exchangeBooking({
          ...options,
          uapi_reservation_locator: booking.uapi_reservation_locator,
        }));
    },
  };
};
<|endoftext|>


<commit_before>const moment = require('moment');
const retry = require('promise-retry');

const { parsers } = require('../../utils');
const getBookingFromUr = require('../../utils/get-booking-from-ur');
const airService = require('./AirService');
const createTerminalService = require('../Terminal/Terminal');
const { AirRuntimeError } = require('./AirErrors');
const validateServiceSettings = require('../../utils/validate-service-settings');

module.exports = (settings) => {
  const service = airService(validateServiceSettings(settings));
  const log = (settings.options && settings.options.logFunction) || console.log;
  return {
    shop(options) {
      if (options.async === true) {
        return service.searchLowFaresAsync(options);
      }
      return service.searchLowFares(options);
    },

    retrieveShop(options) {
      return service.searchLowFaresRetrieve(options);
    },

    availability(options) {
      return service.availability(options);
    },

    airPrice(options) {
      return service.airPrice(options);
    },

    fareRules(options) {
      // add request for fare rules
      const request = {
        ...options,
        fetchFareRules: true,
      };

      return service.lookupFareRules(request);
    },

    toQueue(options) {
      return service.gdsQueue(options);
    },

    addSegments(options) {
      if (
        !options.version
        || !options.universalRecordLocatorCode
        || !options.reservationLocatorCode
      ) {
        return this.getBooking({ pnr: options.pnr })
          .then((booking) => {
            const missedOptions = {
              version: options.version || booking.version,
              reservationLocatorCode: (
                options.reservationLocatorCode || booking.uapi_reservation_locator
              ),
              universalRecordLocatorCode: (
                options.universalRecordLocatorCode || booking.uapi_ur_locator
              ),
            };

            return service.addSegments(Object.assign({}, options, missedOptions));
          });
      }

      return service.addSegments(options);
    },

    book(options) {
      return service.airPricePricingSolutionXML(options).then((data) => {
        const tauDate = moment(options.tau || null);
        const tau = tauDate.isValid() ? tauDate.format() : moment().add(3, 'hours').format();
        const bookingParams = Object.assign({}, {
          ticketDate: tau,
          ActionStatusType: 'TAU',
        }, data, options);
        return service.createReservation(bookingParams).catch((err) => {
          if (err instanceof AirRuntimeError.SegmentBookingFailed
              || err instanceof AirRuntimeError.NoValidFare) {
            if (options.allowWaitlist) { // will not have a UR if waitlisting restricted
              const code = err.data['universal:UniversalRecord'].LocatorCode;
              return service.cancelUR({
                LocatorCode: code,
              }).then(() => Promise.reject(err));
            }
            return Promise.reject(err);
          }
          return Promise.reject(err);
        });
      });
    },

    getBooking(options) {
      return this.getUniversalRecordByPNR(options)
        .then(
          ur => getBookingFromUr(ur, options.pnr)
            || Promise.reject(new AirRuntimeError.NoPNRFoundInUR(ur))
        )
        .then((data) => {
          /*
            disable tickets from PNR, because this is known bug in uapi,
            use getTickets(reservationLocatorCode) instead
           */
          const { tickets, ...otherData } = data; // eslint-disable-line no-unused-vars

          return otherData;
        });
    },

    getPNR(options) {
      console.warn('DEPRECATED, will be dropped in next major version, use getBooking');
      return this.getBooking(options);
    },

    getUniversalRecord(options) {
      return service.getUniversalRecord(options);
    },

    getUniversalRecordByPNR(options) {
      return service.getUniversalRecordByPNR(options)
        .catch((err) => {
          // Checking for error type
          if (!(err instanceof AirRuntimeError.NoReservationToImport)) {
            return Promise.reject(err);
          }
          // Creating passive segment to import PNR
          const terminal = createTerminalService(settings);
          const segment = {
            date: moment().add(42, 'days').format('DDMMM'),
            airline: 'OK',
            from: 'DOH',
            to: 'ODM',
            comment: 'NO1',
            class: 'Y',
          };
          const segmentCommand = (
            `0${segment.airline}OPEN${segment.class}${segment.date}${segment.from}${segment.to}${segment.comment}`
          ).toUpperCase();
          const segmentResult = (
            `1. ${segment.airline} OPEN ${segment.class}  ${segment.date} ${segment.from}${segment.to} ${segment.comment}`
          ).toUpperCase();
          const pnrRegExp = new RegExp(`^(?:\\*\\* THIS BF IS CURRENTLY IN USE \\*\\*\\s*)?${options.pnr}`);
          return terminal.executeCommand(`*${options.pnr}`)
            .then((response) => {
              if (!response.match(pnrRegExp)) {
                return Promise.reject(new AirRuntimeError.UnableToOpenPNRInTerminal());
              }
              return Promise.resolve();
            })
            .then(() => terminal.executeCommand(segmentCommand))
            .then((response) => {
              if (response.indexOf(segmentResult) === -1) {
                return Promise.reject(new AirRuntimeError.UnableToAddExtraSegment());
              }
              return Promise.resolve();
            })
            .then(() => {
              const ticketingDate = moment().add(10, 'days').format('DDMMM');
              const command = `T.TAU/${ticketingDate}`;
              return terminal.executeCommand(command)
                .then(() => terminal.executeCommand('R.UAPI+ER'))
                .then(() => terminal.executeCommand('ER'));
            })
            .then((response) => {
              if (
                (!response.match(pnrRegExp))
                || (response.indexOf(segmentResult) === -1)
              ) {
                return Promise.reject(new AirRuntimeError.UnableToSaveBookingWithExtraSegment());
              }
              return Promise.resolve();
            })
            .catch(
              importErr => terminal.closeSession().then(
                () => Promise.reject(
                  new AirRuntimeError.UnableToImportPnr(options, importErr)
                )
              )
            )
            .then(() => terminal.closeSession())
            .then(() => service.getUniversalRecordByPNR(options))
            .then(ur => service.cancelBooking(getBookingFromUr(ur, options.pnr)))
            .then(() => service.getUniversalRecordByPNR(options));
        });
    },

    ticket(options) {
      return this.getBooking(options)
        .then((booking) => {
          const { fareQuotes = [] } = booking;
          const currency = fareQuotes.reduce((accCurrency, fq) => {
            if (accCurrency !== null) {
              return accCurrency;
            }

            const { pricingInfos = [] } = fq;

            return pricingInfos.reduce((totalPriceCurrency, pricingInfo) => {
              if (totalPriceCurrency !== null) {
                return totalPriceCurrency;
              }

              return pricingInfo.totalPrice
                ? pricingInfo.totalPrice.slice(0, 3).trim()
                : null;
            }, null);
          }, null);

          if (!currency || !/[A-Z]{3}/i.test(currency)) {
            return Promise.reject(new AirRuntimeError.CouldNotRetrieveCurrency(options));
          }

          return {
            ReservationLocator: booking.uapi_reservation_locator,
            currency,
          };
        })
        .then(({ ReservationLocator, currency }) => retry({ retries: 3 }, (again, number) => {
          if (settings.debug && number > 1) {
            log(`ticket ${options.pnr} issue attempt number ${number}`);
          }

          return service.ticket({
            ...options,
            ReservationLocator,
            currency
          })
            .catch((err) => {
              if (err instanceof AirRuntimeError.TicketingFoidRequired) {
                return this.getBooking(options)
                  .then(updatedBooking => service.foid(updatedBooking))
                  .then(() => again(err));
              }
              if (err instanceof AirRuntimeError.TicketingPNRBusy) {
                return again(err);
              }
              return Promise.reject(err);
            });
        }));
    },

    flightInfo(options) {
      const parameters = {
        flightInfoCriteria: Array.isArray(options) ? options : [options],
      };
      return service.flightInfo(parameters);
    },

    getTicket(options) {
      return service.getTicket(options)
        .catch((err) => {
          if (!(err instanceof AirRuntimeError.TicketInfoIncomplete)
            && !(err instanceof AirRuntimeError.DuplicateTicketFound)) {
            return Promise.reject(err);
          }

          return this.getBookingByTicketNumber({
            ticketNumber: options.ticketNumber,
          })
            .then(pnr => this.getBooking({ pnr }))
            .then(booking => service.getTicket({
              ...options,
              pnr: booking.pnr,
              uapi_ur_locator: booking.uapi_ur_locator,
              reservationLocatorCode: booking.uapi_reservation_locator
            }));
        });
    },

    async getTickets(options) {
      const { pnr } = options;
      const ur = await this.getUniversalRecordByPNR({ pnr });
      const urData = Array.isArray(ur) ? ur[0] : ur;
      const { uapi_reservation_locator: reservationLocatorCode } = urData;
      try {
        return await service.getTickets({ reservationLocatorCode });
      } catch (err) {
        if (err instanceof AirRuntimeError.NoAgreement) {
          throw err;
        }

        throw new AirRuntimeError.UnableToRetrieveTickets(options, err);
      }
    },

    async getBookingByTicketNumber(options) {
      return new Promise(async (resolve, reject) => {
        try {
          const terminal = createTerminalService(settings);
          const screen = await terminal.executeCommand(`*TE/${options.ticketNumber}`) || '';
          const [_, pnr = null] = screen.match(/RLOC [^\s]{2} ([^\s]{6})/) || [];

          await terminal.closeSession().catch(() => null);

          if (!pnr) {
            reject(new AirRuntimeError.ParseTicketPNRError({ options, screen }));
          }

          resolve(pnr);
        } catch (err) {
          reject(new AirRuntimeError.GetBookingByTicketNumberError({ options }));
        }
      });
    },

    getPNRByTicketNumber(options) {
      console.warn('DEPRECATED, will be dropped in next major version, use getBookingByTicketNumber');
      return this.getBookingByTicketNumber(options);
    },

    searchBookingsByPassengerName(options) {
      const terminal = createTerminalService(settings);
      return terminal.executeCommand(`*-${options.searchPhrase}`)
        .then((firstScreen) => {
          const list = parsers.searchPassengersList(firstScreen);
          if (list) {
            return Promise
              .all(list.map((line) => {
                const localTerminal = createTerminalService(settings);
                return localTerminal
                  .executeCommand(`*-${options.searchPhrase}`)
                  .then((firstScreenAgain) => {
                    if (firstScreenAgain !== firstScreen) {
                      return Promise.reject(
                        new AirRuntimeError.RequestInconsistency({
                          firstScreen,
                          firstScreenAgain,
                        })
                      );
                    }

                    return localTerminal.executeCommand(`*${line.id}`);
                  })
                  .then(parsers.bookingPnr)
                  .then((pnr) => {
                    return localTerminal.closeSession()
                      .then(() => ({ ...line, pnr }));
                  });
              }))
              .then(data => ({ type: 'list', data }));
          }

          const pnr = parsers.bookingPnr(firstScreen);
          if (pnr) {
            return {
              type: 'pnr',
              data: pnr,
            };
          }

          return Promise.reject(
            new AirRuntimeError.MissingPaxListAndBooking(firstScreen)
          );
        })
        .then(results => terminal.closeSession()
          .then(() => results)
          .catch(() => results));
    },

    cancelTicket(options) {
      return this.getTicket(options)
        .then(
          ticketData => service.cancelTicket({
            pnr: ticketData.pnr,
            ticketNumber: options.ticketNumber,
          })
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.FailedToCancelTicket(options, err))
        );
    },

    cancelBooking(options) {
      const ignoreTickets = typeof options.ignoreTickets === 'undefined'
        ? false // default value
        : options.ignoreTickets;

      const checkTickets = (tickets) => {
        return Promise.all(tickets.map(
          (ticketData) => {
            // Check for VOID or REFUND
            const allTicketsVoidOrRefund = ticketData.tickets.every(
              ticket => ticket.coupons.every(
                coupon => coupon.status === 'V' || coupon.status === 'R'
              )
            );
            if (allTicketsVoidOrRefund) {
              return Promise.resolve(true);
            }
            // Check for cancelTicket option
            if (options.cancelTickets !== true) {
              return Promise.reject(new AirRuntimeError.PNRHasOpenTickets());
            }
            // Check for not OPEN/VOID segments
            const hasNotOpenSegment = ticketData.tickets.some(
              ticket => ticket.coupons.some(
                coupon => 'OV'.indexOf(coupon.status) === -1
              )
            );
            if (hasNotOpenSegment) {
              return Promise.reject(new AirRuntimeError.UnableToCancelTicketStatusNotOpen());
            }
            return Promise.all(
              ticketData.tickets.map(
                ticket => (
                  ticket.coupons[0].status !== 'V'
                    ? service.cancelTicket({
                      pnr: options.pnr,
                      ticketNumber: ticket.ticketNumber,
                    })
                    : Promise.resolve(true)
                )
              )
            );
          }
        ));
      };

      return this.getUniversalRecordByPNR(options)
        .then((ur) => {
          const urr = Array.isArray(ur) ? ur[0] : ur;
          const record = {
            reservationLocatorCode: urr.uapi_reservation_locator
          };
          return (ignoreTickets
            ? Promise.resolve([])
            : this.getTickets(record).then(checkTickets)
          )
            .then(() => this.getBooking(options))
            .then(booking => service.cancelBooking(booking))
            .catch(
              err => Promise.reject(new AirRuntimeError.FailedToCancelPnr(options, err))
            );
        });
    },

    cancelPNR(options) {
      console.warn('DEPRECATED, will be dropped in next major version, use cancelBooking');
      return this.cancelBooking(options);
    },

    getExchangeInformation(options) {
      return this.getBooking(options)
        .then(booking => service.exchangeQuote({
          ...options,
          bookingDate: moment(booking.createdAt).format('YYYY-MM-DD'),
        }));
    },

    exchangeBooking(options) {
      return this.getBooking(options)
        .then(booking => service.exchangeBooking({
          ...options,
          uapi_reservation_locator: booking.uapi_reservation_locator,
        }));
    },
  };
};
<commit_msg>:white_check_mark: pass coverage<commit_after>const moment = require('moment');
const retry = require('promise-retry');

const { parsers } = require('../../utils');
const getBookingFromUr = require('../../utils/get-booking-from-ur');
const airService = require('./AirService');
const createTerminalService = require('../Terminal/Terminal');
const { AirRuntimeError } = require('./AirErrors');
const validateServiceSettings = require('../../utils/validate-service-settings');

module.exports = (settings) => {
  const service = airService(validateServiceSettings(settings));
  const log = (settings.options && settings.options.logFunction) || console.log;
  return {
    shop(options) {
      if (options.async === true) {
        return service.searchLowFaresAsync(options);
      }
      return service.searchLowFares(options);
    },

    retrieveShop(options) {
      return service.searchLowFaresRetrieve(options);
    },

    availability(options) {
      return service.availability(options);
    },

    airPrice(options) {
      return service.airPrice(options);
    },

    fareRules(options) {
      // add request for fare rules
      const request = {
        ...options,
        fetchFareRules: true,
      };

      return service.lookupFareRules(request);
    },

    toQueue(options) {
      return service.gdsQueue(options);
    },

    addSegments(options) {
      if (
        !options.version
        || !options.universalRecordLocatorCode
        || !options.reservationLocatorCode
      ) {
        return this.getBooking({ pnr: options.pnr })
          .then((booking) => {
            const missedOptions = {
              version: options.version || booking.version,
              reservationLocatorCode: (
                options.reservationLocatorCode || booking.uapi_reservation_locator
              ),
              universalRecordLocatorCode: (
                options.universalRecordLocatorCode || booking.uapi_ur_locator
              ),
            };

            return service.addSegments(Object.assign({}, options, missedOptions));
          });
      }

      return service.addSegments(options);
    },

    book(options) {
      return service.airPricePricingSolutionXML(options).then((data) => {
        const tauDate = moment(options.tau || null);
        const tau = tauDate.isValid() ? tauDate.format() : moment().add(3, 'hours').format();
        const bookingParams = Object.assign({}, {
          ticketDate: tau,
          ActionStatusType: 'TAU',
        }, data, options);
        return service.createReservation(bookingParams).catch((err) => {
          if (err instanceof AirRuntimeError.SegmentBookingFailed
              || err instanceof AirRuntimeError.NoValidFare) {
            if (options.allowWaitlist) { // will not have a UR if waitlisting restricted
              const code = err.data['universal:UniversalRecord'].LocatorCode;
              return service.cancelUR({
                LocatorCode: code,
              }).then(() => Promise.reject(err));
            }
            return Promise.reject(err);
          }
          return Promise.reject(err);
        });
      });
    },

    getBooking(options) {
      return this.getUniversalRecordByPNR(options)
        .then(
          ur => getBookingFromUr(ur, options.pnr)
            || Promise.reject(new AirRuntimeError.NoPNRFoundInUR(ur))
        )
        .then((data) => {
          /*
            disable tickets from PNR, because this is known bug in uapi,
            use getTickets(reservationLocatorCode) instead
           */
          const { tickets, ...otherData } = data; // eslint-disable-line no-unused-vars

          return otherData;
        });
    },

    getPNR(options) {
      console.warn('DEPRECATED, will be dropped in next major version, use getBooking');
      return this.getBooking(options);
    },

    getUniversalRecord(options) {
      return service.getUniversalRecord(options);
    },

    getUniversalRecordByPNR(options) {
      return service.getUniversalRecordByPNR(options)
        .catch((err) => {
          // Checking for error type
          if (!(err instanceof AirRuntimeError.NoReservationToImport)) {
            return Promise.reject(err);
          }
          // Creating passive segment to import PNR
          const terminal = createTerminalService(settings);
          const segment = {
            date: moment().add(42, 'days').format('DDMMM'),
            airline: 'OK',
            from: 'DOH',
            to: 'ODM',
            comment: 'NO1',
            class: 'Y',
          };
          const segmentCommand = (
            `0${segment.airline}OPEN${segment.class}${segment.date}${segment.from}${segment.to}${segment.comment}`
          ).toUpperCase();
          const segmentResult = (
            `1. ${segment.airline} OPEN ${segment.class}  ${segment.date} ${segment.from}${segment.to} ${segment.comment}`
          ).toUpperCase();
          const pnrRegExp = new RegExp(`^(?:\\*\\* THIS BF IS CURRENTLY IN USE \\*\\*\\s*)?${options.pnr}`);
          return terminal.executeCommand(`*${options.pnr}`)
            .then((response) => {
              if (!response.match(pnrRegExp)) {
                return Promise.reject(new AirRuntimeError.UnableToOpenPNRInTerminal());
              }
              return Promise.resolve();
            })
            .then(() => terminal.executeCommand(segmentCommand))
            .then((response) => {
              if (response.indexOf(segmentResult) === -1) {
                return Promise.reject(new AirRuntimeError.UnableToAddExtraSegment());
              }
              return Promise.resolve();
            })
            .then(() => {
              const ticketingDate = moment().add(10, 'days').format('DDMMM');
              const command = `T.TAU/${ticketingDate}`;
              return terminal.executeCommand(command)
                .then(() => terminal.executeCommand('R.UAPI+ER'))
                .then(() => terminal.executeCommand('ER'));
            })
            .then((response) => {
              if (
                (!response.match(pnrRegExp))
                || (response.indexOf(segmentResult) === -1)
              ) {
                return Promise.reject(new AirRuntimeError.UnableToSaveBookingWithExtraSegment());
              }
              return Promise.resolve();
            })
            .catch(
              importErr => terminal.closeSession().then(
                () => Promise.reject(
                  new AirRuntimeError.UnableToImportPnr(options, importErr)
                )
              )
            )
            .then(() => terminal.closeSession())
            .then(() => service.getUniversalRecordByPNR(options))
            .then(ur => service.cancelBooking(getBookingFromUr(ur, options.pnr)))
            .then(() => service.getUniversalRecordByPNR(options));
        });
    },

    ticket(options) {
      return this.getBooking(options)
        .then((booking) => {
          const { fareQuotes = [] } = booking;
          const currency = fareQuotes.reduce((accCurrency, fq) => {
            if (accCurrency !== null) {
              return accCurrency;
            }

            const { pricingInfos = [] } = fq;

            return pricingInfos.reduce((totalPriceCurrency, pricingInfo) => {
              if (totalPriceCurrency !== null) {
                return totalPriceCurrency;
              }

              return pricingInfo.totalPrice
                ? pricingInfo.totalPrice.slice(0, 3).trim()
                : null;
            }, null);
          }, null);

          if (!currency || !/[A-Z]{3}/i.test(currency)) {
            return Promise.reject(new AirRuntimeError.CouldNotRetrieveCurrency(options));
          }

          return {
            ReservationLocator: booking.uapi_reservation_locator,
            currency,
          };
        })
        .then(({ ReservationLocator, currency }) => retry({ retries: 3 }, (again, number) => {
          if (settings.debug && number > 1) {
            log(`ticket ${options.pnr} issue attempt number ${number}`);
          }

          return service.ticket({
            ...options,
            ReservationLocator,
            currency
          })
            .catch((err) => {
              if (err instanceof AirRuntimeError.TicketingFoidRequired) {
                return this.getBooking(options)
                  .then(updatedBooking => service.foid(updatedBooking))
                  .then(() => again(err));
              }
              if (err instanceof AirRuntimeError.TicketingPNRBusy) {
                return again(err);
              }
              return Promise.reject(err);
            });
        }));
    },

    flightInfo(options) {
      const parameters = {
        flightInfoCriteria: Array.isArray(options) ? options : [options],
      };
      return service.flightInfo(parameters);
    },

    getTicket(options) {
      return service.getTicket(options)
        .catch((err) => {
          if (!(err instanceof AirRuntimeError.TicketInfoIncomplete)
            && !(err instanceof AirRuntimeError.DuplicateTicketFound)) {
            return Promise.reject(err);
          }

          return this.getPNRByTicketNumber({
            ticketNumber: options.ticketNumber,
          })
            .then(pnr => this.getBooking({ pnr }))
            .then(booking => service.getTicket({
              ...options,
              pnr: booking.pnr,
              uapi_ur_locator: booking.uapi_ur_locator,
              reservationLocatorCode: booking.uapi_reservation_locator
            }));
        });
    },

    async getTickets(options) {
      const { pnr } = options;
      const ur = await this.getUniversalRecordByPNR({ pnr });
      const urData = Array.isArray(ur) ? ur[0] : ur;
      const { uapi_reservation_locator: reservationLocatorCode } = urData;
      try {
        return await service.getTickets({ reservationLocatorCode });
      } catch (err) {
        if (err instanceof AirRuntimeError.NoAgreement) {
          throw err;
        }

        throw new AirRuntimeError.UnableToRetrieveTickets(options, err);
      }
    },

    async getBookingByTicketNumber(options) {
      return new Promise(async (resolve, reject) => {
        try {
          const terminal = createTerminalService(settings);
          const screen = await terminal.executeCommand(`*TE/${options.ticketNumber}`) || '';
          const [_, pnr = null] = screen.match(/RLOC [^\s]{2} ([^\s]{6})/) || [];

          await terminal.closeSession().catch(() => null);

          if (!pnr) {
            reject(new AirRuntimeError.ParseTicketPNRError({ options, screen }));
          }

          resolve(pnr);
        } catch (err) {
          reject(new AirRuntimeError.GetBookingByTicketNumberError({ options }));
        }
      });
    },

    getPNRByTicketNumber(options) {
      console.warn('DEPRECATED, will be dropped in next major version, use getBookingByTicketNumber');
      return this.getBookingByTicketNumber(options);
    },

    searchBookingsByPassengerName(options) {
      const terminal = createTerminalService(settings);
      return terminal.executeCommand(`*-${options.searchPhrase}`)
        .then((firstScreen) => {
          const list = parsers.searchPassengersList(firstScreen);
          if (list) {
            return Promise
              .all(list.map((line) => {
                const localTerminal = createTerminalService(settings);
                return localTerminal
                  .executeCommand(`*-${options.searchPhrase}`)
                  .then((firstScreenAgain) => {
                    if (firstScreenAgain !== firstScreen) {
                      return Promise.reject(
                        new AirRuntimeError.RequestInconsistency({
                          firstScreen,
                          firstScreenAgain,
                        })
                      );
                    }

                    return localTerminal.executeCommand(`*${line.id}`);
                  })
                  .then(parsers.bookingPnr)
                  .then((pnr) => {
                    return localTerminal.closeSession()
                      .then(() => ({ ...line, pnr }));
                  });
              }))
              .then(data => ({ type: 'list', data }));
          }

          const pnr = parsers.bookingPnr(firstScreen);
          if (pnr) {
            return {
              type: 'pnr',
              data: pnr,
            };
          }

          return Promise.reject(
            new AirRuntimeError.MissingPaxListAndBooking(firstScreen)
          );
        })
        .then(results => terminal.closeSession()
          .then(() => results)
          .catch(() => results));
    },

    cancelTicket(options) {
      return this.getTicket(options)
        .then(
          ticketData => service.cancelTicket({
            pnr: ticketData.pnr,
            ticketNumber: options.ticketNumber,
          })
        )
        .catch(
          err => Promise.reject(new AirRuntimeError.FailedToCancelTicket(options, err))
        );
    },

    cancelBooking(options) {
      const ignoreTickets = typeof options.ignoreTickets === 'undefined'
        ? false // default value
        : options.ignoreTickets;

      const checkTickets = (tickets) => {
        return Promise.all(tickets.map(
          (ticketData) => {
            // Check for VOID or REFUND
            const allTicketsVoidOrRefund = ticketData.tickets.every(
              ticket => ticket.coupons.every(
                coupon => coupon.status === 'V' || coupon.status === 'R'
              )
            );
            if (allTicketsVoidOrRefund) {
              return Promise.resolve(true);
            }
            // Check for cancelTicket option
            if (options.cancelTickets !== true) {
              return Promise.reject(new AirRuntimeError.PNRHasOpenTickets());
            }
            // Check for not OPEN/VOID segments
            const hasNotOpenSegment = ticketData.tickets.some(
              ticket => ticket.coupons.some(
                coupon => 'OV'.indexOf(coupon.status) === -1
              )
            );
            if (hasNotOpenSegment) {
              return Promise.reject(new AirRuntimeError.UnableToCancelTicketStatusNotOpen());
            }
            return Promise.all(
              ticketData.tickets.map(
                ticket => (
                  ticket.coupons[0].status !== 'V'
                    ? service.cancelTicket({
                      pnr: options.pnr,
                      ticketNumber: ticket.ticketNumber,
                    })
                    : Promise.resolve(true)
                )
              )
            );
          }
        ));
      };

      return this.getUniversalRecordByPNR(options)
        .then((ur) => {
          const urr = Array.isArray(ur) ? ur[0] : ur;
          const record = {
            reservationLocatorCode: urr.uapi_reservation_locator
          };
          return (ignoreTickets
            ? Promise.resolve([])
            : this.getTickets(record).then(checkTickets)
          )
            .then(() => this.getBooking(options))
            .then(booking => service.cancelBooking(booking))
            .catch(
              err => Promise.reject(new AirRuntimeError.FailedToCancelPnr(options, err))
            );
        });
    },

    cancelPNR(options) {
      console.warn('DEPRECATED, will be dropped in next major version, use cancelBooking');
      return this.cancelBooking(options);
    },

    getExchangeInformation(options) {
      return this.getBooking(options)
        .then(booking => service.exchangeQuote({
          ...options,
          bookingDate: moment(booking.createdAt).format('YYYY-MM-DD'),
        }));
    },

    exchangeBooking(options) {
      return this.getBooking(options)
        .then(booking => service.exchangeBooking({
          ...options,
          uapi_reservation_locator: booking.uapi_reservation_locator,
        }));
    },
  };
};
<|endoftext|>


<commit_before>'use strict';

var Task    = require('./task');

module.exports = Task.extend({
  verbose: true,

  init: function() {
    this.watcher = this.watcher || new (require('sane').Watcher)(this.watchedDir, {
      verbose: this.verbose,
      poll: this.polling()
    });

    this.watcher.on('change', this.didChange.bind(this));
    this.watcher.on('add',    this.didAdd.bind(this));
    this.watcher.on('delete', this.didDelete.bind(this));
  },

  didChange: function (filepath) {
    this.ui.writeLine('Server file changed: ' + filepath);

    this.analytics.track({
      name: 'server file change',
      description: 'File changed: "' + filepath + '"'
    });
  },

  didAdd: function (filepath) {
    this.ui.writeLine('Server file added: ' + filepath);

    this.analytics.track({
      name: 'server file addition',
      description: 'File added: "' + filepath + '"'
    });
  },

  didDelete: function (filepath) {
    this.ui.writeLine('Server file deleted: ' + filepath);

    this.analytics.track({
      name: 'server file deletion',
      description: 'File deleted: "' + filepath + '"'
    });
  },

  then: function() {
    return this.watcher.then.apply(this.watcher, arguments);
  },

  on: function() {
    this.watcher.on.apply(this.watcher, arguments);
  },

  off: function() {
    this.watcher.off.apply(this.watcher, arguments);
  },

  polling: function () {
    return this.options && this.options.watcher === 'polling';
  }
});
<commit_msg>use new sane watcher form (1 top level api)<commit_after>'use strict';

var Task    = require('./task');

module.exports = Task.extend({
  verbose: true,

  init: function() {
    this.watcher = this.watcher || new (require('sane'))(this.watchedDir, {
      verbose: this.verbose,
      poll: this.polling()
    });

    this.watcher.on('change', this.didChange.bind(this));
    this.watcher.on('add',    this.didAdd.bind(this));
    this.watcher.on('delete', this.didDelete.bind(this));
  },

  didChange: function (filepath) {
    this.ui.writeLine('Server file changed: ' + filepath);

    this.analytics.track({
      name: 'server file change',
      description: 'File changed: "' + filepath + '"'
    });
  },

  didAdd: function (filepath) {
    this.ui.writeLine('Server file added: ' + filepath);

    this.analytics.track({
      name: 'server file addition',
      description: 'File added: "' + filepath + '"'
    });
  },

  didDelete: function (filepath) {
    this.ui.writeLine('Server file deleted: ' + filepath);

    this.analytics.track({
      name: 'server file deletion',
      description: 'File deleted: "' + filepath + '"'
    });
  },

  then: function() {
    return this.watcher.then.apply(this.watcher, arguments);
  },

  on: function() {
    this.watcher.on.apply(this.watcher, arguments);
  },

  off: function() {
    this.watcher.off.apply(this.watcher, arguments);
  },

  polling: function () {
    return this.options && this.options.watcher === 'polling';
  }
});
<|endoftext|>


<commit_before>/*
 * remote.js: Commands related to working with remote configs
 *
 * (C) 2012, Nodejitsu Inc.
 *
 */

var fs = require('fs'),
    quill = require('../../quill');

var remote = exports;

remote.usage = [
  '`quill remote` commands allow you to work with remote configs',
  '',
  'quill remote create <name>',
  'quill remote list',
  'quill remote delete <name>',
  'quill remote view <name>',
  'quill remote get <name> <key>',
  'quill remote set <name> <key> <value>',
  'quill remote clear <name> <key>',
  'quill remote load <name> <file>'
];

//
// ### function create (name, callback)
// Creates a remote config called `name`.
//
remote.create = function (name, callback) {
  if (name) {
    quill.prompt.override.name = name;
  }

  quill.prompt.get(['name'], function (err, result) {
    if (err) {
      return callback(err);
    }

    quill.log.info('Creating remote config: ' + result.name.magenta);
    quill.remote.create(result.name, callback);
  });
};

//
// ### function list (callback)
// Lists remote configs.
//
remote.list = function (callback) {
  quill.remote.list(function (err, remotes) {
    if (err) {
      return callback(err);
    }

    var rows = [['name']],
        colors = ['underline'];

    remotes.forEach(function (remote) {
      rows.push([remote.name]);
    });

    quill.inspect.putRows('data', rows, colors);
    callback();
  });
};

//
// ### function delete (name, callback)
// Delete `name` remote config.
//
remote.delete = function (name, callback) {
  if (name) {
    quill.prompt.override.name = name;
  }

  quill.prompt.get(['name'], function (err, result) {
    if (err) {
      return callback(err);
    }

    quill.log.info('Deleting remote config: ' + result.name.magenta);
    quill.remote.destroy(result.name, callback);
  });
};

//
// ### function view (name, callback)
// View `name` remote config.
//
remote.view = function (name, callback) {
  if (name) {
    quill.prompt.override.name = name;
  }

  quill.prompt.get(['name'], function (err, result) {
    if (err) {
      return callback(err);
    }

    quill.log.info('Viewing remote config: ' + result.name.magenta);
    quill.remote.get(result.name, function (err, remote) {
      if (err) {
        return callback(err);
      }

      quill.inspect.putObject(remote);
      callback();
    });
  });
};

//
// ### function get (name, key, callback)
// Get key `key` from remote config `name`.
//
remote.get = function (name, key, callback) {
  if (!name || !key) {
    return callback(new Error('Config name and key required.'));
  }

  quill.remote.get(name, function (err, remote) {
    if (err) {
      return callback(err);
    }

    quill.log.data(key.yellow + ' ' + remote.settings[key].magenta);
    callback();
  });
};

//
// ### function set (name, key, value, callback)
// Set key `key` in remote config `name` to `value`.
//
remote.set = function (name, key, value, callback) {
  if (!name || !key || !value) {
    return callback(new Error('Config name, key and value required.'));
  }

  quill.remote.set(name, key, value, callback);
};

//
// ### function clear (name, key, callback)
// Clear key `key` from remote config `name`.
//
remote.clear = function (name, key, callback) {
  if (!name || !key) {
    return callback(new Error('Config name and key required.'));
  }

  quill.remote.clear(name, key, callback);
};

remote.load = function (name, file, callback) {
  if (!name || !file) {
    return callback(new Error('Config name and file required.'));
  }

  quill.log.info('Loading file ' + file.magenta + ' into ' + name.magenta + ' config');

  fs.readFile(file, function (err, data) {
    if (err) {
      return callback(err);
    }

    data = JSON.parse(data);
    quill.remote.destroy(name, function () {
      //
      // Ignore errors here.
      //
      quill.remote.create(name, data, callback);
    });
  });
};
<commit_msg>[api] Add support for merging config files<commit_after>/*
 * remote.js: Commands related to working with remote configs
 *
 * (C) 2012, Nodejitsu Inc.
 *
 */

var fs = require('fs'),
    quill = require('../../quill');

var remote = exports;

remote.usage = [
  '`quill remote` commands allow you to work with remote configs',
  '',
  'quill remote create <name>',
  'quill remote list',
  'quill remote delete <name>',
  'quill remote view <name>',
  'quill remote get <name> <key>',
  'quill remote set <name> <key> <value>',
  'quill remote clear <name> <key>',
  'quill remote load <name> <file>'
];

//
// ### function create (name, callback)
// Creates a remote config called `name`.
//
remote.create = function (name, callback) {
  if (name) {
    quill.prompt.override.name = name;
  }

  quill.prompt.get(['name'], function (err, result) {
    if (err) {
      return callback(err);
    }

    quill.log.info('Creating remote config: ' + result.name.magenta);
    quill.remote.create(result.name, callback);
  });
};

//
// ### function list (callback)
// Lists remote configs.
//
remote.list = function (callback) {
  quill.remote.list(function (err, remotes) {
    if (err) {
      return callback(err);
    }

    var rows = [['name']],
        colors = ['underline'];

    remotes.forEach(function (remote) {
      rows.push([remote.name]);
    });

    quill.inspect.putRows('data', rows, colors);
    callback();
  });
};

//
// ### function delete (name, callback)
// Delete `name` remote config.
//
remote.delete = function (name, callback) {
  if (name) {
    quill.prompt.override.name = name;
  }

  quill.prompt.get(['name'], function (err, result) {
    if (err) {
      return callback(err);
    }

    quill.log.info('Deleting remote config: ' + result.name.magenta);
    quill.remote.destroy(result.name, callback);
  });
};

//
// ### function view (name, callback)
// View `name` remote config.
//
remote.view = function (name, callback) {
  if (name) {
    quill.prompt.override.name = name;
  }

  quill.prompt.get(['name'], function (err, result) {
    if (err) {
      return callback(err);
    }

    quill.log.info('Viewing remote config: ' + result.name.magenta);
    quill.remote.get(result.name, function (err, remote) {
      if (err) {
        return callback(err);
      }

      quill.inspect.putObject(remote);
      callback();
    });
  });
};

//
// ### function get (name, key, callback)
// Get key `key` from remote config `name`.
//
remote.get = function (name, key, callback) {
  if (!name || !key) {
    return callback(new Error('Config name and key required.'));
  }

  quill.remote.get(name, function (err, remote) {
    if (err) {
      return callback(err);
    }

    quill.log.data(key.yellow + ' ' + remote.settings[key].magenta);
    callback();
  });
};

//
// ### function set (name, key, value, callback)
// Set key `key` in remote config `name` to `value`.
//
remote.set = function (name, key, value, callback) {
  if (!name || !key || !value) {
    return callback(new Error('Config name, key and value required.'));
  }

  quill.remote.set(name, key, value, callback);
};

//
// ### function clear (name, key, callback)
// Clear key `key` from remote config `name`.
//
remote.clear = function (name, key, callback) {
  if (!name || !key) {
    return callback(new Error('Config name and key required.'));
  }

  quill.remote.clear(name, key, callback);
};

remote.load = function (name, file, callback) {
  if (!name || !file) {
    return callback(new Error('Config name and file required.'));
  }

  quill.log.info('Loading file ' + file.magenta + ' into ' + name.magenta + ' config');

  fs.readFile(file, function (err, data) {
    if (err) {
      return callback(err);
    }

    data = JSON.parse(data);
    quill.remote.destroy(name, function () {
      //
      // Ignore errors here.
      //
      quill.remote.create(name, data, callback);
    });
  });
};

//
// ### function merge (name, file, callback)
// Merge `file` into remote config `name`.
//
remote.merge = function (name, file, callback) {
  if (!name || !file) {
    return callback(new Error('Config name and file required.'));
  }

  quill.log.info('Merging file ' + file.magenta + ' into ' + name.magenta + ' config');

  fs.readFile(file, function (err, data) {
    if (err) {
      return callback(err);
    }

    data = JSON.parse(data);

    //
    // Instead of merging config on the server side, merge it locally:
    // fetch it, merge and recreate.
    //
    quill.remote.get(name, function (err, remote) {
      if (err) {
        return callback(err);
      }

      quill.remote.destroy(name, function () {
        if (err) {
          return callback(err);
        }

        Object.keys(data).forEach(function (key) {
          remote[key] = data[key];
        });

        quill.remote.create(name, remote, callback);
      });
    });
  });
};
<|endoftext|>


<commit_before>/*
 * redmine-client
 * https://github.com/jthomerson/redmine-client
 *
 * Copyright (c) 2014 Jeremy Thomerson
 * Licensed under the MIT license.
 */

var DB = require('tingodb')().Db;

function Poller(redmine) {
   this.running = false;
   this.redmine = redmine;
   this.db = new DB(redmine.config.polling.dbPath, {});
   this.issues = this.db.collection('issues');
}

Poller.prototype = {

   run: function() {
      if (this.running) {
         return;
      }
      this.running = true;
      this.poll();
      setInterval(
         (function(self) {
            return function() {
               self.poll();
            };
         })(this),
         this.redmine.config.polling.everySeconds * 1000
      );
   },

   poll: function() {
      console.log('Polling Redmine');
      var self = this;
      this.redmine.getAllIssues({ updated_on: '>=' + this.redmine.util.daysAgo(1).dateFormat(), limit: 10 }).then(function(issuesResp) {
         self.issuesRetrieved(issuesResp);
      });
   },

   issuesRetrieved: function(issuesResp) {
      console.log('poller got issues: ' + issuesResp.total_count + ' (' + issuesResp.limit + ')');
      if (issuesResp.limit < issuesResp.total_count) {
         console.log('need to get more issues');
      }

      var map = {};
      for (var i = 0; i < issuesResp.issues.length; i++) {
         if (map[issuesResp.issues[i].id]) {
            console.log('already had issue: ' + issuesResp.issues[i].id);
         }
         map[issuesResp.issues[i].id] = true;
         this.emitIssueIfNecessary(issuesResp.issues[i]);
      }
   },

   emitIssueIfNecessary: function(iss) {
      var self = this;
      // do this for DB:
      iss._id = iss.id;

      self.issues.findOne({ id: iss.id }, function(err, doc) {
         if (err) {
            console.log('ERROR: data retrieval error trying to find issue ' + iss.id + ' in local DB: ' + err);
            return;
         }

         if (doc) {
            // console.log('found iss: ' + iss.id + ' already in DB');
            // see if the updated_on has changed in the retrieved doc
            if (doc.updated_on !== iss.updated_on) {
               self.issues.save(iss);
               self.redmine.emit('updatedissue', iss);
            }
         } else {
            // console.log('new iss: ' + iss.id + ' not in DB');
            self.issues.save(iss);
            self.redmine.emit('newissue', iss);
         }
      });
   }

};

module.exports = Poller;
<commit_msg>better updated vs. new issue detection logic<commit_after>/*
 * redmine-client
 * https://github.com/jthomerson/redmine-client
 *
 * Copyright (c) 2014 Jeremy Thomerson
 * Licensed under the MIT license.
 */

var DB = require('tingodb')().Db;

function Poller(redmine) {
   this.running = false;
   this.redmine = redmine;
   this.db = new DB(redmine.config.polling.dbPath, {});
   this.issues = this.db.collection('issues');
}

Poller.prototype = {

   run: function() {
      if (this.running) {
         return;
      }
      this.running = true;
      this.poll();
      setInterval(
         (function(self) {
            return function() {
               self.poll();
            };
         })(this),
         this.redmine.config.polling.everySeconds * 1000
      );
   },

   poll: function() {
      console.log('Polling Redmine');
      var self = this;
      this.redmine.getAllIssues({ updated_on: '>=' + this.redmine.util.daysAgo(1).dateFormat(), limit: 10 }).then(function(issuesResp) {
         self.issuesRetrieved(issuesResp);
      });
   },

   issuesRetrieved: function(issuesResp) {
      console.log('poller got issues: ' + issuesResp.total_count + ' (' + issuesResp.limit + ')');
      if (issuesResp.limit < issuesResp.total_count) {
         console.log('need to get more issues');
      }

      var map = {};
      for (var i = 0; i < issuesResp.issues.length; i++) {
         if (map[issuesResp.issues[i].id]) {
            console.log('already had issue: ' + issuesResp.issues[i].id);
         }
         map[issuesResp.issues[i].id] = true;
         this.emitIssueIfNecessary(issuesResp.issues[i]);
      }
   },

   emitIssueIfNecessary: function(iss) {
      var self = this;
      // do this for DB:
      iss._id = iss.id;

      self.issues.findOne({ id: iss.id }, function(err, doc) {
         if (err) {
            console.log('ERROR: data retrieval error trying to find issue ' + iss.id + ' in local DB: ' + err);
            return;
         }

         if (doc) {
            // we have seen it before, so it can not be a 'newissue' event
            if (doc.updated_on !== iss.updated_on) {
               self.redmine.emit('updatedissue', iss);
            }
         } else {
            // We have not seen it, but that does not necessarily mean it is
            // a brand new issue. If there were issues that existed before
            // we started tracking them in our DB, they could be updates
            if (iss.created_on === iss.updated_on) {
               // This is a new issue becase the updated date is exactly the
               // same as the created date. Note that there is a race condition
               // that *could* happen here if an issue is both created and then
               // updated between our polls. Then an issue would get an updated
               // event even though we'd never sent a "newissue" event. There
               // are ways we could code against this, but the side effects are
               // not bad enough to warrant the extra complexity.
               self.redmine.emit('newissue', iss);
            } else {
               // This is essentially the "fallback" catch block for an issue
               // that was updated, but we have not seen it before so it did
               // not go into our normal "updated" block above
               self.redmine.emit('updatedissue', iss);
            }
         }
         self.issues.save(iss);
      });
   }

};

module.exports = Poller;
<|endoftext|>


<commit_before>var RorVsWild = this.RorVsWild = {};

RorVsWild.Local = function(container) {
  this.root = container
  this.active = false
  this.data = JSON.parse((this.container = container).getAttribute("data-json"))
  this.requests = this.data.map(function(data) {
    return new RorVsWild.Local.Request(data)
  })
  this.render()
}

RorVsWild.Local.prototype.render = function() {
  Barber.render("RorVsWild.Local", this, this.root)
}

RorVsWild.Local.prototype.lastRuntime = function() {
  return this.requests[0].runtime()
}

RorVsWild.Local.prototype.toggle = function() {
  this.active ? this.collapse() : this.expand()
}

RorVsWild.Local.prototype.expand = function() {
  this.currentRequest = this.requests[0]
  this.active = true
  this.render()
}

RorVsWild.Local.prototype.collapse = function() {
  this.active = false
  this.render()
}

RorVsWild.Local.formatRuntime = function(runtime) {
  return runtime > 0 && runtime < 1 ? "<1" : Math.round(runtime)
}

RorVsWild.Local.formatImpact = function(impact) {
  return impact > 0 && impact < 1 ? "<1" : Math.round(impact)
}

RorVsWild.Local.formatDateTime = function(date) {
  var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  var minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()
  var hours = date.getHours() < 10 ? "0" +  date.getHours() : date.getHours()
  return [date.getDate(), months[date.getMonth()], hours + ":" + minutes].join(" ")
}

RorVsWild.Local.prototype.goToRequestDetails = function(event) {
  var id = parseInt(event.currentTarget.getAttribute("data-request-id"))
  this.currentRequest = this.requests.find(function(req) { return req.id == id })
  console.log(this.currentRequest)
  this.render()
}

RorVsWild.Local.prototype.goToHistory = function(event) {
  this.currentRequest = null
  this.render()
}

RorVsWild.Local.prototype.containerStyle = function() {
  if (!this.active)
    return 'display: none;'
}

RorVsWild.Local.lastId = 0

RorVsWild.Local.nextId = function() {
  return RorVsWild.Local.lastId += 1
}

RorVsWild.Local.Request = function(data) {
  this.id = RorVsWild.Local.nextId()
  this.data = data
  this.name = data.name
  this.path = data.path
  this.startedAt = RorVsWild.Local.formatDateTime(new Date(data.started_at))
}

RorVsWild.Local.Request.prototype.runtime = function() {
  return RorVsWild.Local.formatRuntime(this.data.runtime)
}

RorVsWild.Local.Request.prototype.sections = function() {
  return this.data.sections.map(function(section) {
    var runtime = (section.total_runtime - section.children_runtime)
    return {
      impact: RorVsWild.Local.formatImpact(runtime * 100 / this.data.runtime),
      averageRuntime: RorVsWild.Local.formatRuntime(runtime / section.calls),
      command: section.command,
      calls: section.calls,
      kind: section.kind.substring(0, 7),
      file: section.file,
      line: section.line,
      runtime: runtime,
    }
  }.bind(this)).sort(function(a, b) { return b.runtime - a.runtime })
}
<commit_msg>Remove console.log.<commit_after>var RorVsWild = this.RorVsWild = {};

RorVsWild.Local = function(container) {
  this.root = container
  this.active = false
  this.data = JSON.parse((this.container = container).getAttribute("data-json"))
  this.requests = this.data.map(function(data) {
    return new RorVsWild.Local.Request(data)
  })
  this.render()
}

RorVsWild.Local.prototype.render = function() {
  Barber.render("RorVsWild.Local", this, this.root)
}

RorVsWild.Local.prototype.lastRuntime = function() {
  return this.requests[0].runtime()
}

RorVsWild.Local.prototype.toggle = function() {
  this.active ? this.collapse() : this.expand()
}

RorVsWild.Local.prototype.expand = function() {
  this.currentRequest = this.requests[0]
  this.active = true
  this.render()
}

RorVsWild.Local.prototype.collapse = function() {
  this.active = false
  this.render()
}

RorVsWild.Local.formatRuntime = function(runtime) {
  return runtime > 0 && runtime < 1 ? "<1" : Math.round(runtime)
}

RorVsWild.Local.formatImpact = function(impact) {
  return impact > 0 && impact < 1 ? "<1" : Math.round(impact)
}

RorVsWild.Local.formatDateTime = function(date) {
  var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  var minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()
  var hours = date.getHours() < 10 ? "0" +  date.getHours() : date.getHours()
  return [date.getDate(), months[date.getMonth()], hours + ":" + minutes].join(" ")
}

RorVsWild.Local.prototype.goToRequestDetails = function(event) {
  var id = parseInt(event.currentTarget.getAttribute("data-request-id"))
  this.currentRequest = this.requests.find(function(req) { return req.id == id })
  this.render()
}

RorVsWild.Local.prototype.goToHistory = function(event) {
  this.currentRequest = null
  this.render()
}

RorVsWild.Local.prototype.containerStyle = function() {
  if (!this.active)
    return 'display: none;'
}

RorVsWild.Local.lastId = 0

RorVsWild.Local.nextId = function() {
  return RorVsWild.Local.lastId += 1
}

RorVsWild.Local.Request = function(data) {
  this.id = RorVsWild.Local.nextId()
  this.data = data
  this.name = data.name
  this.path = data.path
  this.startedAt = RorVsWild.Local.formatDateTime(new Date(data.started_at))
}

RorVsWild.Local.Request.prototype.runtime = function() {
  return RorVsWild.Local.formatRuntime(this.data.runtime)
}

RorVsWild.Local.Request.prototype.sections = function() {
  return this.data.sections.map(function(section) {
    var runtime = (section.total_runtime - section.children_runtime)
    return {
      impact: RorVsWild.Local.formatImpact(runtime * 100 / this.data.runtime),
      averageRuntime: RorVsWild.Local.formatRuntime(runtime / section.calls),
      command: section.command,
      calls: section.calls,
      kind: section.kind.substring(0, 7),
      file: section.file,
      line: section.line,
      runtime: runtime,
    }
  }.bind(this)).sort(function(a, b) { return b.runtime - a.runtime })
}
<|endoftext|>