text:
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Handles web page requests for gnubby sign requests.
 *
 */

'use strict';

var gnubbySignRequestQueue;

/**
 * Initialize request queue.
 */
function initRequestQueue() {
  gnubbySignRequestQueue =
      new OriginKeyedRequestQueue(FACTORY_REGISTRY.getSystemTimer());
}

/**
 * Handles a U2F sign request.
 * @param {MessageSender} messageSender The message sender.
 * @param {Object} request The web page's sign request.
 * @param {Function} sendResponse Called back with the result of the sign.
 * @return {Closeable} Request handler that should be closed when the browser
 *     message channel is closed.
 */
function handleU2fSignRequest(messageSender, request, sendResponse) {
  var sentResponse = false;
  var queuedSignRequest;

  function sendErrorResponse(error) {
    sendResponseOnce(
        sentResponse, queuedSignRequest,
        makeU2fErrorResponse(request, error.errorCode, error.errorMessage),
        sendResponse);
  }

  function sendSuccessResponse(challenge, info, browserData) {
    var responseData = makeU2fSignResponseDataFromChallenge(challenge);
    addSignatureAndBrowserDataToResponseData(
        responseData, info, browserData, 'clientData');
    var response = makeU2fSuccessResponse(request, responseData);
    sendResponseOnce(sentResponse, queuedSignRequest, response, sendResponse);
  }

  var sender = createSenderFromMessageSender(messageSender);
  if (!sender) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }
  if (sender.origin.indexOf('http://') === 0 && !HTTP_ORIGINS_ALLOWED) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }

  queuedSignRequest = validateAndEnqueueSignRequest(
      sender, request, sendErrorResponse, sendSuccessResponse);
  if (queuedSignRequest) {
    chrome.cryptotokenPrivate.recordSignRequest(sender.tabId, sender.frameId);
  }
  return queuedSignRequest;
}

/**
 * Creates a base U2F responseData object from the server challenge.
 * @param {SignChallenge} challenge The server challenge.
 * @return {Object} The responseData object.
 */
function makeU2fSignResponseDataFromChallenge(challenge) {
  var responseData = {'keyHandle': challenge['keyHandle']};
  return responseData;
}

/**
 * Adds the browser data and signature values to a responseData object.
 * @param {Object} responseData The "base" responseData object.
 * @param {string} signatureData The signature data.
 * @param {string} browserData The browser data generated from the challenge.
 * @param {string} browserDataName The name of the browser data key in the
 *     responseData object.
 */
function addSignatureAndBrowserDataToResponseData(
    responseData, signatureData, browserData, browserDataName) {
  responseData[browserDataName] = B64_encode(UTIL_StringToBytes(browserData));
  responseData['signatureData'] = signatureData;
}

/**
 * Validates a sign request using the given sign challenges name, and, if valid,
 * enqueues the sign request for eventual processing.
 * @param {WebRequestSender} sender The sender of the message.
 * @param {Object} request The web page's sign request.
 * @param {function(U2fError)} errorCb Error callback.
 * @param {function(SignChallenge, string, string)} successCb Success callback.
 * @return {Closeable} Request handler that should be closed when the browser
 *     message channel is closed.
 */
function validateAndEnqueueSignRequest(sender, request, errorCb, successCb) {
  function timeout() {
    errorCb({errorCode: ErrorCodes.TIMEOUT});
  }

  if (!isValidSignRequest(request)) {
    errorCb({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }

  // The typecast is necessary because getSignChallenges can return undefined.
  // On the other hand, a valid sign request can't contain an undefined sign
  // challenge list, so the typecast is safe.
  var signChallenges =
      /** @type {!Array<SignChallenge>} */ (getSignChallenges(request));
  var appId;
  if (request['appId']) {
    appId = request['appId'];
  } else if (signChallenges.length) {
    appId = signChallenges[0]['appId'];
  }
  // Sanity check
  if (!appId) {
    console.warn(UTIL_fmt('empty sign appId?'));
    errorCb({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }
  var timeoutValueSeconds = getTimeoutValueFromRequest(request);
  // Attenuate watchdog timeout value less than the signer's timeout, so the
  // watchdog only fires after the signer could reasonably have called back,
  // not before.
  timeoutValueSeconds = attenuateTimeoutInSeconds(
      timeoutValueSeconds, MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2);
  var watchdog = new WatchdogRequestHandler(timeoutValueSeconds, timeout);
  var wrappedErrorCb = watchdog.wrapCallback(errorCb);
  var wrappedSuccessCb = watchdog.wrapCallback(successCb);

  var timer = createAttenuatedTimer(
      FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds);
  var logMsgUrl = request['logMsgUrl'];

  // Queue sign requests from the same origin, to protect against simultaneous
  // sign-out on many tabs resulting in repeated sign-in requests.
  var queuedSignRequest = new QueuedSignRequest(
      signChallenges, timer, sender, wrappedErrorCb, wrappedSuccessCb,
      request['challenge'], appId, logMsgUrl);
  if (!gnubbySignRequestQueue) {
    initRequestQueue();
  }
  var requestToken = gnubbySignRequestQueue.queueRequest(
      appId, sender.origin, queuedSignRequest.begin.bind(queuedSignRequest),
      timer);
  queuedSignRequest.setToken(requestToken);

  watchdog.setCloseable(queuedSignRequest);
  return watchdog;
}

/**
 * Returns whether the request appears to be a valid sign request.
 * @param {Object} request The request.
 * @return {boolean} Whether the request appears valid.
 */
function isValidSignRequest(request) {
  var signChallenges = getSignChallenges(request);
  if (!signChallenges) {
    return false;
  }
  var hasDefaultChallenge = request.hasOwnProperty('challenge');
  var hasAppId = request.hasOwnProperty('appId');
  // If the sign challenge array is empty, the global appId is required.
  if (!hasAppId && (!signChallenges || !signChallenges.length)) {
    return false;
  }
  return isValidSignChallengeArray(
      signChallenges, !hasDefaultChallenge, !hasAppId);
}

/**
 * Adapter class representing a queued sign request.
 * @param {!Array<SignChallenge>} signChallenges The sign challenges.
 * @param {Countdown} timer Timeout timer
 * @param {WebRequestSender} sender Message sender.
 * @param {function(U2fError)} errorCb Error callback
 * @param {function(SignChallenge, string, string)} successCb Success callback
 * @param {string=} opt_defaultChallenge A default sign challenge
 *     value, if a request does not provide one.
 * @param {string=} opt_appId The app id for the entire request.
 * @param {string=} opt_logMsgUrl Url to post log messages to
 * @constructor
 * @implements {Closeable}
 */
function QueuedSignRequest(
    signChallenges, timer, sender, errorCb, successCb, opt_defaultChallenge,
    opt_appId, opt_logMsgUrl) {
  /** @private {!Array<SignChallenge>} */
  this.signChallenges_ = signChallenges;
  /** @private {Countdown} */
  this.timer_ = timer.clone(this.close.bind(this));
  /** @private {WebRequestSender} */
  this.sender_ = sender;
  /** @private {function(U2fError)} */
  this.errorCb_ = errorCb;
  /** @private {function(SignChallenge, string, string)} */
  this.successCb_ = successCb;
  /** @private {string|undefined} */
  this.defaultChallenge_ = opt_defaultChallenge;
  /** @private {string|undefined} */
  this.appId_ = opt_appId;
  /** @private {string|undefined} */
  this.logMsgUrl_ = opt_logMsgUrl;
  /** @private {boolean} */
  this.begun_ = false;
  /** @private {boolean} */
  this.closed_ = false;
}

/** Closes this sign request. */
QueuedSignRequest.prototype.close = function() {
  if (this.closed_) {
    return;
  }
  var hadBegunSigning = false;
  if (this.begun_ && this.signer_) {
    this.signer_.close();
    hadBegunSigning = true;
  }
  if (this.token_) {
    if (hadBegunSigning) {
      console.info(UTIL_fmt('closing in-progress request'));
    } else {
      console.info(UTIL_fmt('closing timed-out request before processing'));
    }
    this.token_.complete();
  }
  this.closed_ = true;
};

/**
 * @param {QueuedRequestToken} token Token for this sign request.
 */
QueuedSignRequest.prototype.setToken = function(token) {
  /** @private {QueuedRequestToken} */
  this.token_ = token;
};

/**
 * Called when this sign request may begin work.
 * @param {QueuedRequestToken} token Token for this sign request.
 */
QueuedSignRequest.prototype.begin = function(token) {
  if (this.timer_.expired()) {
    console.info(UTIL_fmt('Queued request begun after timeout'));
    this.close();
    this.errorCb_({errorCode: ErrorCodes.TIMEOUT});
    return;
  }
  this.begun_ = true;
  this.setToken(token);
  this.signer_ = new Signer(
      this.timer_, this.sender_, this.signerFailed_.bind(this),
      this.signerSucceeded_.bind(this), this.logMsgUrl_);
  if (!this.signer_.setChallenges(
          this.signChallenges_, this.defaultChallenge_, this.appId_)) {
    token.complete();
    this.errorCb_({errorCode: ErrorCodes.BAD_REQUEST});
  }
  // Signer now has responsibility for maintaining timeout.
  this.timer_.clearTimeout();
};

/**
 * Called when this request's signer fails.
 * @param {U2fError} error The failure reported by the signer.
 * @private
 */
QueuedSignRequest.prototype.signerFailed_ = function(error) {
  this.token_.complete();
  this.errorCb_(error);
};

/**
 * Called when this request's signer succeeds.
 * @param {SignChallenge} challenge The challenge that was signed.
 * @param {string} info The sign result.
 * @param {string} browserData Browser data JSON
 * @private
 */
QueuedSignRequest.prototype.signerSucceeded_ = function(
    challenge, info, browserData) {
  this.token_.complete();
  this.successCb_(challenge, info, browserData);
};

/**
 * Creates an object to track signing with a gnubby.
 * @param {Countdown} timer Timer for sign request.
 * @param {WebRequestSender} sender The message sender.
 * @param {function(U2fError)} errorCb Called when the sign operation fails.
 * @param {function(SignChallenge, string, string)} successCb Called when the
 *     sign operation succeeds.
 * @param {string=} opt_logMsgUrl The url to post log messages to.
 * @constructor
 */
function Signer(timer, sender, errorCb, successCb, opt_logMsgUrl) {
  /** @private {Countdown} */
  this.timer_ = timer.clone();
  /** @private {WebRequestSender} */
  this.sender_ = sender;
  /** @private {function(U2fError)} */
  this.errorCb_ = errorCb;
  /** @private {function(SignChallenge, string, string)} */
  this.successCb_ = successCb;
  /** @private {string|undefined} */
  this.logMsgUrl_ = opt_logMsgUrl;

  /** @private {boolean} */
  this.challengesSet_ = false;
  /** @private {boolean} */
  this.done_ = false;

  /** @private {Object<string, string>} */
  this.browserData_ = {};
  /** @private {Object<string, SignChallenge>} */
  this.serverChallenges_ = {};
  // Allow http appIds for http origins. (Broken, but the caller deserves
  // what they get.)
  /** @private {boolean} */
  this.allowHttp_ = this.sender_.origin ?
      this.sender_.origin.indexOf('http://') === 0 :
      false;
  /** @private {RequestHandler} */
  this.handler_ = null;
}

/**
 * Sets the challenges to be signed.
 * @param {Array<SignChallenge>} signChallenges The challenges to set.
 * @param {string=} opt_defaultChallenge A default sign challenge
 *     value, if a request does not provide one.
 * @param {string=} opt_appId The app id for the entire request.
 * @return {boolean} Whether the challenges could be set.
 */
Signer.prototype.setChallenges = function(
    signChallenges, opt_defaultChallenge, opt_appId) {
  if (this.challengesSet_ || this.done_) {
    return false;
  }
  if (this.timer_.expired()) {
    this.notifyError_({errorCode: ErrorCodes.TIMEOUT});
    return true;
  }
  /** @private {Array<SignChallenge>} */
  this.signChallenges_ = signChallenges;
  /** @private {string|undefined} */
  this.defaultChallenge_ = opt_defaultChallenge;
  /** @private {string|undefined} */
  this.appId_ = opt_appId;
  /** @private {boolean} */
  this.challengesSet_ = true;

  this.checkAppIds_();
  return true;
};

/**
 * Checks the app ids of incoming requests.
 * @private
 */
Signer.prototype.checkAppIds_ = function() {
  var appIds = getDistinctAppIds(this.signChallenges_);
  if (this.appId_) {
    appIds = UTIL_unionArrays([this.appId_], appIds);
  }
  if (!appIds || !appIds.length) {
    var error = {
      errorCode: ErrorCodes.BAD_REQUEST,
      errorMessage: 'missing appId',
    };
    this.notifyError_(error);
    return;
  }
  FACTORY_REGISTRY.getOriginChecker()
      .canClaimAppIds(this.sender_.origin, appIds)
      .then(this.originChecked_.bind(this, appIds));
};

/**
 * Called with the result of checking the origin. When the origin is allowed
 * to claim the app ids, begins checking whether the app ids also list the
 * origin.
 * @param {!Array<string>} appIds The app ids.
 * @param {boolean} result Whether the origin could claim the app ids.
 * @private
 */
Signer.prototype.originChecked_ = function(appIds, result) {
  if (!result) {
    var error = {errorCode: ErrorCodes.BAD_REQUEST, errorMessage: 'bad appId'};
    this.notifyError_(error);
    return;
  }
  var appIdChecker = FACTORY_REGISTRY.getAppIdCheckerFactory().create();
  appIdChecker
      .checkAppIds(
          this.timer_.clone(), this.sender_.origin,
          /** @type {!Array<string>} */ (appIds), this.allowHttp_,
          this.logMsgUrl_)
      .then(this.appIdChecked_.bind(this));
};

/**
 * Called with the result of checking app ids.  When the app ids are valid,
 * adds the sign challenges to those being signed.
 * @param {boolean} result Whether the app ids are valid.
 * @private
 */
Signer.prototype.appIdChecked_ = function(result) {
  if (!result) {
    var error = {errorCode: ErrorCodes.BAD_REQUEST, errorMessage: 'bad appId'};
    this.notifyError_(error);
    return;
  }
  if (!this.doSign_()) {
    this.notifyError_({errorCode: ErrorCodes.BAD_REQUEST});
    return;
  }
};

/**
 * Begins signing this signer's challenges.
 * @return {boolean} Whether the challenge could be added.
 * @private
 */
Signer.prototype.doSign_ = async function() {
  // Create the browser data for each challenge.
  let challengeVal;
  for (var i = 0; i < this.signChallenges_.length; i++) {
    var challenge = this.signChallenges_[i];
    var serverChallenge;
    if (challenge.hasOwnProperty('challenge')) {
      serverChallenge = challenge['challenge'];
    } else {
      serverChallenge = this.defaultChallenge_;
    }
    challengeVal = serverChallenge;
    if (!serverChallenge) {
      console.warn(UTIL_fmt('challenge missing'));
      return false;
    }
    var keyHandle = challenge['keyHandle'];

    var browserData = makeSignBrowserData(serverChallenge, this.sender_.origin);
    this.browserData_[keyHandle] = browserData;
    this.serverChallenges_[keyHandle] = challenge;
  }

  var encodedChallenges = encodeSignChallenges(
      this.signChallenges_, this.defaultChallenge_, this.appId_,
      this.getChallengeHash_.bind(this));

  var timeoutSeconds = this.timer_.millisecondsUntilExpired() / 1000.0;

  console.info('Proxying sign request to WebAuthn');
  return this.doSignWebAuthn_(encodedChallenges, challengeVal);
};

/**
 * Sends the sign request via the WebAuthn API.
 * @param {!Array<SignHelperChallenge>} encodedChallenges Credential list
 *     provided by the relying party to be signed.
 * @param {string} challengeVal Base64 encoded challenge.
 * @return {boolean} If the message was sent.
 * @private
 */
Signer.prototype.doSignWebAuthn_ = function(encodedChallenges, challengeVal) {
  // Only try to sign if challenges were provided.
  if (encodedChallenges.length === 0) {
    return false;
  }

  const decodedChallenge = B64_decode(challengeVal);
  if (decodedChallenge.length === 0) {
    this.notifyError_({
      errorCode: ErrorCodes.BAD_REQUEST,
      errorMessage: 'challenge must be base64url encoded',
    });
    return false;
  }

  const credentialList = [];
  for (let i = 0; i < encodedChallenges.length; i++) {
    const decodedKeyHandle = B64_decode(encodedChallenges[i]['keyHandle']);
    if (decodedKeyHandle.length === 0) {
      this.notifyError_({
        errorCode: ErrorCodes.BAD_REQUEST,
        errorMessage: 'keyHandle must be base64url encoded',
      });
      return false;
    }
    credentialList.push({
      type: 'public-key',
      id: new Uint8Array(decodedKeyHandle).buffer,
    });
  }
  // App ID could be defined for each challenge or globally.
  const appid = this.signChallenges_[0].hasOwnProperty('appId') ?
      this.signChallenges_[0]['appId'] :
      this.appId_;

  if (!chrome.cryptotokenPrivate) {
    this.doSignWebAuthnContinue_(decodedChallenge, credentialList, appid);
  } else {
    chrome.cryptotokenPrivate.canMakeU2fApiRequest(
        {
          tabId: this.sender_.tabId,
          frameId: this.sender_.frameId,
          origin: this.sender_.origin,
          appId: appid,
        },
        (result) => {
          if (!result) {
            this.notifyError_({
              errorCode: ErrorCodes.DEVICE_INELIGIBLE,
              errorMessage: 'The operation was not allowed',
            });
            return;
          }
          this.doSignWebAuthnContinue_(decodedChallenge, credentialList, appid);
        });
  }

  return true;
};

Signer.prototype.doSignWebAuthnContinue_ = function(
    decodedChallenge, credentialList, appid) {
  const request = {
    publicKey: {
      challenge: new Uint8Array(decodedChallenge).buffer,
      timeout: this.timer_.millisecondsUntilExpired(),
      rpId: this.sender_.origin,
      allowCredentials: credentialList,
      userVerification: 'discouraged',
      extensions: {
        appid: appid,
      },
    },
  };
  navigator.credentials.get(request)
      .then(response => {
        this.handleWebAuthnSuccess_(response);
      })
      .catch(exception => {
        this.handleWebAuthnError_(exception);
      });
};

/**
 * Converts the WebAuthn error code to a U2F error code.
 * @param {*} exception Exception returned from the WebAuthn request.
 * @private
 */
Signer.prototype.handleWebAuthnError_ = function(exception) {
  const domError = /** @type {!DOMException} */ (exception);
  let errorCode = ErrorCodes.OTHER_ERROR;
  let errorDetails;

  if (domError && domError.name) {
    switch (domError.name) {
      case 'NotAllowedError':
      case 'InvalidStateError':
        errorCode = ErrorCodes.DEVICE_INELIGIBLE;
        break;
      default:
        // Fall through
        break;
    }
  }

  this.notifyError_({
    errorCode: errorCode,
    errorMessage: domError.toString(),
  });
};

/**
 * Converts the WebAuthn response to the response for cryptotoken.
 * @param {?PublicKeyCredential} assertion Assertion object received from
 *     credential request.
 * @private
 */
Signer.prototype.handleWebAuthnSuccess_ = function(assertion) {
  // Find the challenge to which this assertion corresponds.
  const assertionKeyHandle = assertion['id'];
  let signChallenge;
  for (let i = 0; i < this.signChallenges_.length; i++) {
    if (this.signChallenges_[i]['keyHandle'] === assertionKeyHandle) {
      signChallenge = this.signChallenges_[i];
      break;
    }
  }

  if (signChallenge === undefined) {
    console.warn('Response received from unknown key');
    this.notifyError_({
      errorCode: ErrorCodes.DEVICE_INELIGIBLE,
      errorMessage: 'Response received from unknown key',
    });
    return;
  }

  // First 32 bytes of authenticator data is the rpIdHash.
  let index = 32;
  const authenticatorDataBytes =
      new Uint8Array(assertion['response']['authenticatorData']);
  if (authenticatorDataBytes.length < index + 4) {
    // Invalid response length.
    this.notifyError_({
      errorCode: ErrorCodes.OTHER_ERROR,
      errorMessage: 'Invalid response message',
    });
    return;
  }

  const flags = [authenticatorDataBytes[index++] & 0x3];
  const counter = Array.from(authenticatorDataBytes.slice(index, index + 4));
  const signature =
      Array.from(new Uint8Array(assertion['response']['signature']));

  // Combine the flags byte with the counter and signature to recreate the U2F
  // authentication response message.
  const signResponse = flags.concat(counter).concat(signature);

  // Decode the ArrayBuffer view of the clientDataJSON into a string.
  const clientDataJSON = new TextDecoder('utf-8').decode(
      new Uint8Array(assertion['response']['clientDataJSON']));

  this.notifySuccess_(signChallenge, B64_encode(signResponse), clientDataJSON);
};

/**
 * @param {string} keyHandle The key handle used with the challenge.
 * @param {string} challenge The challenge.
 * @return {string} The hashed challenge associated with the key
 *     handle/challenge pair.
 * @private
 */
Signer.prototype.getChallengeHash_ = function(keyHandle, challenge) {
  return B64_encode(sha256HashOfString(this.browserData_[keyHandle]));
};

/** Closes this signer. */
Signer.prototype.close = function() {
  this.close_();
};

/**
 * Closes this signer, and optionally notifies the caller of error.
 * @param {boolean=} opt_notifying When true, this method is being called in the
 *     process of notifying the caller of an existing status. When false,
 *     the caller is notified with a default error value, ErrorCodes.TIMEOUT.
 * @private
 */
Signer.prototype.close_ = function(opt_notifying) {
  if (this.handler_) {
    this.handler_.close();
    this.handler_ = null;
  }
  this.timer_.clearTimeout();
  if (!opt_notifying) {
    this.notifyError_({errorCode: ErrorCodes.TIMEOUT});
  }
};

/**
 * Notifies the caller of error.
 * @param {U2fError} error Error.
 * @private
 */
Signer.prototype.notifyError_ = function(error) {
  if (this.done_) {
    return;
  }
  this.done_ = true;
  this.close_(true);
  this.errorCb_(error);
};

/**
 * Notifies the caller of success.
 * @param {SignChallenge} challenge The challenge that was signed.
 * @param {string} info The sign result.
 * @param {string} browserData Browser data JSON
 * @private
 */
Signer.prototype.notifySuccess_ = function(challenge, info, browserData) {
  if (this.done_) {
    return;
  }
  this.done_ = true;
  this.close_(true);
  this.successCb_(challenge, info, browserData);
};

/**
 * Called by the helper upon completion.
 * @param {HelperReply} helperReply The result of the sign request.
 * @param {string=} opt_source The source of the sign result.
 * @private
 */
Signer.prototype.helperComplete_ = function(helperReply, opt_source) {
  if (helperReply.type !== 'sign_helper_reply') {
    this.notifyError_({errorCode: ErrorCodes.OTHER_ERROR});
    return;
  }
  var reply = /** @type {SignHelperReply} */ (helperReply);

  if (reply.code) {
    var reportedError = mapDeviceStatusCodeToU2fError(reply.code);
    console.info(UTIL_fmt(
        'helper reported ' + reply.code.toString(16) + ', returning ' +
        reportedError.errorCode));
    // Log non-expected reply codes if we have an url to send them
    if ((reportedError.errorCode === ErrorCodes.OTHER_ERROR) &&
        this.logMsgUrl_) {
      logMessage('log=u2fsign&rc=' + reply.code.toString(16), this.logMsgUrl_);
    }
    this.notifyError_(reportedError);
  } else {
    if (this.logMsgUrl_ && opt_source) {
      var logMsg = 'signed&source=' + opt_source;
      logMessage(logMsg, this.logMsgUrl_);
    }

    var key = reply.responseData['keyHandle'];
    var browserData = this.browserData_[key];
    // Notify with server-provided challenge, not the encoded one: the
    // server-provided challenge contains additional fields it relies on.
    var serverChallenge = this.serverChallenges_[key];
    this.notifySuccess_(
        serverChallenge, reply.responseData.signatureData, browserData);
  }
};


text:
AliAnalysisTask *AddTaskJFJTask(TString taskName,
                                    TString sJCatalyst        = "JCatalystTask",
                                    TString centBins          = "0.0 100.0",
                                    double jetCone            = 0.4,
                                    double ktjetCone          = 0.4,
                                    int ktScheme              = 1,
                                    int antiktScheme          = 1,
                                    Bool_t usePionMass        = false,
                                    Bool_t useDeltaPhiBGSubtr = true,
                                    double particleEtaCut     = 0.8,
                                    double particlePtCut      = 0.15,
                                    double leadingJetCut      = 20.0,
                                    double subleadingJetCut   = 20.0,
                                    double minJetPt           = 10.0,
                                    double constituentCut     = 5.0,
                                    double deltaPhiCut        = 2.0,
                                    double matchingR          = 0.2,
                                    double trackingIneff      = 0.0){

    // Load Custom Configuration and parameters
    // override values with parameters
    std::stringstream ss( centBins.Data() );
    double binBorder;
    vector<double> vecCentBins;
    ss >> binBorder;
    while (!ss.fail()) {
        vecCentBins.push_back(binBorder);
        ss >> binBorder;
    }

    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
    //==== Check the analysis type using the event handlers connected to the analysis mgr
    if (!mgr->GetInputEventHandler() ){
            ::Error("AddTaskJFJTask", "This task requires an input event handler" );
            return NULL;
    }

    //==== Set up the dijet task ====
    AliJFJTask *dijetTask = new AliJFJTask(taskName.Data(),"AOD");
    dijetTask->SetDebugLevel(5);
    dijetTask->SetJCatalystTaskName(sJCatalyst.Data());
    dijetTask->SetCentralityBins(vecCentBins);
    dijetTask->SetJetConeSize(jetCone, ktjetCone);
    dijetTask->SetBGSubtrSettings(ktScheme, antiktScheme, usePionMass, useDeltaPhiBGSubtr);
    dijetTask->SetCuts(particleEtaCut, particlePtCut, leadingJetCut, subleadingJetCut, constituentCut, deltaPhiCut, matchingR, trackingIneff, minJetPt);
    cout << dijetTask->GetName() << endl;

    mgr->AddTask((AliAnalysisTask*) dijetTask);

    // Create containers for input/output
    AliAnalysisDataContainer *cinput  = mgr->GetCommonInputContainer();

    // Connect input/output
    mgr->ConnectInput(dijetTask, 0, cinput);
    AliAnalysisDataContainer *jHist = mgr->CreateContainer(Form("%scontainer",dijetTask->GetName()),  TDirectory::Class(), AliAnalysisManager::kOutputContainer, Form("%s:%s",AliAnalysisManager::GetCommonFileName(), dijetTask->GetName()));
    mgr->ConnectOutput(dijetTask, 1, jHist );

    return dijetTask;
}

redpajama_set_name: RedPajamaGithub


text:
<?php if (!defined('ABSPATH')) {
    exit; // Exit if accessed directly
} ?>

<form role="search" method="get" class="site-search js-search-submit" action="<?php echo esc_url(home_url('/')); ?>">
  <div class="small-12 row no-margin collapse">
    <input type="text" class="search-bar small-10" value="<?php echo get_search_query(); ?>" name="s" placeholder="<?php _e('Search', 'sage'); ?> <?php bloginfo('name'); ?>">
    <input type="submit" class="button fa shrink" value="">
  </div>
</form>


text:
Third-party patches are essential for keeping puppet great. We simply can't
access the huge number of platforms and myriad configurations for running
puppet. We want to keep it as easy as possible to contribute changes that
get things working in your environment. There are a few guidelines that we
need contributors to follow so that we can have a chance of keeping on
top of things.

## Getting Started

* Make sure you have a [Jira account](TBD)
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Serach for existing ticktes matching your issue and if none are found submit one.
  * Provide a clear description of the issue including any configuration information.
  * Provide clear reproduction steps.
* Fork the repository on GitHub

## Making Changes

* Create a topic branch from where you want to base your work.
  * This is usually the master branch.
  * Only target release branches if you are certain your fix must be on that
    branch.
  * To quickly create a topic branch based on master; `git checkout -b
    fix/master/my_contribution master`. Please avoid working directly on the
    `master` branch.
* Make commits of logical units.
* Check for unnecessary whitespace with `git diff --check` before committing.
* Make sure your commit messages are in the proper format.

````
    (BS-1234) Super awesome feature incoming.

    With the addition of this patch cats can now fly, pigs can speak, and
    dogs are vegans.
````

* Make sure you have added the necessary tests for your changes.
  * Untested code will not be merged!
* Run _all_ the tests to assure nothing else was accidentally broken.
  * AGAIN... untested code will not be merged!

## Making Trivial Changes

### Documentation

For changes of a trivial nature to comments and documentation, it is not
always necessary to create a new ticket in Jira. In this case, it is
appropriate to start the first line of a commit with '(doc)' instead of
a ticket number.

````
    (doc) Add documentation commit example to CONTRIBUTING

    There is no example for contributing a documentation commit
    to the Bespoke repository. This is a problem because the contributor
    is left to assume how a commit of this nature may appear.

    The first line is a real life imperative statement with '(doc)' in
    place of what would have been the ticket number in a
    non-documentation related commit. The body describes the nature of
    the new documentation or comments added.
````

## Submitting Changes

* Push your changes to a topic branch in your fork of the repository.
* Submit a pull request to the repository in the "Fancy Lads" organization.
* Update your Jira ticket to mark that you have submitted code and are ready for it to be reviewed (Status: Ready for Merge).
  * Include a link to the pull request in the ticket.
* After feedback has been given we expect responses within two weeks. After two
  weeks we may close the pull request if there is no activity.

# Additional Resources

* TBD


text:
@interface MacPrintClass:View
{
}

- drawSelf:(NXRect *)rects :(int)rectCount ;
- (BOOL)getRect:(NXRect *)theRect forPage:(int)page;
- (BOOL)knowsPagesFirst:(int *)firstPageNum last:(int *)lastPageNum;
- beginPageSetupRect:(const NXRect  * )aRect
					  placement:(const NXPoint *) location;
- beginSetup;
- endPage;
- endPSOutput;

@end


text:
var possibleHooks = require("../lib/possible-hooks");
var parseHookfile = require("../lib/parse-hookfile");
var writeHookfile = require("../lib/write-hookfile");

module.exports = function(hook, args){
	var parsed = parseHookfile(process.cwd());
	parsed[hook].push(args[0]);
	writeHookfile(process.cwd(), parsed);
};


text:
EXEC zsystem.Versions_Start 'CORE', 0003, 'jorundur'
GO

---------------------------------------------------------------------------------------------------------------------------------

GRANT SELECT ON zsystem.settings TO zzp_server
GRANT SELECT ON zsystem.versions TO zzp_server
GRANT EXEC ON zsystem.Versions_Check TO zzp_server
GO

---------------------------------------------------------------------------------------------------------------------------------

--IF EXISTS (SELECT * FROM sys.database_principals WHERE name = 'zzp_service')
--BEGIN
--  REVOKE SELECT ON zsystem.settings FROM zzp_service
--  REVOKE SELECT ON zsystem.versions FROM zzp_service
--  REVOKE EXEC ON zsystem.Versions_Check FROM zzp_service
--END
--GO

---------------------------------------------------------------------------------------------------------------------------------

--IF EXISTS (SELECT * FROM sys.database_principals WHERE name = 'zzp_service') AND NOT EXISTS(SELECT * FROM zsystem.versions WHERE developer = 'CORE' AND [version] = 4)
--BEGIN
--  DECLARE @RoleMemberName sysname, @SQL NVARCHAR(4000)
--  DECLARE Member_Cursor CURSOR FOR
--    select [name]
--      from sys.database_principals
--     where principal_id in (select member_principal_id
--                              from sys.database_role_members
--                             where role_principal_id in (select principal_id FROM sys.database_principals where [name] = 'zzp_service' AND [type] = 'R'))
--  OPEN Member_Cursor;
--  FETCH NEXT FROM Member_Cursor into @RoleMemberName
--  WHILE @@FETCH_STATUS = 0
--  BEGIN
--    SET @SQL = 'ALTER ROLE '+ QUOTENAME('zzp_service', '[') +' DROP MEMBER '+ QUOTENAME(@RoleMemberName, '[')
--    EXEC(@SQL)
--
--    FETCH NEXT FROM Member_Cursor into @RoleMemberName
--  END;
--
--  CLOSE Member_Cursor;
--  DEALLOCATE Member_Cursor;
--
--  DROP ROLE zzp_service
--END
--GO

---------------------------------------------------------------------------------------------------------------------------------

GO
EXEC zsystem.Versions_Finish 'CORE', 0003, 'jorundur'
GO


text:
using System;

namespace DataMigration
{
    /// <summary>
    /// This is the fundamental interface that ISourceValueMap derives from.
    /// There is a need for LitmusTests, Transformation Functions, and ForeignId generation to
    /// share the same code, hence this interface hierarchy.  This is the more stripped-down
    /// interface, which is implemented by LitmusTestDescriptor, and which is sufficient for
    /// the code that parses out arguments and looks for Method names using tags, to do its
    /// work.  ISourceValueMap has more fields, and TransformationMaps and
    /// BadRowsForeignIdDesciptors implement it.
    /// </summary>
    public interface IMethodMap
    {
       /// <summary>
        /// SrcColumns is a comma-separated list of integers which refer to input data columns,
        /// zero-relative.
        /// </summary>
        String SrcColumns { get; set; }

        /// <summary>
        /// Method is the name of the method that needs to be applied to the srcColumns values,
        /// to calculate a result.
        /// </summary>
        String Method { get; set; }

        /// <summary>
        /// MethodTag is a short string that is an identifier denoting which method resolver is
        /// used by this Method.  If Method is non-empty, then this needs to be set.
        /// </summary>
        String MethodTag { get; set; }

        /// <summary>
        /// The Lookup property denotes which, if any, lookup object is to be used.
        /// </summary>
        String Lookup { get; set; }
    }
}


text:
<!DOCTYPE html>

<meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Closure Unit Tests - goog.ui.AdvancedTooltip</title>

  Hover Here For Popup
    Child of target

Content


text:
class CreateVegetables < ActiveRecord::Migration
  def change
    create_table :vegetables do |t|
      t.string :name
      t.decimal :price
      t.string :comment
    end

    set_table_comment :vegetables, 'Healthy'

    set_column_comment :vegetables, :name, 'The name of the vegetable'

    set_column_comments :vegetables, :price => 'vegetable cost', :comment => 'thoughts'

    change_table :vegetables do |t|
      t.set_table_comment 'Healthy and delicious'
    end

    add_index :vegetables, :name, :unique => true

    set_index_comment :index_vegetables_on_name, "Comment on index"
  end
end


text:
#ifndef FTYPES_H
#define FTYPES_H

#include <glib.h>
#include "../slab.h"

/* field types */
enum ftenum {
	FT_NONE,	/* used for text labels with no value */
	FT_PROTOCOL,
	FT_BOOLEAN,	/* TRUE and FALSE come from <glib.h> */
	FT_UINT8,
	FT_UINT16,
	FT_UINT24,	/* really a UINT32, but displayed as 3 hex-digits if FD_HEX*/
	FT_UINT32,
	FT_UINT64,
	FT_INT8,
	FT_INT16,
	FT_INT24,	/* same as for UINT24 */
	FT_INT32,
	FT_INT64,
	FT_FLOAT,
	FT_DOUBLE,
	FT_ABSOLUTE_TIME,
	FT_RELATIVE_TIME,
	FT_STRING,
	FT_STRINGZ,	/* for use with proto_tree_add_item() */
	FT_UINT_STRING,	/* for use with proto_tree_add_item() */
	/*FT_UCS2_LE, */    /* Unicode, 2 byte, Little Endian     */
	FT_ETHER,
	FT_BYTES,
	FT_UINT_BYTES,
	FT_IPv4,
	FT_IPv6,
	FT_IPXNET,
	FT_FRAMENUM,	/* a UINT32, but if selected lets you go to frame with that numbe */
	FT_PCRE,		/* a compiled Perl-Compatible Regular Expression object */
	FT_GUID,		/* GUID, UUID */
	FT_OID,			/* OBJECT IDENTIFIER */
	FT_NUM_TYPES /* last item number plus one */
};

#define IS_FT_INT(ft)    ((ft)==FT_INT8||(ft)==FT_INT16||(ft)==FT_INT24||(ft)==FT_INT32)
#define IS_FT_UINT(ft)   ((ft)==FT_UINT8||(ft)==FT_UINT16||(ft)==FT_UINT24||(ft)==FT_UINT32||(ft)==FT_FRAMENUM)
#define IS_FT_TIME(ft)   ((ft)==FT_ABSOLUTE_TIME||(ft)==FT_RELATIVE_TIME)
#define IS_FT_STRING(ft) ((ft)==FT_STRING||(ft)==FT_STRINGZ)

typedef enum ftenum ftenum_t;
typedef struct _ftype_t ftype_t;

/* String representation types. */
enum ftrepr {
    FTREPR_DISPLAY,
    FTREPR_DFILTER
};

typedef enum ftrepr ftrepr_t;

#ifdef HAVE_LIBPCRE
typedef struct _pcre_tuple_t pcre_tuple_t;
#endif /* HAVE_LIBPCRE */

/* Initialize the ftypes subsytem. Called once. */
void
ftypes_initialize(void);

/* ---------------- FTYPE ----------------- */

/* Return a string representing the name of the type */
const char*
ftype_name(ftenum_t ftype);

/* Return a string presenting a "pretty" representation of the
 * name of the type. The pretty name means more to the user than
 * that "FT_*" name. */
const char*
ftype_pretty_name(ftenum_t ftype);

/* Returns length of field in packet, or 0 if not determinable/defined. */
int
ftype_length(ftenum_t ftype);

gboolean
ftype_can_slice(enum ftenum ftype);

gboolean
ftype_can_eq(enum ftenum ftype);

gboolean
ftype_can_ne(enum ftenum ftype);

gboolean
ftype_can_gt(enum ftenum ftype);

gboolean
ftype_can_ge(enum ftenum ftype);

gboolean
ftype_can_lt(enum ftenum ftype);

gboolean
ftype_can_le(enum ftenum ftype);

gboolean
ftype_can_bitwise_and(enum ftenum ftype);

gboolean
ftype_can_contains(enum ftenum ftype);

gboolean
ftype_can_matches(enum ftenum ftype);

/* ---------------- FVALUE ----------------- */

#include <epan/ipv4.h>
#include <epan/guid-utils.h>

#include <epan/tvbuff.h>
#include <epan/nstime.h>
#include <epan/dfilter/drange.h>

typedef struct _fvalue_t {
	ftype_t	*ftype;
	union {
		/* Put a few basic types in here */
		gpointer	pointer;
		guint32		uinteger;
		gint32		sinteger;
		guint64		integer64;
		gdouble		floating;
		gchar		*string;
		guchar		*ustring;
		GByteArray	*bytes;
		GString		*gstring;
		ipv4_addr	ipv4;
		e_guid_t	guid;
		nstime_t	time;
		tvbuff_t	*tvb;
#ifdef HAVE_LIBPCRE
		pcre_tuple_t	*re;
#endif /* HAVE_LIBPCRE */
	} value;

	/* The following is provided for private use
	 * by the fvalue. */
	gboolean	fvalue_gboolean1;

} fvalue_t;

typedef void (*FvalueNewFunc)(fvalue_t*);
typedef void (*FvalueFreeFunc)(fvalue_t*);
typedef void (*LogFunc)(const char*,...);

typedef gboolean (*FvalueFromUnparsed)(fvalue_t*, char*, gboolean, LogFunc);
typedef gboolean (*FvalueFromString)(fvalue_t*, char*, LogFunc);
typedef void (*FvalueToStringRepr)(fvalue_t*, ftrepr_t, char*);
typedef int (*FvalueStringReprLen)(fvalue_t*, ftrepr_t);

typedef void (*FvalueSetFunc)(fvalue_t*, gpointer, gboolean);
typedef void (*FvalueSetUnsignedIntegerFunc)(fvalue_t*, guint32);
typedef void (*FvalueSetSignedIntegerFunc)(fvalue_t*, gint32);
typedef void (*FvalueSetInteger64Func)(fvalue_t*, guint64);
typedef void (*FvalueSetFloatingFunc)(fvalue_t*, gdouble);

typedef gpointer (*FvalueGetFunc)(fvalue_t*);
typedef guint32 (*FvalueGetUnsignedIntegerFunc)(fvalue_t*);
typedef gint32  (*FvalueGetSignedIntegerFunc)(fvalue_t*);
typedef guint64 (*FvalueGetInteger64Func)(fvalue_t*);
typedef double (*FvalueGetFloatingFunc)(fvalue_t*);

typedef gboolean (*FvalueCmp)(fvalue_t*, fvalue_t*);

typedef guint (*FvalueLen)(fvalue_t*);
typedef void (*FvalueSlice)(fvalue_t*, GByteArray *, guint offset, guint length);

struct _ftype_t {
    ftenum_t        ftype;
	const char		*name;
	const char		*pretty_name;
	int			wire_size;
	FvalueNewFunc		new_value;
	FvalueFreeFunc		free_value;
	FvalueFromUnparsed	val_from_unparsed;
	FvalueFromString	val_from_string;
	FvalueToStringRepr	val_to_string_repr;
	FvalueStringReprLen	len_string_repr;

	/* could be union */
	FvalueSetFunc		set_value;
	FvalueSetUnsignedIntegerFunc	set_value_uinteger;
	FvalueSetSignedIntegerFunc		set_value_sinteger;
	FvalueSetInteger64Func	set_value_integer64;
	FvalueSetFloatingFunc	set_value_floating;

	/* could be union */
	FvalueGetFunc		get_value;
	FvalueGetUnsignedIntegerFunc	get_value_uinteger;
	FvalueGetSignedIntegerFunc		get_value_sinteger;
	FvalueGetInteger64Func	get_value_integer64;
	FvalueGetFloatingFunc	get_value_floating;

	FvalueCmp		cmp_eq;
	FvalueCmp		cmp_ne;
	FvalueCmp		cmp_gt;
	FvalueCmp		cmp_ge;
	FvalueCmp		cmp_lt;
	FvalueCmp		cmp_le;
	FvalueCmp		cmp_bitwise_and;
	FvalueCmp		cmp_contains;
	FvalueCmp		cmp_matches;

	FvalueLen		len;
	FvalueSlice		slice;
};

fvalue_t*
fvalue_new(ftenum_t ftype);

void
fvalue_init(fvalue_t *fv, ftenum_t ftype);

/* Define type needed for the fvalue_t free list. */
SLAB_ITEM_TYPE_DEFINE(fvalue_t)

/* Free all memory used by an fvalue_t. With MSVC and a
 * libwireshark.dll, we need a special declaration.
 */
WS_VAR_IMPORT SLAB_FREE_LIST_DECLARE(fvalue_t)

#define FVALUE_CLEANUP(fv)					\
	{							\
		register FvalueFreeFunc	free_value;		\
		free_value = (fv)->ftype->free_value;	\
		if (free_value) {				\
			free_value((fv));			\
		}						\
	}

#define FVALUE_FREE(fv)						\
	{							\
		FVALUE_CLEANUP(fv)				\
		SLAB_FREE(fv, fvalue_t);			\
	}

fvalue_t*
fvalue_from_unparsed(ftenum_t ftype, char *s, gboolean allow_partial_value, LogFunc logfunc);

fvalue_t*
fvalue_from_string(ftenum_t ftype, char *s, LogFunc logfunc);

/* Returns the length of the string required to hold the
 * string representation of the the field value.
 * The length DOES NOT include the terminating NUL. */
int
fvalue_string_repr_len(fvalue_t *fv, ftrepr_t rtype);

/* Creates the string representation of the field value.
 * If given non-NULL 'buf', the string is written at the memory
 * location pointed to by 'buf'. If 'buf' is NULL, new memory
 * is malloc'ed and the string representation is written there.
 * The pointer to the beginning of the string representation is
 * returned. If 'buf' was NULL, this points to the newly-allocated
 * memory. if 'buf' was non-NULL, then the return value will be
 * 'buf'. */
extern char *
fvalue_to_string_repr(fvalue_t *fv, ftrepr_t rtype, char *buf);

ftype_t*
fvalue_ftype(fvalue_t *fv);

const char*
fvalue_type_name(fvalue_t *fv);

void
fvalue_set(fvalue_t *fv, gpointer value, gboolean already_copied);

void
fvalue_set_uinteger(fvalue_t *fv, guint32 value);

void
fvalue_set_sinteger(fvalue_t *fv, gint32 value);

void
fvalue_set_integer64(fvalue_t *fv, guint64 value);

void
fvalue_set_floating(fvalue_t *fv, gdouble value);

gpointer
fvalue_get(fvalue_t *fv);

extern guint32
fvalue_get_uinteger(fvalue_t *fv);

extern gint32
fvalue_get_sinteger(fvalue_t *fv);

guint64
fvalue_get_integer64(fvalue_t *fv);

extern double
fvalue_get_floating(fvalue_t *fv);

gboolean
fvalue_eq(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_ne(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_gt(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_ge(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_lt(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_le(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_bitwise_and(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_contains(fvalue_t *a, fvalue_t *b);

gboolean
fvalue_matches(fvalue_t *a, fvalue_t *b);

guint
fvalue_length(fvalue_t *fv);

fvalue_t*
fvalue_slice(fvalue_t *fv, drange *dr);

#endif /* ftypes.h */


text:
<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
/*
| -------------------------------------------------------------------
| AUTO-LOADER
| -------------------------------------------------------------------
| This file specifies which systems should be loaded by default.
|
| In order to keep the framework as light-weight as possible only the
| absolute minimal resources are loaded by default. For example,
| the database is not connected to automatically since no assumption
| is made regarding whether you intend to use it.  This file lets
| you globally define which systems you would like loaded with every
| request.
|
| -------------------------------------------------------------------
| Instructions
| -------------------------------------------------------------------
|
| These are the things you can load automatically:
|
| 1. Packages
| 2. Libraries
| 3. Helper files
| 4. Custom config files
| 5. Language files
| 6. Models
|
*/

/*
| -------------------------------------------------------------------
|  Auto-load Packges
| -------------------------------------------------------------------
| Prototype:
|
|  $autoload['packages'] = array(APPPATH.'third_party', '/usr/local/shared');
|
*/

$autoload['packages'] = array();

/*
| -------------------------------------------------------------------
|  Auto-load Libraries
| -------------------------------------------------------------------
| These are the classes located in the system/libraries folder
| or in your application/libraries folder.
|
| Prototype:
|
|	$autoload['libraries'] = array('database', 'session', 'xmlrpc');

|	* pyrocache and session is loaded by MY_Controller to allow the site_ref to be set
*/

$autoload['libraries'] = array('asset', 'database', 'template', 'parser');

/*
| -------------------------------------------------------------------
|  Auto-load Helper Files
| -------------------------------------------------------------------
| Prototype:
|
|	$autoload['helper'] = array('url', 'file');
*/

$autoload['helper'] = array(
	'debug', 'url', 'form', 'text', 'string', 'language', 'html', 'pagination', 'array', 'gravatar',
	'markdown', 'addons/module', 'users/user'
);

/*
| -------------------------------------------------------------------
|  Auto-load Config files
| -------------------------------------------------------------------
| Prototype:
|
|	$autoload['config'] = array('config1', 'config2');
|
| NOTE: This item is intended for use ONLY if you have created custom
| config files.  Otherwise, leave it blank.
|
*/

$autoload['config'] = array('language');

/*
| -------------------------------------------------------------------
|  Auto-load Language files
| -------------------------------------------------------------------
| Prototype:
|
|	$autoload['language'] = array('lang1', 'lang2');
|
| NOTE: Do not include the "_lang" part of your file.  For example
| "codeigniter_lang.php" would be referenced as array('codeigniter');
|
*/

$autoload['language'] = array('errors');

/*
| -------------------------------------------------------------------
|  Auto-load Models
| -------------------------------------------------------------------
| Prototype:
|
|	$autoload['model'] = array('model1', 'model2');
|
*/

// Autoloaded in MY_Controller
//	permissions/permission_m', addons/module_m', 'pages/pages_m
$autoload['model'] = array();

/* End of file autoload.php */


text:
require_relative 'base_service'
require_relative 'reopen_service'
require_relative 'close_service'

module MergeRequests
  class UpdateService < MergeRequests::BaseService
    def execute(merge_request)
      # We don't allow change of source/target projects and source branch
      # after merge request was created
      params.except!(:source_project_id)
      params.except!(:target_project_id)
      params.except!(:source_branch)

      update(merge_request)
    end

    def handle_changes(merge_request, options = {})
      if has_changes?(merge_request, options)
        todo_service.mark_pending_todos_as_done(merge_request, current_user)
      end

      if merge_request.previous_changes.include?('title') ||
         merge_request.previous_changes.include?('description')
        todo_service.update_merge_request(merge_request, current_user)
      end

      if merge_request.previous_changes.include?('target_branch')
        create_branch_change_note(merge_request, 'target',
                                  merge_request.previous_changes['target_branch'].first,
                                  merge_request.target_branch)
      end

      if merge_request.previous_changes.include?('milestone_id')
        create_milestone_note(merge_request)
      end

      if merge_request.previous_changes.include?('assignee_id')
        create_assignee_note(merge_request)
        notification_service.reassigned_merge_request(merge_request, current_user)
        todo_service.reassigned_merge_request(merge_request, current_user)
      end

      if merge_request.previous_changes.include?('target_branch') ||
          merge_request.previous_changes.include?('source_branch')
        merge_request.mark_as_unchecked
      end
    end

    def reopen_service
      MergeRequests::ReopenService
    end

    def close_service
      MergeRequests::CloseService
    end
  end
end