<commit_before>const debug = require('debug')('telegraf:client')
const crypto = require('crypto')
const fetch = require('node-fetch')
const fs = require('fs')
const https = require('https')
const path = require('path')
const TelegramError = require('./error')
const MultipartStream = require('./multipart-stream')
const { isStream } = MultipartStream

const WebhookBlacklist = [
  'getChat',
  'getChatAdministrators',
  'getChatMember',
  'getChatMembersCount',
  'getFile',
  'getFileLink',
  'getGameHighScores',
  'getMe',
  'getUserProfilePhotos',
  'getWebhookInfo'
]

const DefaultExtensions = {
  audio: 'mp3',
  photo: 'jpg',
  sticker: 'webp',
  video: 'mp4',
  video_note: 'mp4',
  voice: 'ogg'
}

const DefaultOptions = {
  apiRoot: 'https://api.telegram.org',
  webhookReply: true,
  agent: new https.Agent({
    keepAlive: true,
    keepAliveMsecs: 10000
  })
}

const WebhookReplyStub = {
  webhook: true,
  details: 'https://core.telegram.org/bots/api#making-requests-when-getting-updates'
}

function safeJSONParse (text) {
  try {
    return JSON.parse(text)
  } catch (err) {
    debug('JSON parse failed', err)
  }
}

function includesMedia (payload) {
  return Object.keys(payload).some(
    (key) => Array.isArray(payload[key])
      ? payload[key].some(({ media }) => media && typeof media === 'object' && (media.source || media.url))
      : payload[key] && typeof payload[key] === 'object' && (payload[key].source || payload[key].url)
  )
}

function buildJSONConfig (options) {
  return Promise.resolve({
    method: 'POST',
    compress: true,
    headers: { 'content-type': 'application/json', 'connection': 'keep-alive' },
    body: JSON.stringify(options)
  })
}

function buildFormDataConfig (options) {
  if (options.reply_markup && typeof options.reply_markup !== 'string') {
    options.reply_markup = JSON.stringify(options.reply_markup)
  }
  const boundary = crypto.randomBytes(32).toString('hex')
  const formData = new MultipartStream(boundary)
  const tasks = Object.keys(options).map((key) => attachFormValue(formData, options[key], key))
  return Promise.all(tasks).then(() => {
    return {
      method: 'POST',
      compress: true,
      headers: { 'content-type': `multipart/form-data; boundary=${boundary}`, 'connection': 'keep-alive' },
      body: formData
    }
  })
}

function attachFormValue (form, value, id) {
  if (!value) {
    return Promise.resolve()
  }
  const valueType = typeof value
  if (valueType === 'string' || valueType === 'boolean' || valueType === 'number') {
    form.addPart({
      headers: { 'content-disposition': `form-data; name="${id}"` },
      body: `${value}`
    })
    return Promise.resolve()
  }
  if (Array.isArray(value)) {
    return Promise.all(
      value.map((item) => {
        if (typeof item.media !== 'object') {
          return Promise.resolve(item)
        }
        const attachmentId = crypto.randomBytes(16).toString('hex')
        return attachFormMedia(form, item.media, attachmentId)
          .then(() => Object.assign({}, item, { media: `attach://${attachmentId}` }))
      })
    ).then((items) => form.addPart({
      headers: { 'content-disposition': `form-data; name="${id}"` },
      body: JSON.stringify(items)
    }))
  }
  return attachFormMedia(form, value, id)
}

function attachFormMedia (form, media, id) {
  let fileName = media.filename || `${id}.${DefaultExtensions[id] || 'dat'}`
  if (media.url) {
    return fetch(media.url).then((res) =>
      form.addPart({
        headers: { 'content-disposition': `form-data; name="${id}"; filename="${fileName}"` },
        body: res.body
      })
    )
  }
  if (media.source) {
    if (fs.existsSync(media.source)) {
      fileName = media.filename || path.basename(media.source)
      media.source = fs.createReadStream(media.source)
    }
    if (isStream(media.source) || Buffer.isBuffer(media.source)) {
      form.addPart({
        headers: { 'content-disposition': `form-data; name="${id}"; filename="${fileName}"` },
        body: media.source
      })
    }
  }
  return Promise.resolve()
}

function isKoaReponse (response) {
  return typeof response.set === 'function' && typeof response.header === 'object'
}

function answerToWebhook (response, payload = {}) {
  if (!includesMedia(payload)) {
    if (isKoaReponse(response)) {
      response.body = payload
      return Promise.resolve(WebhookReplyStub)
    }
    if (!response.headersSent) {
      response.setHeader('content-type', 'application/json')
    }
    return new Promise((resolve) =>
      response.end(JSON.stringify(payload), 'utf-8', () => resolve(WebhookReplyStub))
    )
  }

  return buildFormDataConfig(payload)
    .then(({ headers, body }) => {
      if (isKoaReponse(response)) {
        Object.keys(headers).forEach(key => response.set(key, headers[key]))
        response.body = body
        return Promise.resolve(WebhookReplyStub)
      }
      if (!response.headersSent) {
        Object.keys(headers).forEach(key => response.setHeader(key, headers[key]))
      }
      return new Promise((resolve) => {
        response.on('finish', () => resolve(WebhookReplyStub))
        body.pipe(response)
      })
    })
}

class ApiClient {
  constructor (token, options, webhookResponse) {
    this.token = token
    this.options = Object.assign({}, DefaultOptions, options)
    if (this.options.apiRoot.startsWith('http://')) {
      this.options.agent = null
    }
    this.response = webhookResponse
  }

  set webhookReply (enable) {
    this.options.webhookReply = enable
  }

  get webhookReply () {
    return this.options.webhookReply
  }

  callApi (method, payload = {}) {
    const { token, options, response, responseEnd } = this
    if (options.webhookReply && response && !responseEnd && !WebhookBlacklist.includes(method)) {
      debug('▷ webhook call:', method)
      this.responseEnd = true
      return answerToWebhook(response, Object.assign({ method }, payload))
    }

    if (!token) {
      throw new TelegramError({
        error_code: 401,
        description: 'Bot Token is required'
      })
    }

    debug('▶ http call:', method)
    const buildConfig = includesMedia(payload)
      ? buildFormDataConfig(Object.assign({ method }, payload))
      : buildJSONConfig(payload)
    return buildConfig
      .then((config) => {
        const apiUrl = `${options.apiRoot}/bot${token}/${method}`
        config.agent = options.agent
        return fetch(apiUrl, config)
      })
      .then((res) => res.text())
      .then((text) => {
        return safeJSONParse(text) || {
          error_code: 500,
          description: 'Unsupported http response from Telegram',
          response: text
        }
      })
      .then((data) => {
        if (!data.ok) {
          throw new TelegramError(data, { method, payload })
        }
        return data.result
      })
  }
}

module.exports = ApiClient
<commit_msg>fix typo<commit_after>const debug = require('debug')('telegraf:client')
const crypto = require('crypto')
const fetch = require('node-fetch')
const fs = require('fs')
const https = require('https')
const path = require('path')
const TelegramError = require('./error')
const MultipartStream = require('./multipart-stream')
const { isStream } = MultipartStream

const WebhookBlacklist = [
  'getChat',
  'getChatAdministrators',
  'getChatMember',
  'getChatMembersCount',
  'getFile',
  'getFileLink',
  'getGameHighScores',
  'getMe',
  'getUserProfilePhotos',
  'getWebhookInfo'
]

const DefaultExtensions = {
  audio: 'mp3',
  photo: 'jpg',
  sticker: 'webp',
  video: 'mp4',
  video_note: 'mp4',
  voice: 'ogg'
}

const DefaultOptions = {
  apiRoot: 'https://api.telegram.org',
  webhookReply: true,
  agent: new https.Agent({
    keepAlive: true,
    keepAliveMsecs: 10000
  })
}

const WebhookReplyStub = {
  webhook: true,
  details: 'https://core.telegram.org/bots/api#making-requests-when-getting-updates'
}

function safeJSONParse (text) {
  try {
    return JSON.parse(text)
  } catch (err) {
    debug('JSON parse failed', err)
  }
}

function includesMedia (payload) {
  return Object.keys(payload).some(
    (key) => Array.isArray(payload[key])
      ? payload[key].some(({ media }) => media && typeof media === 'object' && (media.source || media.url))
      : payload[key] && typeof payload[key] === 'object' && (payload[key].source || payload[key].url)
  )
}

function buildJSONConfig (options) {
  return Promise.resolve({
    method: 'POST',
    compress: true,
    headers: { 'content-type': 'application/json', 'connection': 'keep-alive' },
    body: JSON.stringify(options)
  })
}

function buildFormDataConfig (options) {
  if (options.reply_markup && typeof options.reply_markup !== 'string') {
    options.reply_markup = JSON.stringify(options.reply_markup)
  }
  const boundary = crypto.randomBytes(32).toString('hex')
  const formData = new MultipartStream(boundary)
  const tasks = Object.keys(options).map((key) => attachFormValue(formData, options[key], key))
  return Promise.all(tasks).then(() => {
    return {
      method: 'POST',
      compress: true,
      headers: { 'content-type': `multipart/form-data; boundary=${boundary}`, 'connection': 'keep-alive' },
      body: formData
    }
  })
}

function attachFormValue (form, value, id) {
  if (!value) {
    return Promise.resolve()
  }
  const valueType = typeof value
  if (valueType === 'string' || valueType === 'boolean' || valueType === 'number') {
    form.addPart({
      headers: { 'content-disposition': `form-data; name="${id}"` },
      body: `${value}`
    })
    return Promise.resolve()
  }
  if (Array.isArray(value)) {
    return Promise.all(
      value.map((item) => {
        if (typeof item.media !== 'object') {
          return Promise.resolve(item)
        }
        const attachmentId = crypto.randomBytes(16).toString('hex')
        return attachFormMedia(form, item.media, attachmentId)
          .then(() => Object.assign({}, item, { media: `attach://${attachmentId}` }))
      })
    ).then((items) => form.addPart({
      headers: { 'content-disposition': `form-data; name="${id}"` },
      body: JSON.stringify(items)
    }))
  }
  return attachFormMedia(form, value, id)
}

function attachFormMedia (form, media, id) {
  let fileName = media.filename || `${id}.${DefaultExtensions[id] || 'dat'}`
  if (media.url) {
    return fetch(media.url).then((res) =>
      form.addPart({
        headers: { 'content-disposition': `form-data; name="${id}"; filename="${fileName}"` },
        body: res.body
      })
    )
  }
  if (media.source) {
    if (fs.existsSync(media.source)) {
      fileName = media.filename || path.basename(media.source)
      media.source = fs.createReadStream(media.source)
    }
    if (isStream(media.source) || Buffer.isBuffer(media.source)) {
      form.addPart({
        headers: { 'content-disposition': `form-data; name="${id}"; filename="${fileName}"` },
        body: media.source
      })
    }
  }
  return Promise.resolve()
}

function isKoaResponse (response) {
  return typeof response.set === 'function' && typeof response.header === 'object'
}

function answerToWebhook (response, payload = {}) {
  if (!includesMedia(payload)) {
    if (isKoaResponse(response)) {
      response.body = payload
      return Promise.resolve(WebhookReplyStub)
    }
    if (!response.headersSent) {
      response.setHeader('content-type', 'application/json')
    }
    return new Promise((resolve) =>
      response.end(JSON.stringify(payload), 'utf-8', () => resolve(WebhookReplyStub))
    )
  }

  return buildFormDataConfig(payload)
    .then(({ headers, body }) => {
      if (isKoaResponse(response)) {
        Object.keys(headers).forEach(key => response.set(key, headers[key]))
        response.body = body
        return Promise.resolve(WebhookReplyStub)
      }
      if (!response.headersSent) {
        Object.keys(headers).forEach(key => response.setHeader(key, headers[key]))
      }
      return new Promise((resolve) => {
        response.on('finish', () => resolve(WebhookReplyStub))
        body.pipe(response)
      })
    })
}

class ApiClient {
  constructor (token, options, webhookResponse) {
    this.token = token
    this.options = Object.assign({}, DefaultOptions, options)
    if (this.options.apiRoot.startsWith('http://')) {
      this.options.agent = null
    }
    this.response = webhookResponse
  }

  set webhookReply (enable) {
    this.options.webhookReply = enable
  }

  get webhookReply () {
    return this.options.webhookReply
  }

  callApi (method, payload = {}) {
    const { token, options, response, responseEnd } = this
    if (options.webhookReply && response && !responseEnd && !WebhookBlacklist.includes(method)) {
      debug('▷ webhook call:', method)
      this.responseEnd = true
      return answerToWebhook(response, Object.assign({ method }, payload))
    }

    if (!token) {
      throw new TelegramError({
        error_code: 401,
        description: 'Bot Token is required'
      })
    }

    debug('▶ http call:', method)
    const buildConfig = includesMedia(payload)
      ? buildFormDataConfig(Object.assign({ method }, payload))
      : buildJSONConfig(payload)
    return buildConfig
      .then((config) => {
        const apiUrl = `${options.apiRoot}/bot${token}/${method}`
        config.agent = options.agent
        return fetch(apiUrl, config)
      })
      .then((res) => res.text())
      .then((text) => {
        return safeJSONParse(text) || {
          error_code: 500,
          description: 'Unsupported http response from Telegram',
          response: text
        }
      })
      .then((data) => {
        if (!data.ok) {
          throw new TelegramError(data, { method, payload })
        }
        return data.result
      })
  }
}

module.exports = ApiClient
<|endoftext|>


<commit_before>angular.module('electionsApp')
    .controller('submitController', function submitController($state, $scope, localStorageService, $modal) {
        // Process the submit request
        $scope.processSubmitSubmit = function () {
            // Clean up
            localStorageService.remove('nextState');
            localStorageService.remove('isLoggedIn');

            // Store the scope data
            console.log($scope.formData);

            // Update voteCount
            var votes = localStorageService.get('voteCount') || 0;
            localStorageService.set('voteCount', votes + 1);

            // Process president
            if ($scope.formData.presidentNoPreference) {
                var presidentNoPreference = localStorageService.get('presidentNoPreference') || 0;
                localStorageService.set('presidentNoPreference', presidentNoPreference + 1);
            } else {
                // Process preferences
            }

            // Process cultural
            if ($scope.formData.culturalNoPreference) {
                var culturalNoPreference = localStorageService.get('culturalNoPreference') || 0;
                localStorageService.set('culturalNoPreference', culturalNoPreference + 1);
            } else {
                // Process preferences
            }

            // Process games
            if ($scope.formData.gamesNoPreference) {
                var gamesNoPreference = localStorageService.get('gamesNoPreference') || 0;
                localStorageService.set('gamesNoPreference', gamesNoPreference + 1);
            } else {
                // Process preferences
            }

            // Process films
            if ($scope.formData.filmsNoPreference) {
                var filmsNoPreference = localStorageService.get('filmsNoPreference') || 0;
                localStorageService.set('filmsNoPreference', filmsNoPreference + 1);
            } else {
                // Process preferences
            }

            // Process science
            if ($scope.formData.scienceNoPreference) {
                var scienceNoPreference = localStorageService.get('scienceNoPreference') || 0;
                localStorageService.set('scienceNoPreference', scienceNoPreference + 1);
            } else {
                // Process preferences
            }

            // Open the submit modal
            $modal.open({
                templateUrl: 'partials/errorModal.html',
                controller: 'successSubmitController'
            });
        };
    })
    .controller('successSubmitController', function successSubmitController($state, $modalInstance, $scope) {
        $scope.error = {};
        $scope.error.name = 'Success';
        $scope.error.msg = 'Your vote has been successfully entered into the system';
        $scope.error.button = 'done';

        // Dismiss the modal
        $scope.dismiss = function () {
            $modalInstance.dismiss('cancel');
            $state.go('login');
        };
    });
<commit_msg>store the values in memory<commit_after>angular.module('electionsApp')
    .controller('submitController', function submitController($state, $scope, localStorageService, $modal) {
        // Process the submit request
        $scope.processSubmitSubmit = function () {
            // Clean up
            localStorageService.remove('nextState');
            localStorageService.remove('isLoggedIn');

            // Store the scope data
            console.log($scope.formData);

            // Update voteCount
            var votes = localStorageService.get('voteCount') || 0;
            localStorageService.set('voteCount', votes + 1);

            var firstPreferenceID, firstPreferences;
            var secondPreferenceID, secondPreferences;
            var thirdPreferenceID, thirdPreferences;

            // Process president
            if ($scope.formData.presidentNoPreference) {
                var presidentNoPreference = localStorageService.get('presidentNoPreference') || 0;
                localStorageService.set('presidentNoPreference', presidentNoPreference + 1);
            } else {
                // Process preferences
                firstPreferenceID = $scope.formData.presidentFirst;
                firstPreferences = localStorageService.get(firstPreferenceID + '_' + 1) || 0;
                localStorageService.set(firstPreferenceID + '_' + 1, firstPreferences + 1);

                secondPreferenceID = $scope.formData.presidentSecond;
                secondPreferences = localStorageService.get(secondPreferenceID + '_' + 1) || 0;
                localStorageService.set(secondPreferenceID + '_' + 2, secondPreferences + 1);

                thirdPreferenceID = $scope.formData.presidentThird;
                thirdPreferences = localStorageService.get(thirdPreferenceID + '_' + 1) || 0;
                localStorageService.set(thirdPreferenceID + '_' + 3, thirdPreferences + 1);
            }

            // Process games
            if ($scope.formData.gamesNoPreference) {
                var gamesNoPreference = localStorageService.get('gamesNoPreference') || 0;
                localStorageService.set('gamesNoPreference', gamesNoPreference + 1);
            } else {
                // Process preferences
                firstPreferenceID = $scope.formData.gamesFirst;
                firstPreferences = localStorageService.get(firstPreferenceID + '_' + 1) || 0;
                localStorageService.set(firstPreferenceID + '_' + 1, firstPreferences + 1);

                secondPreferenceID = $scope.formData.gamesSecond;
                secondPreferences = localStorageService.get(secondPreferenceID + '_' + 1) || 0;
                localStorageService.set(secondPreferenceID + '_' + 2, secondPreferences + 1);

                thirdPreferenceID = $scope.formData.gamesThird;
                thirdPreferences = localStorageService.get(thirdPreferenceID + '_' + 1) || 0;
                localStorageService.set(thirdPreferenceID + '_' + 3, thirdPreferences + 1);
            }

            // Process cultural
            if ($scope.formData.culturalNoPreference) {
                var culturalNoPreference = localStorageService.get('culturalNoPreference') || 0;
                localStorageService.set('culturalNoPreference', culturalNoPreference + 1);
            } else {
                // Process preferences
                firstPreferenceID = $scope.formData.culturalFirst;
                firstPreferences = localStorageService.get(firstPreferenceID + '_' + 1) || 0;
                localStorageService.set(firstPreferenceID + '_' + 1, firstPreferences + 1);

                secondPreferenceID = $scope.formData.culturalSecond;
                secondPreferences = localStorageService.get(secondPreferenceID + '_' + 1) || 0;
                localStorageService.set(secondPreferenceID + '_' + 2, secondPreferences + 1);

                thirdPreferenceID = $scope.formData.culturalThird;
                thirdPreferences = localStorageService.get(thirdPreferenceID + '_' + 1) || 0;
                localStorageService.set(thirdPreferenceID + '_' + 3, thirdPreferences + 1);
            }

            // Process science
            if ($scope.formData.scienceNoPreference) {
                var scienceNoPreference = localStorageService.get('scienceNoPreference') || 0;
                localStorageService.set('scienceNoPreference', scienceNoPreference + 1);
            } else {
                // Process preferences
                firstPreferenceID = $scope.formData.scienceFirst;
                firstPreferences = localStorageService.get(firstPreferenceID + '_' + 1) || 0;
                localStorageService.set(firstPreferenceID + '_' + 1, firstPreferences + 1);

                secondPreferenceID = $scope.formData.scienceSecond;
                secondPreferences = localStorageService.get(secondPreferenceID + '_' + 1) || 0;
                localStorageService.set(secondPreferenceID + '_' + 2, secondPreferences + 1);

                thirdPreferenceID = $scope.formData.scienceThird;
                thirdPreferences = localStorageService.get(thirdPreferenceID + '_' + 1) || 0;
                localStorageService.set(thirdPreferenceID + '_' + 3, thirdPreferences + 1);
            }

            // Process films
            if ($scope.formData.filmsNoPreference) {
                var filmsNoPreference = localStorageService.get('filmsNoPreference') || 0;
                localStorageService.set('filmsNoPreference', filmsNoPreference + 1);
            } else {
                // Process preferences
                firstPreferenceID = $scope.formData.filmsFirst;
                firstPreferences = localStorageService.get(firstPreferenceID + '_' + 1) || 0;
                localStorageService.set(firstPreferenceID + '_' + 1, firstPreferences + 1);

                secondPreferenceID = $scope.formData.filmsSecond;
                secondPreferences = localStorageService.get(secondPreferenceID + '_' + 1) || 0;
                localStorageService.set(secondPreferenceID + '_' + 2, secondPreferences + 1);

                thirdPreferenceID = $scope.formData.filmsThird;
                thirdPreferences = localStorageService.get(thirdPreferenceID + '_' + 1) || 0;
                localStorageService.set(thirdPreferenceID + '_' + 3, thirdPreferences + 1);
            }

            // Open the submit modal
            $modal.open({
                templateUrl: 'partials/errorModal.html',
                controller: 'successSubmitController'
            });
        };
    })
    .controller('successSubmitController', function successSubmitController($state, $modalInstance, $scope) {
        $scope.error = {};
        $scope.error.name = 'Success';
        $scope.error.msg = 'Your vote has been successfully entered into the system';
        $scope.error.button = 'done';

        // Dismiss the modal
        $scope.dismiss = function () {
            $modalInstance.dismiss('cancel');
            $state.go('login');
        };
    });
<|endoftext|>


<commit_before>// @ts-check
/// <reference lib="esnext.asynciterable" />
const Octokit = require("@octokit/rest");
const { runSequence } = require("./run-sequence");

// The first is used by bot-based kickoffs, the second by automatic triggers
const triggeredPR = process.env.SOURCE_ISSUE || process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER;

/**
 * This program should be invoked as `node ./scripts/update-experimental-branches <GithubAccessToken> <PR1> [PR2] [...]`
 * The order PR numbers are passed controls the order in which they are merged together.
 * TODO: the following is racey - if two experiment-enlisted PRs trigger simultaneously and witness one another in an unupdated state, they'll both produce
 * a new experimental branch, but each will be missing a change from the other. There's no _great_ way to fix this beyond setting the maximum concurrency
 * of this task to 1 (so only one job is allowed to update experiments at a time).
 */
async function main() {
    const prnums = process.argv.slice(3);
    if (!prnums.length) {
        return; // No enlisted PRs, nothing to update
    }
    if (!prnums.some(n => n === triggeredPR)) {
        return; // Only have work to do for enlisted PRs
    }
    console.log(`Performing experimental branch updating and merging for pull requests ${prnums.join(", ")}`);

    const userName = process.env.GH_USERNAME;
    const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`;

    // Forcibly cleanup workspace
    runSequence([
        ["git", ["checkout", "."]],
        ["git", ["fetch", "-fu", "origin", "master:master"]],
        ["git", ["checkout", "master"]],
        ["git", ["remote", "add", "fork", remoteUrl]], // Add the remote fork
    ]);

    const gh = new Octokit({
        auth: process.argv[2]
    });
    for (const numRaw of prnums) {
        const num = +numRaw;
        if (num) {
            // PR number rather than branch name - lookup info
            const inputPR = await gh.pulls.get({ owner: "Microsoft", repo: "TypeScript", pull_number: num });
            // GH calculates the rebaseable-ness of a PR into its target, so we can just use that here
            if (!inputPR.data.rebaseable) {
                if (+triggeredPR === num) {
                    await gh.issues.createComment({
                        owner: "Microsoft",
                        repo: "TypeScript",
                        issue_number: num,
                        body: `This PR is configured as an experiment, and currently has rebase conflicts with master - please rebase onto master and fix the conflicts.`
                    });
                    throw new Error(`Rebase conflict detected in PR ${num} with master`);
                }
                return; // A PR is currently in conflict, give up
            }
            runSequence([
                ["git", ["fetch", "origin", `pull/${num}/head:${num}`]],
                ["git", ["checkout", `${num}`]],
                ["git", ["rebase", "master"]],
                ["git", ["push", "-f", "-u", "fork", `${num}`]], // Keep a rebased copy of this branch in our fork
            ]);

        }
        else {
            throw new Error(`Invalid PR number: ${numRaw}`);
        }
    }

    // Return to `master` and make a new `experimental` branch
    runSequence([
        ["git", ["checkout", "master"]],
        ["git", ["checkout", "-b", "experimental"]],
    ]);

    // Merge each branch into `experimental` (which, if there is a conflict, we now know is from inter-experiment conflict)
    for (const branch of prnums) {
        // Find the merge base
        const mergeBase = runSequence([
            ["git", ["merge-base", branch, "experimental"]],
        ]);
        // Simulate the merge and abort if there are conflicts
        const mergeTree = runSequence([
            ["git", ["merge-tree", mergeBase.trim(), branch, "experimental"]]
        ]);
        if (mergeTree.indexOf(`===${"="}===`)) { // 7 equals is the center of the merge conflict marker
            throw new Error(`Merge conflict detected involving PR ${branch} with other experiment`);
        }
        // Merge (always producing a merge commit)
        runSequence([
            ["git", ["merge", branch, "--no-ff"]],
        ]);
    }
    // Every branch merged OK, force push the replacement `experimental` branch
    runSequence([
        ["git", ["push", "-f", "-u", "fork", "experimental"]],
    ]);
}

main().catch(e => (console.error(e), process.exitCode = 2));
<commit_msg>Taking typos out one line at a time<commit_after>// @ts-check
/// <reference lib="esnext.asynciterable" />
const Octokit = require("@octokit/rest");
const { runSequence } = require("./run-sequence");

// The first is used by bot-based kickoffs, the second by automatic triggers
const triggeredPR = process.env.SOURCE_ISSUE || process.env.SYSTEM_PULLREQUEST_PULLREQUESTNUMBER;

/**
 * This program should be invoked as `node ./scripts/update-experimental-branches <GithubAccessToken> <PR1> [PR2] [...]`
 * The order PR numbers are passed controls the order in which they are merged together.
 * TODO: the following is racey - if two experiment-enlisted PRs trigger simultaneously and witness one another in an unupdated state, they'll both produce
 * a new experimental branch, but each will be missing a change from the other. There's no _great_ way to fix this beyond setting the maximum concurrency
 * of this task to 1 (so only one job is allowed to update experiments at a time).
 */
async function main() {
    const prnums = process.argv.slice(3);
    if (!prnums.length) {
        return; // No enlisted PRs, nothing to update
    }
    if (!prnums.some(n => n === triggeredPR)) {
        return; // Only have work to do for enlisted PRs
    }
    console.log(`Performing experimental branch updating and merging for pull requests ${prnums.join(", ")}`);

    const userName = process.env.GH_USERNAME;
    const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`;

    // Forcibly cleanup workspace
    runSequence([
        ["git", ["checkout", "."]],
        ["git", ["fetch", "-fu", "origin", "master:master"]],
        ["git", ["checkout", "master"]],
        ["git", ["remote", "add", "fork", remoteUrl]], // Add the remote fork
    ]);

    const gh = new Octokit({
        auth: process.argv[2]
    });
    for (const numRaw of prnums) {
        const num = +numRaw;
        if (num) {
            // PR number rather than branch name - lookup info
            const inputPR = await gh.pulls.get({ owner: "Microsoft", repo: "TypeScript", pull_number: num });
            // GH calculates the rebaseable-ness of a PR into its target, so we can just use that here
            if (!inputPR.data.rebaseable) {
                if (+triggeredPR === num) {
                    await gh.issues.createComment({
                        owner: "Microsoft",
                        repo: "TypeScript",
                        issue_number: num,
                        body: `This PR is configured as an experiment, and currently has rebase conflicts with master - please rebase onto master and fix the conflicts.`
                    });
                    throw new Error(`Rebase conflict detected in PR ${num} with master`);
                }
                return; // A PR is currently in conflict, give up
            }
            runSequence([
                ["git", ["fetch", "origin", `pull/${num}/head:${num}`]],
                ["git", ["checkout", `${num}`]],
                ["git", ["rebase", "master"]],
                ["git", ["push", "-f", "-u", "fork", `${num}`]], // Keep a rebased copy of this branch in our fork
            ]);

        }
        else {
            throw new Error(`Invalid PR number: ${numRaw}`);
        }
    }

    // Return to `master` and make a new `experimental` branch
    runSequence([
        ["git", ["checkout", "master"]],
        ["git", ["checkout", "-b", "experimental"]],
    ]);

    // Merge each branch into `experimental` (which, if there is a conflict, we now know is from inter-experiment conflict)
    for (const branch of prnums) {
        // Find the merge base
        const mergeBase = runSequence([
            ["git", ["merge-base", branch, "experimental"]],
        ]);
        // Simulate the merge and abort if there are conflicts
        const mergeTree = runSequence([
            ["git", ["merge-tree", mergeBase.trim(), branch, "experimental"]]
        ]);
        if (mergeTree.indexOf(`===${"="}===`) >= 0) { // 7 equals is the center of the merge conflict marker
            throw new Error(`Merge conflict detected involving PR ${branch} with other experiment`);
        }
        // Merge (always producing a merge commit)
        runSequence([
            ["git", ["merge", branch, "--no-ff"]],
        ]);
    }
    // Every branch merged OK, force push the replacement `experimental` branch
    runSequence([
        ["git", ["push", "-f", "-u", "fork", "experimental"]],
    ]);
}

main().catch(e => (console.error(e), process.exitCode = 2));
<|endoftext|>


<commit_before>// Maps context object to observer tree.
const trees = new WeakMap();

function escape(text) {
  const node = document.createElement('p');
  node.textContent = text;
  return node.innerHTML;
}

function resolve(obj, prop) {
  if (typeof obj !== 'undefined') {
    const value = obj[prop];
    if (typeof value === 'function') {
      return value.call();
    }
    return value;
  }
}

function pluck(context, key) {
  const properties = key.split('.');
  const value = properties.reduce(resolve, context) || '';
  return escape(value);
}

function queryAll(selectors, root = document) {
  return Array.from(root.querySelectorAll(selectors));
}

function bindings(node) {
  const results = [];
  for (const child of node.childNodes) {
    switch (child.nodeType) {
    case 1:
      results.push(...bindAttributes(child));
      results.push(...bindings(child));
      break;
    case 3:
      results.push(...bindText(child));
      break;
    }
  }
  return results;
}

function notifyTree(node) {
  for (const fn of node.observers) fn();
  for (const name in node.children)
    notifyTree(node.children[name]);
}

function appendChild(parent, name) {
  const child = parent.children[name];
  return child ? child : parent.children[name] = {
    name: name, children: {}, observers: []
  };
}

function compose(a, b) {
  return function composed() {
    return a(b.apply(this, arguments));
  };
}

function descend(node, key, visitor) {
  const fn = compose(visitor, appendChild);
  return key.split('.').reduce(fn, node);
}

// Finds or builds the observer tree for a context object.
function tree(context) {
  let root = trees.get(context);
  if (!root) {
    root = {children: {}, observers: []};
    trees.set(context, root);
  }
  return root;
}

function bind(fragment, context) {
  const root = tree(context);
  for (const {target, key, update} of bindings(fragment)) {
    const observer = update.bind(target, context, key);
    const leaf = descend(root, key, proxyOnce(context));
    leaf.observers.push(observer);
    update.call(target, context, key);
  }
  return fragment;
}

// Returns a visitor function to descend through a context object's
// attributes, proxying assignment operators to notify the observer
// tree of changes.
function proxyOnce(context) {
  let current = context;
  return function visit(node) {
    if (!node.proxied) {
      proxy(current, node.name, notifyTree.bind(null, node));
      node.proxied = true;
    }
    current = current[node.name];
    return node;
  };
}

function proxy(target, property, after) {
  let current = target[property];
  Object.defineProperty(target, property, {
    get: () => current,
    set: (value) => {
      current = value;
      after();
    }
  });
}

function updateText(context, key) {
  this.textContent = pluck(context, key);
}

function updateAttribute(context, key) {
  this.value = pluck(context, key);
}

function parse(text) {
  const tokens = [];
  for (const token of text.split(/({{.+?}})/)) {
    const stache = token.startsWith('{{') && token.endsWith('}}');
    tokens.push(stache
      ? {type: 1, value: token.slice(2, -2).trim()}
      : {type: 0, value: token});
  }
  return tokens;
}

function bindAttributes(node) {
  const bindings = [];
  for (const attr of Array.from(node.attributes)) {
    for (const token of parse(attr.value)) {
      if (token.type === 1) {
        bindings.push({
          target: attr,
          key: token.value,
          update: updateAttribute
        });
      }
    }
  }
  return bindings;
}

function bindText(node) {
  const tokens = parse(node.textContent);
  if (tokens.length === 1 && tokens[0].type === 0) {
    return [];
  }

  const bindings = [];
  for (const token of tokens) {
    const text = document.createTextNode(token.value);
    node.parentNode.insertBefore(text, node);
    if (token.type === 1) {
      bindings.push({
        target: text,
        key: token.value,
        update: updateText
      });
    }
  }

  node.parentNode.removeChild(node);
  return bindings;
}

export function template(name) {
  const template = document.querySelector(`template[data-name="${name}"]`);
  const fragment = template.content;
  return function evaluate(context) {
    return bind(fragment.cloneNode(true), context);
  };
}

export function install(global = 'Templates') {
  const registry = {};
  const templates = queryAll('template[data-name]');
  const names = templates.map(el => el.getAttribute('data-name'));
  for (const name of names) registry[name] = template(name);
  window[global] = registry;
}
<commit_msg>Replace array mutation with map<commit_after>// Maps context object to observer tree.
const trees = new WeakMap();

function escape(text) {
  const node = document.createElement('p');
  node.textContent = text;
  return node.innerHTML;
}

function resolve(obj, prop) {
  if (typeof obj !== 'undefined') {
    const value = obj[prop];
    if (typeof value === 'function') {
      return value.call();
    }
    return value;
  }
}

function pluck(context, key) {
  const properties = key.split('.');
  const value = properties.reduce(resolve, context) || '';
  return escape(value);
}

function queryAll(selectors, root = document) {
  return Array.from(root.querySelectorAll(selectors));
}

function bindings(node) {
  const results = [];
  for (const child of node.childNodes) {
    switch (child.nodeType) {
    case 1:
      results.push(...bindAttributes(child));
      results.push(...bindings(child));
      break;
    case 3:
      results.push(...bindText(child));
      break;
    }
  }
  return results;
}

function notifyTree(node) {
  for (const fn of node.observers) fn();
  for (const name in node.children)
    notifyTree(node.children[name]);
}

function appendChild(parent, name) {
  const child = parent.children[name];
  return child ? child : parent.children[name] = {
    name: name, children: {}, observers: []
  };
}

function compose(a, b) {
  return function composed() {
    return a(b.apply(this, arguments));
  };
}

function descend(node, key, visitor) {
  const fn = compose(visitor, appendChild);
  return key.split('.').reduce(fn, node);
}

// Finds or builds the observer tree for a context object.
function tree(context) {
  let root = trees.get(context);
  if (!root) {
    root = {children: {}, observers: []};
    trees.set(context, root);
  }
  return root;
}

function bind(fragment, context) {
  const root = tree(context);
  for (const {target, key, update} of bindings(fragment)) {
    const observer = update.bind(target, context, key);
    const leaf = descend(root, key, proxyOnce(context));
    leaf.observers.push(observer);
    update.call(target, context, key);
  }
  return fragment;
}

// Returns a visitor function to descend through a context object's
// attributes, proxying assignment operators to notify the observer
// tree of changes.
function proxyOnce(context) {
  let current = context;
  return function visit(node) {
    if (!node.proxied) {
      proxy(current, node.name, notifyTree.bind(null, node));
      node.proxied = true;
    }
    current = current[node.name];
    return node;
  };
}

function proxy(target, property, after) {
  let current = target[property];
  Object.defineProperty(target, property, {
    get: () => current,
    set: (value) => {
      current = value;
      after();
    }
  });
}

function updateText(context, key) {
  this.textContent = pluck(context, key);
}

function updateAttribute(context, key) {
  this.value = pluck(context, key);
}

function parse(text) {
  return text.split(/({{.+?}})/).map(token => {
    const stache = token.startsWith('{{') && token.endsWith('}}');
    return stache
      ? {type: 1, value: token.slice(2, -2).trim()}
      : {type: 0, value: token};
  });
}

function bindAttributes(node) {
  const bindings = [];
  for (const attr of Array.from(node.attributes)) {
    for (const token of parse(attr.value)) {
      if (token.type === 1) {
        bindings.push({
          target: attr,
          key: token.value,
          update: updateAttribute
        });
      }
    }
  }
  return bindings;
}

function bindText(node) {
  const tokens = parse(node.textContent);
  if (tokens.length === 1 && tokens[0].type === 0) {
    return [];
  }

  const bindings = [];
  for (const token of tokens) {
    const text = document.createTextNode(token.value);
    node.parentNode.insertBefore(text, node);
    if (token.type === 1) {
      bindings.push({
        target: text,
        key: token.value,
        update: updateText
      });
    }
  }

  node.parentNode.removeChild(node);
  return bindings;
}

export function template(name) {
  const template = document.querySelector(`template[data-name="${name}"]`);
  const fragment = template.content;
  return function evaluate(context) {
    return bind(fragment.cloneNode(true), context);
  };
}

export function install(global = 'Templates') {
  const registry = {};
  const templates = queryAll('template[data-name]');
  const names = templates.map(el => el.getAttribute('data-name'));
  for (const name of names) registry[name] = template(name);
  window[global] = registry;
}
<|endoftext|>


<commit_before>!function() {
  var _undefined;

  var var1 = 'roperties';
  var var2 = 'ropertyDescriptors';
  var var3 = 'static';
  var var4 = 'onfiguration';
  var _properties = 'p' + var1;
  var _deepProperties = 'deepP' + var1;
  var _propertyDescriptors = 'p' + var2;
  var _staticProperties = var3 + 'P' + var1;
  var _staticDeepProperties = var3 + 'DeepP' + var1;
  var _staticPropertyDescriptors = var3 + 'P' + var2;
  var _configuration = 'c' + var4;
  var _deepConfiguration = 'deepC' + var4;
  var _deepProps = 'deepProps';
  var _deepStatics = 'deepStatics';
  var _deepConf = 'deepConf';
  var _initializers = 'initializers';
  var _methods = 'methods';
  var _composers = 'composers';
  var _compose = 'compose';
  var _object = 'object';
  var _length = 'length';
  var _create = 'create';
  var _Object = Object;
  var isArray = Array.isArray;
  var defineProperties = _Object.defineProperties;
  var objectKeys = _Object.keys;
  var3 = Array.prototype;
  var concat = var3.concat;
  var slice = var3.slice;

  var assign = _Object.assign || function(to) {
    var args = arguments, s = 1, from, keys, i;

    for (; s < args[_length];) {
      from = args[s++];
      if (from) {
        keys = objectKeys(from);
        for (i = 0; i < keys[_length]; i++) {
          to[keys[i]] = from[keys[i]];
        }
      }
    }

    return to;
  };

  function isFunction(obj) {
    return typeof obj == 'function';
  }

  function isObject(obj) {
    return obj && (typeof obj == _object || isFunction(obj));
  }

  function isPlainObject(value) {
    return value && typeof value == _object &&
      value.__proto__ == _Object.prototype;
  }

  /**
   * The 'src' argument plays the command role.
   * The returned values is always of the same type as the 'src'.
   * @param {Array|Object|*} dst Destination
   * @param {Array|Object|*} src Source
   * @returns {Array|Object|*} The `dst` argument
   */
  function mergeOne(dst, src) {
    if (src === _undefined) return dst;

    // According to specification arrays must be concatenated.
    // Also, the '.concat' creates a new array instance. Overrides the 'dst'.
    if (isArray(src)) return (isArray(dst) ? dst : []).concat(src);

    // Now deal with non plain 'src' object. 'src' overrides 'dst'
    // Note that functions are also assigned! We do not deep merge functions.
    if (!isPlainObject(src)) return src;

    // See if 'dst' is allowed to be mutated.
    // If not - it's overridden with a new plain object.
    var returnValue = isObject(dst) ? dst : {};

    var keys = objectKeys(src), i = 0, key, srcValue, dstValue, newDst;
    for (; i < keys[_length];) {
      key = keys[i++];

      srcValue = src[key];
      // Do not merge properties with the '_undefined' value.
      if (srcValue !== _undefined) {
        dstValue = returnValue[key];
        // Recursive calls to mergeOne() must allow only plain objects or arrays in dst
        newDst = isPlainObject(dstValue) || isArray(srcValue) ? dstValue : {};

        // deep merge each property. Recursion!
        returnValue[key] = mergeOne(newDst, srcValue);
      }
    }

    return returnValue;
  }

  function merge(dst) {
    return slice.call(arguments, 1).reduce(mergeOne, dst);
  }

  function extractFunctions() {
    var1 = concat.apply([], arguments).filter(isFunction);
    return var1[_length] == 0 ? _undefined : var1;
  }

  function pushUniqueFuncs(dst, src) {
    var i = 0, fn;
    for (; i < src[_length]; i) {
      fn = src[i++];
      if (isFunction(fn) && dst.indexOf(fn) < 0) {
        dst.push(fn);
      }
    }
  }

  function concatAssignFunctions(dstObject, srcArray, propName) {
    if (isArray(srcArray)) {
      pushUniqueFuncs(dstObject[propName] = dstObject[propName] || [], srcArray);
    }
  }

  function combineProperties(dstObject, srcObject, propName, action) {
    if (!isObject(srcObject[propName])) {
      return;
    }
    if (!isObject(dstObject[propName])) {
      dstObject[propName] = {};
    }
    action(dstObject[propName], srcObject[propName]);
  }

  function deepMergeAssign(dstObject, srcObject, propName) {
    combineProperties(dstObject, srcObject, propName, merge);
  }

  function mergeAssign(dstObject, srcObject, propName) {
    combineProperties(dstObject, srcObject, propName, assign);
  }

  /**
   * Converts stampit extended descriptor to a standard one.
   * @param {Object|*} descr
   * methods
   * properties
   * props
   * refs
   * initializers
   * [init
   * deepProperties
   * deepProps
   * propertyDescriptors
   * staticProperties
   * statics
   * staticDeepProperties
   * deepStatics
   * staticPropertyDescriptors
   * configuration
   * conf
   * deepConfiguration
   * deepConf
   * composers
   * @returns {Descriptor} Standardised descriptor
   */
  function standardiseDescriptor(descr) {
    if (!isObject(descr)) return descr;
    var4 = {};

    var4[_methods] = descr[_methods] || _undefined;

    var1 = descr[_properties];
    var2 = descr.props;
    var3 = descr.refs;
    var4[_properties] = isObject(var1 || var2 || var3) ? assign({}, var3, var2, var1) : _undefined;

    var4[_initializers] = extractFunctions(descr.init, descr[_initializers]);

    var1 = descr[_deepProperties];
    var2 = descr[_deepProps];
    var4[_deepProperties] = isObject(var1 || var2) ? merge({}, var2, var1) : _undefined;

    var4[_propertyDescriptors] = descr[_propertyDescriptors];

    var1 = descr[_staticProperties];
    var2 = descr.statics;
    var4[_staticProperties] = isObject(var1 || var2) ? assign({}, var2, var1) : _undefined;

    var1 = descr[_staticDeepProperties];
    var2 = descr[_deepStatics];
    var4[_staticDeepProperties] = isObject(var1 || var2) ? merge({}, var2, var1) : _undefined;

    var4[_staticPropertyDescriptors] = descr[_staticPropertyDescriptors];

    var1 = descr[_configuration];
    var2 = descr.conf;
    var4[_configuration] = isObject(var1 || var2) ? assign({}, var2, var1) : _undefined;

    var1 = descr[_deepConfiguration];
    var2 = descr[_deepConf];
    var3 = isObject(var1 || var2) ? merge({}, var2, var1) : _undefined;

    var1 = extractFunctions(descr[_composers]);
    if (var1) {
      var3 = var3 || {};
      concatAssignFunctions(var3, var1, _composers);
    }

    var4[_deepConfiguration] = var3;

    return var4;
  }

  /**
   * Creates new factory instance.
   * @returns {Function} The new factory function.
   */
  function createFactory() {
    return function Stamp(options) {
      var i = Stamp[_compose] || {};
      // Next line was optimized for most JS VMs. Please, be careful here!
      var obj = _Object[_create](i[_methods] || null);

      var inits = i[_initializers], args = slice.apply(arguments);
      var initializer, returnedValue;

      var tmp = i[_deepProperties];
      if (tmp) merge(obj, tmp);
      tmp = i[_properties];
      if (tmp) assign(obj, tmp);
      tmp = i[_propertyDescriptors];
      if (tmp) defineProperties(obj, tmp);

      if (!inits || inits[_length] == 0) return obj;

      if (options === _undefined) options = {};
      for (i = 0; i < inits[_length];) {
        initializer = inits[i++];
        if (isFunction(initializer)) {
          returnedValue = initializer.call(obj, options,
            {instance: obj, stamp: Stamp, args: args});
          obj = returnedValue === _undefined ? obj : returnedValue;
        }
      }

      return obj;
    };
  }

  /**
   * Returns a new stamp given a descriptor and a compose function implementation.
   * @param {Descriptor} [descriptor={}] The information about the object the stamp will be creating.
   * @returns {Stamp} The new stamp
   */
  function createStamp(descriptor) {
    var1 = createFactory();

    var2 = descriptor[_staticDeepProperties];
    var2 && merge(var1, var2);

    var2 = descriptor[_staticProperties];
    var2 && assign(var1, var2);

    var2 = descriptor[_staticPropertyDescriptors];
    var2 && defineProperties(var1, var2);

    var2 = isFunction(var1[_compose]) ? var1[_compose] : compose;
    assign(var1[_compose] = function() {
      return var2.apply(this, arguments);
    }, descriptor);

    return var1;
  }

  /**
   * Mutates the dstDescriptor by merging the srcComposable data into it.
   * @param {Descriptor} dstDescriptor The descriptor object to merge into.
   * @param {Composable} [srcComposable] The composable
   * (either descriptor or stamp) to merge data form.
   * @returns {Descriptor} Returns the dstDescriptor argument.
   */
  function mergeComposable(dstDescriptor, srcComposable) {
    var4 = (srcComposable && srcComposable[_compose]) || srcComposable;
    if (isObject(var4)) {
      mergeAssign(dstDescriptor, var4, _methods);
      mergeAssign(dstDescriptor, var4, _properties);
      deepMergeAssign(dstDescriptor, var4, _deepProperties);
      mergeAssign(dstDescriptor, var4, _propertyDescriptors);
      mergeAssign(dstDescriptor, var4, _staticProperties);
      deepMergeAssign(dstDescriptor, var4, _staticDeepProperties);
      mergeAssign(dstDescriptor, var4, _staticPropertyDescriptors);
      mergeAssign(dstDescriptor, var4, _configuration);
      deepMergeAssign(dstDescriptor, var4, _deepConfiguration);
      concatAssignFunctions(dstDescriptor, var4[_initializers], _initializers);
    }

    return dstDescriptor;
  }

  /**
   * Given the list of composables (stamp descriptors and stamps) returns
   * a new stamp (composable factory function).
   * @typedef {Function} Compose
   * Parameters:  {...Composable} The list of composables.
   * @returns {Stamp} A new stamp (aka composable factory function)
   */
  function compose() {
    var descriptor = concat.apply([this], arguments)
    .filter(isObject)
    .reduce(mergeComposable, {});
    return createStamp(descriptor);
  }

  /**
   * The Stamp Descriptor
   * @typedef {Function|Object} Descriptor
   * @returns {Stamp} A new stamp based on this Stamp
   * @property {Object} [methods] Methods or other data used as object instances' prototype
   * @property {Array<Function>} [initializers] List of initializers called for each object instance
   * @property {Object} [properties] Shallow assigned properties of object instances
   * @property {Object} [deepProperties] Deeply merged properties of object instances
   * @property {Object} [staticProperties] Shallow assigned properties of Stamps
   * @property {Object} [staticDeepProperties] Deeply merged properties of Stamps
   * @property {Object} [configuration] Shallow assigned properties of Stamp arbitrary metadata
   * @property {Object} [deepConfiguration] Deeply merged properties of Stamp arbitrary metadata
   * @property {Object} [propertyDescriptors] ES5 Property Descriptors applied to object instances
   * @property {Object} [staticPropertyDescriptors] ES5 Property Descriptors applied to Stamps
   */

  /**
   * The Stamp factory function
   * @typedef {Function} Stamp
   * @returns {*} Instantiated object
   * @property {Descriptor} compose - The Stamp descriptor and composition function
   */

  /**
   * A composable object - stamp or descriptor
   * @typedef {Stamp|Descriptor} Composable
   */

  /**
   * Returns true if argument is a stamp.
   * @param {*} obj Any object
   * @returns {Boolean} True is the obj is a stamp
   */
  function isStamp(obj) {
    return isFunction(obj) && isFunction(obj[_compose]);
  }

  function createUtilityFunction(propName, action) {
    return function() {
      var4 = {};
      var3 = concat.apply([{}], arguments);
      var4[propName] = action.apply(_undefined, var3);
      var1 = this;

      return ((var1 && var1[_compose]) || _stampit).call(var1, var4);
    };
  }

  var allUtilities = {};

  allUtilities[_methods] = createUtilityFunction(_methods, assign);

  allUtilities[_properties] = allUtilities.refs = allUtilities.props =
    createUtilityFunction(_properties, assign);

  allUtilities[_initializers] = allUtilities.init =
    createUtilityFunction(_initializers, extractFunctions);

  allUtilities[_composers] = createUtilityFunction(_composers, extractFunctions);

  allUtilities[_deepProperties] = allUtilities[_deepProps] =
    createUtilityFunction(_deepProperties, merge);

  allUtilities[_staticProperties] = allUtilities.statics =
    createUtilityFunction(_staticProperties, assign);

  allUtilities[_staticDeepProperties] = allUtilities[_deepStatics] =
    createUtilityFunction(_staticDeepProperties, merge);

  allUtilities[_configuration] = allUtilities.conf =
    createUtilityFunction(_configuration, assign);

  allUtilities[_deepConfiguration] = allUtilities[_deepConf] =
    createUtilityFunction(_deepConfiguration, merge);

  allUtilities[_propertyDescriptors] = createUtilityFunction(_propertyDescriptors, assign);

  allUtilities[_staticPropertyDescriptors] = createUtilityFunction(_staticPropertyDescriptors, assign);

  /**
   * Infected compose
   * Parameters:  {...Composable} The list of composables.
   * @return {Stamp} The Stampit-flavoured stamp
   */
  var _stampit = assign(function stampit() {
    var i = 0, tmp1, composables = [], uniqueComposers, tmp2 = arguments, tmp3;
    for (; i < tmp2[_length]; i) {
      tmp1 = tmp2[i++];
      if (isObject(tmp1)) {
        composables.push(isStamp(tmp1) ? tmp1 : standardiseDescriptor(tmp1));
      }
    }

    // Calling the standard pure compose function here.
    tmp1 = compose.apply(this || baseStampit, composables);

    tmp2 = tmp1[_compose][_deepConfiguration];
    tmp3 = tmp2 && tmp2[_composers];
    if (tmp3 && tmp3[_length] > 0) {
      pushUniqueFuncs(tmp2[_composers] = uniqueComposers = [], tmp3);

      if (isStamp(this)) {
        composables.unshift(this);
      }
      for (i = 0; i < uniqueComposers[_length]; i) {
        tmp3 = uniqueComposers[i++]({stamp: tmp1, composables: composables});
        tmp1 = isStamp(tmp3) ? tmp3 : tmp1;
      }
    }

    return tmp1;
  }, allUtilities); // Setting up the shortcut functions

  var4 = {};
  allUtilities[_create] = function() {
    return this.apply(_undefined, arguments);
  };
  allUtilities[_compose] = _stampit;
  var4[_staticProperties] = allUtilities;

  /**
   * Infected stamp. Used as a storage of the infection metadata
   * @type {Function}
   * @return {Stamp}
   */
  var baseStampit = compose(var4);

  _stampit[_compose] = _stampit.bind(); // bind to undefined

  if (typeof _undefined != typeof module) module.exports = _stampit; else self.stampit = _stampit;
}();
<commit_msg>Further minification 11<commit_after>!function() {
  var _undefined;

  var var1 = 'roperties';
  var var2 = 'ropertyDescriptors';
  var var3 = 'static';
  var var4 = 'onfiguration';
  var _properties = 'p' + var1;
  var _deepProperties = 'deepP' + var1;
  var _propertyDescriptors = 'p' + var2;
  var _staticProperties = var3 + 'P' + var1;
  var _staticDeepProperties = var3 + 'DeepP' + var1;
  var _staticPropertyDescriptors = var3 + 'P' + var2;
  var _configuration = 'c' + var4;
  var _deepConfiguration = 'deepC' + var4;
  var _deepProps = 'deepProps';
  var _deepStatics = 'deepStatics';
  var _deepConf = 'deepConf';
  var _initializers = 'initializers';
  var _methods = 'methods';
  var _composers = 'composers';
  var _compose = 'compose';
  var _object = 'object';
  var _length = 'length';
  var _create = 'create';
  var _Object = Object;
  var isArray = Array.isArray;
  var defineProperties = _Object.defineProperties;
  var objectKeys = _Object.keys;
  var3 = Array.prototype;
  var concat = var3.concat;
  var slice = var3.slice;

  var assign = _Object.assign || function(to) {
    var args = arguments, s = 1, from, keys, i;

    for (; s < args[_length];) {
      from = args[s++];
      if (from) {
        keys = objectKeys(from);
        for (i = 0; i < keys[_length]; i++) {
          to[keys[i]] = from[keys[i]];
        }
      }
    }

    return to;
  };

  function isFunction(obj) {
    return typeof obj == 'function';
  }

  function isObject(obj) {
    return obj && (typeof obj == _object || isFunction(obj));
  }

  function isPlainObject(value) {
    return value && typeof value == _object &&
      value.__proto__ == _Object.prototype;
  }

  /**
   * The 'src' argument plays the command role.
   * The returned values is always of the same type as the 'src'.
   * @param {Array|Object|*} dst Destination
   * @param {Array|Object|*} src Source
   * @returns {Array|Object|*} The `dst` argument
   */
  function mergeOne(dst, src) {
    if (src === _undefined) return dst;

    // According to specification arrays must be concatenated.
    // Also, the '.concat' creates a new array instance. Overrides the 'dst'.
    if (isArray(src)) return (isArray(dst) ? dst : []).concat(src);

    // Now deal with non plain 'src' object. 'src' overrides 'dst'
    // Note that functions are also assigned! We do not deep merge functions.
    if (!isPlainObject(src)) return src;

    // See if 'dst' is allowed to be mutated.
    // If not - it's overridden with a new plain object.
    var returnValue = isObject(dst) ? dst : {};

    var keys = objectKeys(src), i = 0, key, srcValue, dstValue, newDst;
    for (; i < keys[_length];) {
      key = keys[i++];

      srcValue = src[key];
      // Do not merge properties with the '_undefined' value.
      if (srcValue !== _undefined) {
        dstValue = returnValue[key];
        // Recursive calls to mergeOne() must allow only plain objects or arrays in dst
        newDst = isPlainObject(dstValue) || isArray(srcValue) ? dstValue : {};

        // deep merge each property. Recursion!
        returnValue[key] = mergeOne(newDst, srcValue);
      }
    }

    return returnValue;
  }

  function merge(dst) {
    return slice.call(arguments, 1).reduce(mergeOne, dst);
  }

  function extractFunctions() {
    var1 = concat.apply([], arguments).filter(isFunction);
    return var1[_length] == 0 ? _undefined : var1;
  }

  function pushUniqueFuncs(dst, src) {
    var i = 0, fn;
    for (; i < src[_length]; i) {
      fn = src[i++];
      if (isFunction(fn) && dst.indexOf(fn) < 0) {
        dst.push(fn);
      }
    }
  }

  function concatAssignFunctions(dstObject, srcArray, propName) {
    if (isArray(srcArray)) {
      pushUniqueFuncs(dstObject[propName] = dstObject[propName] || [], srcArray);
    }
  }

  /**
   * Converts stampit extended descriptor to a standard one.
   * @param {Object|*} descr
   * methods
   * properties
   * props
   * refs
   * initializers
   * [init
   * deepProperties
   * deepProps
   * propertyDescriptors
   * staticProperties
   * statics
   * staticDeepProperties
   * deepStatics
   * staticPropertyDescriptors
   * configuration
   * conf
   * deepConfiguration
   * deepConf
   * composers
   * @returns {Descriptor} Standardised descriptor
   */
  function standardiseDescriptor(descr) {
    if (!isObject(descr)) return descr;
    var4 = {};

    var4[_methods] = descr[_methods] || _undefined;

    var1 = descr[_properties];
    var2 = descr.props;
    var3 = descr.refs;
    var4[_properties] = isObject(var1 || var2 || var3) ? assign({}, var3, var2, var1) : _undefined;

    var4[_initializers] = extractFunctions(descr.init, descr[_initializers]);

    var1 = descr[_deepProperties];
    var2 = descr[_deepProps];
    var4[_deepProperties] = isObject(var1 || var2) ? merge({}, var2, var1) : _undefined;

    var4[_propertyDescriptors] = descr[_propertyDescriptors];

    var1 = descr[_staticProperties];
    var2 = descr.statics;
    var4[_staticProperties] = isObject(var1 || var2) ? assign({}, var2, var1) : _undefined;

    var1 = descr[_staticDeepProperties];
    var2 = descr[_deepStatics];
    var4[_staticDeepProperties] = isObject(var1 || var2) ? merge({}, var2, var1) : _undefined;

    var4[_staticPropertyDescriptors] = descr[_staticPropertyDescriptors];

    var1 = descr[_configuration];
    var2 = descr.conf;
    var4[_configuration] = isObject(var1 || var2) ? assign({}, var2, var1) : _undefined;

    var1 = descr[_deepConfiguration];
    var2 = descr[_deepConf];
    var3 = isObject(var1 || var2) ? merge({}, var2, var1) : _undefined;

    var1 = extractFunctions(descr[_composers]);
    if (var1) {
      var3 = var3 || {};
      concatAssignFunctions(var3, var1, _composers);
    }

    var4[_deepConfiguration] = var3;

    return var4;
  }

  /**
   * Creates new factory instance.
   * @returns {Function} The new factory function.
   */
  function createFactory() {
    return function Stamp(options) {
      var i = Stamp[_compose] || {};
      // Next line was optimized for most JS VMs. Please, be careful here!
      var obj = _Object[_create](i[_methods] || null);

      var inits = i[_initializers], args = slice.apply(arguments);
      var initializer, returnedValue;

      var tmp = i[_deepProperties];
      if (tmp) merge(obj, tmp);
      tmp = i[_properties];
      if (tmp) assign(obj, tmp);
      tmp = i[_propertyDescriptors];
      if (tmp) defineProperties(obj, tmp);

      if (!inits || inits[_length] == 0) return obj;

      if (options === _undefined) options = {};
      for (i = 0; i < inits[_length];) {
        initializer = inits[i++];
        if (isFunction(initializer)) {
          returnedValue = initializer.call(obj, options,
            {instance: obj, stamp: Stamp, args: args});
          obj = returnedValue === _undefined ? obj : returnedValue;
        }
      }

      return obj;
    };
  }

  /**
   * Returns a new stamp given a descriptor and a compose function implementation.
   * @param {Descriptor} [descriptor={}] The information about the object the stamp will be creating.
   * @returns {Stamp} The new stamp
   */
  function createStamp(descriptor) {
    var1 = createFactory();

    var2 = descriptor[_staticDeepProperties];
    var2 && merge(var1, var2);

    var2 = descriptor[_staticProperties];
    var2 && assign(var1, var2);

    var2 = descriptor[_staticPropertyDescriptors];
    var2 && defineProperties(var1, var2);

    var2 = isFunction(var1[_compose]) ? var1[_compose] : compose;
    assign(var1[_compose] = function() {
      return var2.apply(this, arguments);
    }, descriptor);

    return var1;
  }

  /**
   * Mutates the dstDescriptor by merging the srcComposable data into it.
   * @param {Descriptor} dstDescriptor The descriptor object to merge into.
   * @param {Composable} [srcComposable] The composable
   * (either descriptor or stamp) to merge data form.
   * @returns {Descriptor} Returns the dstDescriptor argument.
   */
  function mergeComposable(dstDescriptor, srcComposable) {
    var4 = (srcComposable && srcComposable[_compose]) || srcComposable;
    if (isObject(var4)) {
      function mergeAssign(propName, deep) {
        if (!isObject(var4[propName])) {
          return;
        }
        if (!isObject(dstDescriptor[propName])) {
          dstDescriptor[propName] = {};
        }
        (deep || assign)(dstDescriptor[propName], var4[propName]);
      }

      mergeAssign(_methods);
      mergeAssign(_properties);
      mergeAssign(_deepProperties, merge);
      mergeAssign(_propertyDescriptors);
      mergeAssign(_staticProperties);
      mergeAssign(_staticDeepProperties, merge);
      mergeAssign(_staticPropertyDescriptors, merge);
      mergeAssign(_configuration);
      mergeAssign(_deepConfiguration, merge);
      concatAssignFunctions(dstDescriptor, var4[_initializers], _initializers);
    }

    return dstDescriptor;
  }

  /**
   * Given the list of composables (stamp descriptors and stamps) returns
   * a new stamp (composable factory function).
   * @typedef {Function} Compose
   * Parameters:  {...Composable} The list of composables.
   * @returns {Stamp} A new stamp (aka composable factory function)
   */
  function compose() {
    var descriptor = concat.apply([this], arguments)
    .filter(isObject)
    .reduce(mergeComposable, {});
    return createStamp(descriptor);
  }

  /**
   * The Stamp Descriptor
   * @typedef {Function|Object} Descriptor
   * @returns {Stamp} A new stamp based on this Stamp
   * @property {Object} [methods] Methods or other data used as object instances' prototype
   * @property {Array<Function>} [initializers] List of initializers called for each object instance
   * @property {Object} [properties] Shallow assigned properties of object instances
   * @property {Object} [deepProperties] Deeply merged properties of object instances
   * @property {Object} [staticProperties] Shallow assigned properties of Stamps
   * @property {Object} [staticDeepProperties] Deeply merged properties of Stamps
   * @property {Object} [configuration] Shallow assigned properties of Stamp arbitrary metadata
   * @property {Object} [deepConfiguration] Deeply merged properties of Stamp arbitrary metadata
   * @property {Object} [propertyDescriptors] ES5 Property Descriptors applied to object instances
   * @property {Object} [staticPropertyDescriptors] ES5 Property Descriptors applied to Stamps
   */

  /**
   * The Stamp factory function
   * @typedef {Function} Stamp
   * @returns {*} Instantiated object
   * @property {Descriptor} compose - The Stamp descriptor and composition function
   */

  /**
   * A composable object - stamp or descriptor
   * @typedef {Stamp|Descriptor} Composable
   */

  /**
   * Returns true if argument is a stamp.
   * @param {*} obj Any object
   * @returns {Boolean} True is the obj is a stamp
   */
  function isStamp(obj) {
    return isFunction(obj) && isFunction(obj[_compose]);
  }

  function createUtilityFunction(propName, action) {
    return function() {
      var4 = {};
      var3 = concat.apply([{}], arguments);
      var4[propName] = action.apply(_undefined, var3);
      var1 = this;

      return ((var1 && var1[_compose]) || _stampit).call(var1, var4);
    };
  }

  var allUtilities = {};

  allUtilities[_methods] = createUtilityFunction(_methods, assign);

  allUtilities[_properties] = allUtilities.refs = allUtilities.props =
    createUtilityFunction(_properties, assign);

  allUtilities[_initializers] = allUtilities.init =
    createUtilityFunction(_initializers, extractFunctions);

  allUtilities[_composers] = createUtilityFunction(_composers, extractFunctions);

  allUtilities[_deepProperties] = allUtilities[_deepProps] =
    createUtilityFunction(_deepProperties, merge);

  allUtilities[_staticProperties] = allUtilities.statics =
    createUtilityFunction(_staticProperties, assign);

  allUtilities[_staticDeepProperties] = allUtilities[_deepStatics] =
    createUtilityFunction(_staticDeepProperties, merge);

  allUtilities[_configuration] = allUtilities.conf =
    createUtilityFunction(_configuration, assign);

  allUtilities[_deepConfiguration] = allUtilities[_deepConf] =
    createUtilityFunction(_deepConfiguration, merge);

  allUtilities[_propertyDescriptors] = createUtilityFunction(_propertyDescriptors, assign);

  allUtilities[_staticPropertyDescriptors] = createUtilityFunction(_staticPropertyDescriptors, assign);

  /**
   * Infected compose
   * Parameters:  {...Composable} The list of composables.
   * @return {Stamp} The Stampit-flavoured stamp
   */
  var _stampit = assign(function stampit() {
    var i = 0, tmp1, composables = [], uniqueComposers, tmp2 = arguments, tmp3;
    for (; i < tmp2[_length]; i) {
      tmp1 = tmp2[i++];
      if (isObject(tmp1)) {
        composables.push(isStamp(tmp1) ? tmp1 : standardiseDescriptor(tmp1));
      }
    }

    // Calling the standard pure compose function here.
    tmp1 = compose.apply(this || baseStampit, composables);

    tmp2 = tmp1[_compose][_deepConfiguration];
    tmp3 = tmp2 && tmp2[_composers];
    if (tmp3 && tmp3[_length] > 0) {
      pushUniqueFuncs(tmp2[_composers] = uniqueComposers = [], tmp3);

      if (isStamp(this)) {
        composables.unshift(this);
      }
      for (i = 0; i < uniqueComposers[_length]; i) {
        tmp3 = uniqueComposers[i++]({stamp: tmp1, composables: composables});
        tmp1 = isStamp(tmp3) ? tmp3 : tmp1;
      }
    }

    return tmp1;
  }, allUtilities); // Setting up the shortcut functions

  var4 = {};
  allUtilities[_create] = function() {
    return this.apply(_undefined, arguments);
  };
  allUtilities[_compose] = _stampit;
  var4[_staticProperties] = allUtilities;

  /**
   * Infected stamp. Used as a storage of the infection metadata
   * @type {Function}
   * @return {Stamp}
   */
  var baseStampit = compose(var4);

  _stampit[_compose] = _stampit.bind(); // bind to undefined

  if (typeof _undefined != typeof module) module.exports = _stampit; else self.stampit = _stampit;
}();
<|endoftext|>


<commit_before>"use strict";

/*  ------------------------------------------------------------------------ */

const O              = Object,
      isBrowser      = (typeof window !== 'undefined') && (window.window === window) && window.navigator,
      nodeRequire    = isBrowser ? null : module.require, // to prevent bundlers from expanding the require call
      lastOf         = x => x[x.length - 1],
      getSource      = require ('get-source'),
      partition      = require ('./impl/partition'),
      asTable        = require ('as-table'),
      nixSlashes     = x => x.replace (/\\/g, '/'),
      pathRoot       = isBrowser ? window.location.href : (nixSlashes (process.cwd ()) + '/'),
      pathToRelative = isBrowser ? ((root, full) => full.replace (root, '')) : nodeRequire ('path').relative

/*  ------------------------------------------------------------------------ */

class StackTracey {

    constructor (input, offset) {

        const originalInput          = input
            , isParseableSyntaxError = input && (input instanceof SyntaxError && !isBrowser)

    /*  new StackTracey ()            */

        if (!input) {
             input = new Error ()
             offset = (offset === undefined) ? 1 : offset
        }

    /*  new StackTracey (Error)      */

        if (input instanceof Error) {
            input = input.stack || ''
        }

    /*  new StackTracey (string)     */

        if (typeof input === 'string') {
            input = this.rawParse (input).slice (offset).map (x => this.extractEntryMetadata (x))
        }

    /*  new StackTracey (array)      */

        if (Array.isArray (input)) {

            if (isParseableSyntaxError) {

                const rawLines = nodeRequire ('util').inspect (originalInput).split ('\n')
                    , fileLine = rawLines[0].split (':')
                    , line = fileLine.pop ()
                    , file = fileLine.join (':')

                if (file) {
                    input.unshift ({
                        file: nixSlashes (file),
                        line: line,
                        column: (rawLines[2] || '').indexOf ('^') + 1,
                        sourceLine: rawLines[1],
                        callee: '(syntax error)',
                        syntaxError: true
                    })
                }
            }

            this.items = input

        } else {
            this.items = []
        }
    }

    extractEntryMetadata (e) {

        const decomposedPath = this.decomposePath (e.file || '')
        const fileRelative = decomposedPath[0]
        const externalDomain = decomposedPath[1]

        return O.assign (e, {

            calleeShort:    e.calleeShort || lastOf ((e.callee || '').split ('.')),
            fileRelative:   fileRelative,
            fileShort:      this.shortenPath (fileRelative),
            fileName:       lastOf ((e.file || '').split ('/')),
            thirdParty:     this.isThirdParty (fileRelative, externalDomain) && !e.index,
            externalDomain: externalDomain
        })
    }

    shortenPath (relativePath) {
        return relativePath.replace (/^node_modules\//, '')
                           .replace (/^webpack\/bootstrap\//, '')
                           .replace (/^__parcel_source_root\//, '')
    }

    decomposePath (fullPath) {
        let fileRelative = pathToRelative (pathRoot, fullPath)

        const externalDomainMatch = fileRelative.match (/^(http|https)\:\/\/?([^\/]+)\/(.*)/)
        const externalDomain = externalDomainMatch ? externalDomainMatch[2] : undefined
        fileRelative = externalDomainMatch ? externalDomainMatch[3] : fileRelative

        return [
            nixSlashes(fileRelative).replace (/^.*\:\/\/?\/?/, ''), // cut webpack:/// and webpack:/ things
            externalDomain
        ]
    }

    isThirdParty (relativePath, externalDomain) {
        return externalDomain ||
               (relativePath[0] === '~')                          || // webpack-specific heuristic
               (relativePath[0] === '/')                          || // external source
               (relativePath.indexOf ('node_modules')      === 0) ||
               (relativePath.indexOf ('webpack/bootstrap') === 0)
    }

    rawParse (str) {

        const lines = (str || '').split ('\n')

        const entries = lines.map (line => {

            line = line.trim ()

            let callee, fileLineColumn = [], native, planA, planB

            if ((planA = line.match (/at (.+) \(eval at .+ \((.+)\), .+\)/)) || // eval calls
                (planA = line.match (/at (.+) \((.+)\)/)) ||
                ((line.slice (0, 3) !== 'at ') && (planA = line.match (/(.*)@(.*)/)))) {

                callee         =  planA[1]
                native         = (planA[2] === 'native')
                fileLineColumn = (planA[2].match (/(.*):(.+):(.+)/) || []).slice (1)

            } else if ((planB = line.match (/^(at\s+)*(.+):([0-9]+):([0-9]+)/) )) {
                fileLineColumn = (planB).slice (2)

            } else {
                return undefined
            }

        /*  Detect things like Array.reduce
            TODO: detect more built-in types            */

            if (callee && !fileLineColumn[0]) {
                const type = callee.split ('.')[0]
                if (type === 'Array') {
                    native = true
                }
            }

            return {
                beforeParse: line,
                callee:      callee || '',
                index:       isBrowser && (fileLineColumn[0] === window.location.href),
                native:      native || false,
                file:        nixSlashes (fileLineColumn[0] || ''),
                line:        parseInt (fileLineColumn[1] || '', 10) || undefined,
                column:      parseInt (fileLineColumn[2] || '', 10) || undefined
            }
        })

        return entries.filter (x => (x !== undefined))
    }

    withSourceAt (i) {
        return this.items[i] && this.withSource (this.items[i])
    }

    withSourceAsyncAt (i) {
        return this.items[i] && this.withSourceAsync (this.items[i])
    }

    withSource (loc) {

        if (this.shouldSkipResolving (loc)) {
            return loc

        } else {

            let resolved = getSource (loc.file || '').resolve (loc)

            if (!resolved.sourceFile) {
                return loc
            }

            return this.withSourceResolved (loc, resolved)
        }
    }

    withSourceAsync (loc) {

        if (this.shouldSkipResolving (loc)) {
            return Promise.resolve (loc)

        } else {
            return getSource.async (loc.file || '')
                        .then (x => x.resolve (loc))
                        .then (resolved => this.withSourceResolved (loc, resolved))
                        .catch (e => this.withSourceResolved (loc, { error: e, sourceLine: '' }))
        }
    }

    shouldSkipResolving (loc) {
        return loc.sourceFile || loc.error || (loc.file && loc.file.indexOf ('<') >= 0) // skip things like <anonymous> and stuff that was already fetched
    }

    withSourceResolved (loc, resolved) {

        if (resolved.sourceFile && !resolved.sourceFile.error) {
            resolved.file = nixSlashes (resolved.sourceFile.path)
            resolved = this.extractEntryMetadata (resolved)
        }

        if (resolved.sourceLine.includes ('// @hide')) {
            resolved.sourceLine = resolved.sourceLine.replace  ('// @hide', '')
            resolved.hide       = true
        }

        if (resolved.sourceLine.includes ('__webpack_require__') || // webpack-specific heuristics
            resolved.sourceLine.includes ('/******/ ({')) {
            resolved.thirdParty = true
        }

        return O.assign ({ sourceLine: '' }, loc, resolved)
    }

    withSources () {
        return this.map (x => this.withSource (x))
    }

    withSourcesAsync () {
        return Promise.all (this.items.map (x => this.withSourceAsync (x)))
                      .then (items => new StackTracey (items))
    }

    mergeRepeatedLines () {
        return new StackTracey (
            partition (this.items, e => e.file + e.line).map (
                group => {
                    return group.items.slice (1).reduce ((memo, entry) => {
                        memo.callee      = (memo.callee      || '<anonymous>') + ' → ' + (entry.callee      || '<anonymous>')
                        memo.calleeShort = (memo.calleeShort || '<anonymous>') + ' → ' + (entry.calleeShort || '<anonymous>')
                        return memo
                    }, O.assign ({}, group.items[0]))
                }
            )
        )
    }

    clean () {
        const s = this.withSources ().mergeRepeatedLines ()
        return s.filter (s.isClean.bind (s))
    }

    cleanAsync () {
        return this.withSourcesAsync ().then (s => {
            s = s.mergeRepeatedLines ()
            return s.filter (s.isClean.bind (s))
        })
    }

    isClean (entry, index) {
        return (index === 0) || !(entry.thirdParty || entry.hide || entry.native)
    }

    at (i) {
        return O.assign ({

            beforeParse: '',
            callee:      '<???>',
            index:       false,
            native:      false,
            file:        '<???>',
            line:        0,
            column:      0

        }, this.items[i])
    }

    asTable (opts) {

        const maxColumnWidths = (opts && opts.maxColumnWidths) || this.maxColumnWidths ()

        const trimEnd   = (s, n) => s && ((s.length > n) ? (s.slice (0, n-1) + '…') : s)
        const trimStart = (s, n) => s && ((s.length > n) ? ('…' + s.slice (-(n-1))) : s)

        const trimmed = this.map (
            e => [
                ('at ' + trimEnd (e.calleeShort,                                maxColumnWidths.callee)),
                trimStart ((e.fileShort && (e.fileShort + ':' + e.line)) || '', maxColumnWidths.file),
                trimEnd (((e.sourceLine || '').trim () || ''),                  maxColumnWidths.sourceLine)
            ]
        )

        return asTable (trimmed.items)
    }

    maxColumnWidths () {
        return {
            callee:     30,
            file:       60,
            sourceLine: 80
        }
    }

    static resetCache () {

        getSource.resetCache ()
        getSource.async.resetCache ()
    }

    static locationsEqual (a, b) {

        return (a.file   === b.file) &&
               (a.line   === b.line) &&
               (a.column === b.column)
    }
}

/*  Array methods
    ------------------------------------------------------------------------ */

;['map', 'filter', 'slice', 'concat'].forEach (method => {

    StackTracey.prototype[method] = function (/*...args */) { // no support for ...args in Node v4 :(
        return new StackTracey (this.items[method].apply (this.items, arguments))
    }
})

/*  ------------------------------------------------------------------------ */

module.exports = StackTracey

<commit_msg>debug (CI)<commit_after>"use strict";

/*  ------------------------------------------------------------------------ */

const O              = Object,
      isBrowser      = (typeof window !== 'undefined') && (window.window === window) && window.navigator,
      nodeRequire    = isBrowser ? null : module.require, // to prevent bundlers from expanding the require call
      lastOf         = x => x[x.length - 1],
      getSource      = require ('get-source'),
      partition      = require ('./impl/partition'),
      asTable        = require ('as-table'),
      nixSlashes     = x => x.replace (/\\/g, '/'),
      pathRoot       = isBrowser ? window.location.href : (nixSlashes (process.cwd ()) + '/'),
      pathToRelative = isBrowser ? ((root, full) => full.replace (root, '')) : nodeRequire ('path').relative

/*  ------------------------------------------------------------------------ */

class StackTracey {

    constructor (input, offset) {

        const originalInput          = input
            , isParseableSyntaxError = input && (input instanceof SyntaxError && !isBrowser)

    /*  new StackTracey ()            */

        if (!input) {
             input = new Error ()
             offset = (offset === undefined) ? 1 : offset
        }

    /*  new StackTracey (Error)      */

        if (input instanceof Error) {
            input = input.stack || ''
        }

    /*  new StackTracey (string)     */

        if (typeof input === 'string') {
            input = this.rawParse (input).slice (offset).map (x => this.extractEntryMetadata (x))
        }

    /*  new StackTracey (array)      */

        if (Array.isArray (input)) {

            if (isParseableSyntaxError) {

                const rawLines = nodeRequire ('util').inspect (originalInput).split ('\n')
                    , fileLine = rawLines[0].split (':')
                    , line = fileLine.pop ()
                    , file = fileLine.join (':')

                if (file) {
                    input.unshift ({
                        file: nixSlashes (file),
                        line: line,
                        column: (rawLines[2] || '').indexOf ('^') + 1,
                        sourceLine: rawLines[1],
                        callee: '(syntax error)',
                        syntaxError: true
                    })
                }
            }

            this.items = input

        } else {
            this.items = []
        }
    }

    extractEntryMetadata (e) {

        const decomposedPath = this.decomposePath (e.file || '')
        const fileRelative = decomposedPath[0]
        const externalDomain = decomposedPath[1]

        return O.assign (e, {

            calleeShort:    e.calleeShort || lastOf ((e.callee || '').split ('.')),
            fileRelative:   fileRelative,
            fileShort:      this.shortenPath (fileRelative),
            fileName:       lastOf ((e.file || '').split ('/')),
            thirdParty:     this.isThirdParty (fileRelative, externalDomain) && !e.index,
            externalDomain: externalDomain
        })
    }

    shortenPath (relativePath) {
        return relativePath.replace (/^node_modules\//, '')
                           .replace (/^webpack\/bootstrap\//, '')
                           .replace (/^__parcel_source_root\//, '')
    }

    decomposePath (fullPath) {
        let fileRelative = pathToRelative (pathRoot, fullPath)

        console.log({ fileRelative, pathRoot, fullPath, match: fileRelative.match (/^(http|https)\:\/\/?([^\/]+)\/(.*)/) })

        const externalDomainMatch = fileRelative.match (/^(http|https)\:\/\/?([^\/]+)\/(.*)/)
        const externalDomain = externalDomainMatch ? externalDomainMatch[2] : undefined
        fileRelative = externalDomainMatch ? externalDomainMatch[3] : fileRelative

        return [
            nixSlashes(fileRelative).replace (/^.*\:\/\/?\/?/, ''), // cut webpack:/// and webpack:/ things
            externalDomain
        ]
    }

    isThirdParty (relativePath, externalDomain) {
        return externalDomain ||
               (relativePath[0] === '~')                          || // webpack-specific heuristic
               (relativePath[0] === '/')                          || // external source
               (relativePath.indexOf ('node_modules')      === 0) ||
               (relativePath.indexOf ('webpack/bootstrap') === 0)
    }

    rawParse (str) {

        const lines = (str || '').split ('\n')

        const entries = lines.map (line => {

            line = line.trim ()

            let callee, fileLineColumn = [], native, planA, planB

            if ((planA = line.match (/at (.+) \(eval at .+ \((.+)\), .+\)/)) || // eval calls
                (planA = line.match (/at (.+) \((.+)\)/)) ||
                ((line.slice (0, 3) !== 'at ') && (planA = line.match (/(.*)@(.*)/)))) {

                callee         =  planA[1]
                native         = (planA[2] === 'native')
                fileLineColumn = (planA[2].match (/(.*):(.+):(.+)/) || []).slice (1)

            } else if ((planB = line.match (/^(at\s+)*(.+):([0-9]+):([0-9]+)/) )) {
                fileLineColumn = (planB).slice (2)

            } else {
                return undefined
            }

        /*  Detect things like Array.reduce
            TODO: detect more built-in types            */

            if (callee && !fileLineColumn[0]) {
                const type = callee.split ('.')[0]
                if (type === 'Array') {
                    native = true
                }
            }

            return {
                beforeParse: line,
                callee:      callee || '',
                index:       isBrowser && (fileLineColumn[0] === window.location.href),
                native:      native || false,
                file:        nixSlashes (fileLineColumn[0] || ''),
                line:        parseInt (fileLineColumn[1] || '', 10) || undefined,
                column:      parseInt (fileLineColumn[2] || '', 10) || undefined
            }
        })

        return entries.filter (x => (x !== undefined))
    }

    withSourceAt (i) {
        return this.items[i] && this.withSource (this.items[i])
    }

    withSourceAsyncAt (i) {
        return this.items[i] && this.withSourceAsync (this.items[i])
    }

    withSource (loc) {

        if (this.shouldSkipResolving (loc)) {
            return loc

        } else {

            let resolved = getSource (loc.file || '').resolve (loc)

            if (!resolved.sourceFile) {
                return loc
            }

            return this.withSourceResolved (loc, resolved)
        }
    }

    withSourceAsync (loc) {

        if (this.shouldSkipResolving (loc)) {
            return Promise.resolve (loc)

        } else {
            return getSource.async (loc.file || '')
                        .then (x => x.resolve (loc))
                        .then (resolved => this.withSourceResolved (loc, resolved))
                        .catch (e => this.withSourceResolved (loc, { error: e, sourceLine: '' }))
        }
    }

    shouldSkipResolving (loc) {
        return loc.sourceFile || loc.error || (loc.file && loc.file.indexOf ('<') >= 0) // skip things like <anonymous> and stuff that was already fetched
    }

    withSourceResolved (loc, resolved) {

        if (resolved.sourceFile && !resolved.sourceFile.error) {
            resolved.file = nixSlashes (resolved.sourceFile.path)
            resolved = this.extractEntryMetadata (resolved)
        }

        if (resolved.sourceLine.includes ('// @hide')) {
            resolved.sourceLine = resolved.sourceLine.replace  ('// @hide', '')
            resolved.hide       = true
        }

        if (resolved.sourceLine.includes ('__webpack_require__') || // webpack-specific heuristics
            resolved.sourceLine.includes ('/******/ ({')) {
            resolved.thirdParty = true
        }

        return O.assign ({ sourceLine: '' }, loc, resolved)
    }

    withSources () {
        return this.map (x => this.withSource (x))
    }

    withSourcesAsync () {
        return Promise.all (this.items.map (x => this.withSourceAsync (x)))
                      .then (items => new StackTracey (items))
    }

    mergeRepeatedLines () {
        return new StackTracey (
            partition (this.items, e => e.file + e.line).map (
                group => {
                    return group.items.slice (1).reduce ((memo, entry) => {
                        memo.callee      = (memo.callee      || '<anonymous>') + ' → ' + (entry.callee      || '<anonymous>')
                        memo.calleeShort = (memo.calleeShort || '<anonymous>') + ' → ' + (entry.calleeShort || '<anonymous>')
                        return memo
                    }, O.assign ({}, group.items[0]))
                }
            )
        )
    }

    clean () {
        const s = this.withSources ().mergeRepeatedLines ()
        return s.filter (s.isClean.bind (s))
    }

    cleanAsync () {
        return this.withSourcesAsync ().then (s => {
            s = s.mergeRepeatedLines ()
            return s.filter (s.isClean.bind (s))
        })
    }

    isClean (entry, index) {
        return (index === 0) || !(entry.thirdParty || entry.hide || entry.native)
    }

    at (i) {
        return O.assign ({

            beforeParse: '',
            callee:      '<???>',
            index:       false,
            native:      false,
            file:        '<???>',
            line:        0,
            column:      0

        }, this.items[i])
    }

    asTable (opts) {

        const maxColumnWidths = (opts && opts.maxColumnWidths) || this.maxColumnWidths ()

        const trimEnd   = (s, n) => s && ((s.length > n) ? (s.slice (0, n-1) + '…') : s)
        const trimStart = (s, n) => s && ((s.length > n) ? ('…' + s.slice (-(n-1))) : s)

        const trimmed = this.map (
            e => [
                ('at ' + trimEnd (e.calleeShort,                                maxColumnWidths.callee)),
                trimStart ((e.fileShort && (e.fileShort + ':' + e.line)) || '', maxColumnWidths.file),
                trimEnd (((e.sourceLine || '').trim () || ''),                  maxColumnWidths.sourceLine)
            ]
        )

        return asTable (trimmed.items)
    }

    maxColumnWidths () {
        return {
            callee:     30,
            file:       60,
            sourceLine: 80
        }
    }

    static resetCache () {

        getSource.resetCache ()
        getSource.async.resetCache ()
    }

    static locationsEqual (a, b) {

        return (a.file   === b.file) &&
               (a.line   === b.line) &&
               (a.column === b.column)
    }
}

/*  Array methods
    ------------------------------------------------------------------------ */

;['map', 'filter', 'slice', 'concat'].forEach (method => {

    StackTracey.prototype[method] = function (/*...args */) { // no support for ...args in Node v4 :(
        return new StackTracey (this.items[method].apply (this.items, arguments))
    }
})

/*  ------------------------------------------------------------------------ */

module.exports = StackTracey

<|endoftext|>