apks-utils.js 27 KB
"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

require("source-map-support/register");

var _teen_process = require("teen_process");

var _logger = _interopRequireDefault(require("../logger.js"));

var _path = _interopRequireDefault(require("path"));

var _lodash = _interopRequireDefault(require("lodash"));

var _appiumSupport = require("appium-support");

var _lruCache = _interopRequireDefault(require("lru-cache"));

var _helpers = require("../helpers.js");

var _asyncLock = _interopRequireDefault(require("async-lock"));

const BASE_APK = 'base-master.apk';

const LANGUAGE_APK = lang => `base-${lang}.apk`;

const APKS_CACHE = new _lruCache.default({
  max: 10,
  dispose: (apksHash, extractedFilesRoot) => _appiumSupport.fs.rimraf(extractedFilesRoot)
});
const APKS_CACHE_GUARD = new _asyncLock.default();

async function extractFromApks(apks, dstPath) {
  if (!_lodash.default.isArray(dstPath)) {
    dstPath = [dstPath];
  }

  return await APKS_CACHE_GUARD.acquire(apks, async () => {
    const apksHash = await _appiumSupport.fs.hash(apks);

    _logger.default.debug(`Calculated '${apks}' hash: ${apksHash}`);

    if (APKS_CACHE.has(apksHash)) {
      const resultPath = _path.default.resolve(APKS_CACHE.get(apksHash), ...dstPath);

      if (await _appiumSupport.fs.exists(resultPath)) {
        return resultPath;
      }

      APKS_CACHE.del(apksHash);
    }

    const tmpRoot = await _appiumSupport.tempDir.openDir();

    _logger.default.debug(`Unpacking application bundle at '${apks}' to '${tmpRoot}'`);

    await (0, _helpers.unzipFile)(apks, tmpRoot);

    const resultPath = _path.default.resolve(tmpRoot, ...dstPath);

    if (!(await _appiumSupport.fs.exists(resultPath))) {
      throw new Error(`${dstPath.join(_path.default.sep)} cannot be found in '${apks}' bundle. ` + `Does the archive contain a valid application bundle?`);
    }

    APKS_CACHE.set(apksHash, tmpRoot);
    return resultPath;
  });
}

let apksUtilsMethods = {};

apksUtilsMethods.execBundletool = async function execBundletool(args, errorMsg) {
  await this.initBundletool();
  args = ['-jar', this.binaries.bundletool, ...args];

  _logger.default.debug(`Executing bundletool with arguments: ${JSON.stringify(args)}`);

  let stdout;

  try {
    ({
      stdout
    } = await (0, _teen_process.exec)(await (0, _helpers.getJavaForOs)(), args));

    _logger.default.debug(`Command stdout: ${_lodash.default.truncate(stdout, {
      length: 300
    })}`);

    return stdout;
  } catch (e) {
    if (e.stdout) {
      _logger.default.debug(`Command stdout: ${e.stdout}`);
    }

    if (e.stderr) {
      _logger.default.debug(`Command stderr: ${e.stderr}`);
    }

    throw new Error(`${errorMsg}. Original error: ${e.message}`);
  }
};

apksUtilsMethods.getDeviceSpec = async function getDeviceSpec(specLocation) {
  const args = ['get-device-spec', '--adb', this.executable.path, '--device-id', this.curDeviceId, '--output', specLocation];

  _logger.default.debug(`Getting the spec for the device '${this.curDeviceId}'`);

  await this.execBundletool(args, 'Cannot retrieve the device spec');
  return specLocation;
};

apksUtilsMethods.installApks = async function installApks(apks, options = {}) {
  options = _lodash.default.cloneDeep(options);

  _lodash.default.defaults(options, {
    timeout: this.adbExecTimeout === _helpers.DEFAULT_ADB_EXEC_TIMEOUT ? _helpers.APKS_INSTALL_TIMEOUT : this.adbExecTimeout,
    timeoutCapName: 'androidInstallTimeout'
  });

  Object.assign(options, {
    replace: true
  });
  const tmpRoot = await _appiumSupport.tempDir.openDir();

  try {
    const specPath = await this.getDeviceSpec(_path.default.resolve(tmpRoot, 'deviceSpec.json'));
    const args = ['extract-apks', '--apks', apks, '--output-dir', tmpRoot, '--device-spec', specPath];

    _logger.default.debug(`Extracting the apk files from '${apks}'`);

    await this.execBundletool(args, `Cannot extract the application bundle at '${apks}'`);
    const installArgs = (0, _helpers.buildInstallArgs)(await this.getApiLevel(), options);
    const apkPathsToInstall = (await _appiumSupport.fs.readdir(tmpRoot)).filter(name => name.endsWith(_helpers.APK_EXTENSION)).map(name => _path.default.resolve(tmpRoot, name));

    _logger.default.debug('Got the following apk files to install: ' + JSON.stringify(apkPathsToInstall.map(x => _path.default.basename(x))));

    const output = await this.adbExec(['install-multiple', ...installArgs, ...apkPathsToInstall], {
      timeout: options.timeout,
      timeoutCapName: options.timeoutCapName
    });
    const truncatedOutput = !_lodash.default.isString(output) || output.length <= 300 ? output : `${output.substr(0, 150)}...${output.substr(output.length - 150)}`;

    _logger.default.debug(`Install command stdout: ${truncatedOutput}`);

    if (_lodash.default.includes(output, 'INSTALL_FAILED')) {
      throw new Error(output);
    }
  } finally {
    await _appiumSupport.fs.rimraf(tmpRoot);
  }
};

apksUtilsMethods.extractBaseApk = async function extractBaseApk(apks) {
  return await extractFromApks(apks, ['splits', BASE_APK]);
};

apksUtilsMethods.extractLanguageApk = async function extractLanguageApk(apks, language = null) {
  if (language) {
    try {
      return await extractFromApks(apks, ['splits', LANGUAGE_APK(language)]);
    } catch (e) {
      _logger.default.debug(e.message);

      _logger.default.info(`Assuming that splitting by language is not enabled for the '${apks}' bundle ` + `and returning the main apk instead`);

      return await this.extractBaseApk(apks);
    }
  }

  const defaultLanguages = ['en', 'en_us'];

  for (const lang of defaultLanguages) {
    try {
      return await extractFromApks(apks, ['splits', LANGUAGE_APK(lang)]);
    } catch (ign) {}
  }

  _logger.default.info(`Cannot find any split apk for the default languages ${JSON.stringify(defaultLanguages)}. ` + `Returning the main apk instead.`);

  return await this.extractBaseApk(apks);
};

apksUtilsMethods.isTestPackageOnlyError = function (output) {
  return /\[INSTALL_FAILED_TEST_ONLY\]/.test(output);
};

var _default = apksUtilsMethods;
exports.default = _default;require('source-map-support').install();


//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi90b29scy9hcGtzLXV0aWxzLmpzIl0sIm5hbWVzIjpbIkJBU0VfQVBLIiwiTEFOR1VBR0VfQVBLIiwibGFuZyIsIkFQS1NfQ0FDSEUiLCJMUlUiLCJtYXgiLCJkaXNwb3NlIiwiYXBrc0hhc2giLCJleHRyYWN0ZWRGaWxlc1Jvb3QiLCJmcyIsInJpbXJhZiIsIkFQS1NfQ0FDSEVfR1VBUkQiLCJBc3luY0xvY2siLCJleHRyYWN0RnJvbUFwa3MiLCJhcGtzIiwiZHN0UGF0aCIsIl8iLCJpc0FycmF5IiwiYWNxdWlyZSIsImhhc2giLCJsb2ciLCJkZWJ1ZyIsImhhcyIsInJlc3VsdFBhdGgiLCJwYXRoIiwicmVzb2x2ZSIsImdldCIsImV4aXN0cyIsImRlbCIsInRtcFJvb3QiLCJ0ZW1wRGlyIiwib3BlbkRpciIsIkVycm9yIiwiam9pbiIsInNlcCIsInNldCIsImFwa3NVdGlsc01ldGhvZHMiLCJleGVjQnVuZGxldG9vbCIsImFyZ3MiLCJlcnJvck1zZyIsImluaXRCdW5kbGV0b29sIiwiYmluYXJpZXMiLCJidW5kbGV0b29sIiwiSlNPTiIsInN0cmluZ2lmeSIsInN0ZG91dCIsInRydW5jYXRlIiwibGVuZ3RoIiwiZSIsInN0ZGVyciIsIm1lc3NhZ2UiLCJnZXREZXZpY2VTcGVjIiwic3BlY0xvY2F0aW9uIiwiZXhlY3V0YWJsZSIsImN1ckRldmljZUlkIiwiaW5zdGFsbEFwa3MiLCJvcHRpb25zIiwiY2xvbmVEZWVwIiwiZGVmYXVsdHMiLCJ0aW1lb3V0IiwiYWRiRXhlY1RpbWVvdXQiLCJERUZBVUxUX0FEQl9FWEVDX1RJTUVPVVQiLCJBUEtTX0lOU1RBTExfVElNRU9VVCIsInRpbWVvdXRDYXBOYW1lIiwiT2JqZWN0IiwiYXNzaWduIiwicmVwbGFjZSIsInNwZWNQYXRoIiwiaW5zdGFsbEFyZ3MiLCJnZXRBcGlMZXZlbCIsImFwa1BhdGhzVG9JbnN0YWxsIiwicmVhZGRpciIsImZpbHRlciIsIm5hbWUiLCJlbmRzV2l0aCIsIkFQS19FWFRFTlNJT04iLCJtYXAiLCJ4IiwiYmFzZW5hbWUiLCJvdXRwdXQiLCJhZGJFeGVjIiwidHJ1bmNhdGVkT3V0cHV0IiwiaXNTdHJpbmciLCJzdWJzdHIiLCJpbmNsdWRlcyIsImV4dHJhY3RCYXNlQXBrIiwiZXh0cmFjdExhbmd1YWdlQXBrIiwibGFuZ3VhZ2UiLCJpbmZvIiwiZGVmYXVsdExhbmd1YWdlcyIsImlnbiIsImlzVGVzdFBhY2thZ2VPbmx5RXJyb3IiLCJ0ZXN0Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUlBOztBQUVBLE1BQU1BLFFBQVEsR0FBRyxpQkFBakI7O0FBQ0EsTUFBTUMsWUFBWSxHQUFJQyxJQUFELElBQVcsUUFBT0EsSUFBSyxNQUE1Qzs7QUFDQSxNQUFNQyxVQUFVLEdBQUcsSUFBSUMsaUJBQUosQ0FBUTtBQUN6QkMsRUFBQUEsR0FBRyxFQUFFLEVBRG9CO0FBRXpCQyxFQUFBQSxPQUFPLEVBQUUsQ0FBQ0MsUUFBRCxFQUFXQyxrQkFBWCxLQUFrQ0Msa0JBQUdDLE1BQUgsQ0FBVUYsa0JBQVY7QUFGbEIsQ0FBUixDQUFuQjtBQUlBLE1BQU1HLGdCQUFnQixHQUFHLElBQUlDLGtCQUFKLEVBQXpCOztBQWVBLGVBQWVDLGVBQWYsQ0FBZ0NDLElBQWhDLEVBQXNDQyxPQUF0QyxFQUErQztBQUM3QyxNQUFJLENBQUNDLGdCQUFFQyxPQUFGLENBQVVGLE9BQVYsQ0FBTCxFQUF5QjtBQUN2QkEsSUFBQUEsT0FBTyxHQUFHLENBQUNBLE9BQUQsQ0FBVjtBQUNEOztBQUVELFNBQU8sTUFBTUosZ0JBQWdCLENBQUNPLE9BQWpCLENBQXlCSixJQUF6QixFQUErQixZQUFZO0FBSXRELFVBQU1QLFFBQVEsR0FBRyxNQUFNRSxrQkFBR1UsSUFBSCxDQUFRTCxJQUFSLENBQXZCOztBQUNBTSxvQkFBSUMsS0FBSixDQUFXLGVBQWNQLElBQUssV0FBVVAsUUFBUyxFQUFqRDs7QUFFQSxRQUFJSixVQUFVLENBQUNtQixHQUFY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QWU2QyxnQkFBZixDQUFpQyxJQUF4RixHQUNOLGlDQURIOztBQUVBLFNBQU8sTUFBTSxLQUFLSixjQUFMLENBQW9CdkUsSUFBcEIsQ0FBYjtBQUNELENBdEJEOztBQXdCQXNCLGdCQUFnQixDQUFDdUQsc0JBQWpCLEdBQTBDLFVBQVVaLE1BQVYsRUFBa0I7QUFDMUQsU0FBTywrQkFBK0JhLElBQS9CLENBQW9DYixNQUFwQyxDQUFQO0FBQ0QsQ0FGRDs7ZUFJZTNDLGdCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhlYyB9IGZyb20gJ3RlZW5fcHJvY2Vzcyc7XG5pbXBvcnQgbG9nIGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgeyBmcywgdGVtcERpciB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCBMUlUgZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCB7XG4gIGdldEphdmFGb3JPcywgdW56aXBGaWxlLCBidWlsZEluc3RhbGxBcmdzLFxuICBBUEtTX0lOU1RBTExfVElNRU9VVCwgQVBLX0VYVEVOU0lPTixcbiAgREVGQVVMVF9BREJfRVhFQ19USU1FT1VUIH0gZnJvbSAnLi4vaGVscGVycy5qcyc7XG5pbXBvcnQgQXN5bmNMb2NrIGZyb20gJ2FzeW5jLWxvY2snO1xuXG5jb25zdCBCQVNFX0FQSyA9ICdiYXNlLW1hc3Rlci5hcGsnO1xuY29uc3QgTEFOR1VBR0VfQVBLID0gKGxhbmcpID0+IGBiYXNlLSR7bGFuZ30uYXBrYDtcbmNvbnN0IEFQS1NfQ0FDSEUgPSBuZXcgTFJVKHtcbiAgbWF4OiAxMCxcbiAgZGlzcG9zZTogKGFwa3NIYXNoLCBleHRyYWN0ZWRGaWxlc1Jvb3QpID0+IGZzLnJpbXJhZihleHRyYWN0ZWRGaWxlc1Jvb3QpLFxufSk7XG5jb25zdCBBUEtTX0NBQ0hFX0dVQVJEID0gbmV3IEFzeW5jTG9jaygpO1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBwYXJ0aWN1bGFyIGFwa3MgcGFja2FnZSBpbnRvIGEgdGVtcG9yYXJ5IGZvbGRlcixcbiAqIGZpbmRzIGFuZCByZXR1cm5zIHRoZSBmdWxsIHBhdGggdG8gdGhlIGZpbGUgY29udGFpbmVkIGluIHRoaXMgYXBrLlxuICogVGhlIHJlc3VsdGluZyB0ZW1wb3JhcnkgcGF0aCwgd2hlcmUgdGhlIC5hcGtzIGZpbGUgaGFzIGJlZW4gZXh0cmFjdGVkLFxuICogd2lsbCBiZSBzdG9yZWQgaW50byB0aGUgaW50ZXJuYWwgTFJVIGNhY2hlIGZvciBiZXR0ZXIgcGVyZm9ybWFuY2UuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwa3MgLSBUaGUgZnVsbCBwYXRoIHRvIHRoZSAuYXBrcyBmaWxlXG4gKiBAcGFyYW0ge3N0cmluZ3xBcnJheTxTdHJpbmc+fSBkc3RQYXRoIC0gVGhlIHJlbGF0aXZlIHBhdGggdG8gdGhlIGRlc3RpbmF0aW9uIGZpbGUsXG4gKiB3aGljaCBpcyBnb2luZyB0byBiZSBleHRyYWN0ZWQsIHdoZXJlIGVhY2ggcGF0aCBjb21wb25lbnQgaXMgYW4gYXJyYXkgaXRlbVxuICogQHJldHVybnMge3N0cmluZ30gRnVsbCBwYXRoIHRvIHRoZSBleHRyYWN0ZWQgZmlsZVxuICogQHRocm93cyB7RXJyb3J9IElmIHRoZSByZXF1ZXN0ZWQgaXRlbSBkb2VzIG5vdCBleGlzdCBpbiB0aGUgZXh0cmFjdGVkIGFyY2hpdmUgb3IgdGhlIHByb3ZpZGVzXG4gKiBhcGtzIGZpbGUgaXMgbm90IGEgdmFsaWQgYnVuZGxlXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RGcm9tQXBrcyAoYXBrcywgZHN0UGF0aCkge1xuICBpZiAoIV8uaXNBcnJheShkc3RQYXRoKSkge1xuICAgIGRzdFBhdGggPSBbZHN0UGF0aF07XG4gIH1cblxuICByZXR1cm4gYXdhaXQgQVBLU19DQUNIRV9HVUFSRC5hY3F1aXJlKGFwa3MsIGFzeW5jICgpID0+IHtcbiAgICAvLyBJdCBtaWdodCBiZSB0aGF0IHRoZSBvcmlnaW5hbCBmaWxlIGhhcyBiZWVuIHJlcGxhY2VkLFxuICAgIC8vIHNvIHdlIG5lZWQgdG8ga2VlcCB0aGUgaGFzaCBzdW1zIGluc3RlYWQgb2YgdGhlIGFjdHVhbCBmaWxlIHBhdGhzXG4gICAgLy8gYXMgY2FjaGluZyBrZXlzXG4gICAgY29uc3QgYXBrc0hhc2ggPSBhd2FpdCBmcy5oYXNoKGFwa3MpO1xuICAgIGxvZy5kZWJ1ZyhgQ2FsY3VsYXRlZCAnJHthcGtzfScgaGFzaDogJHthcGtzSGFzaH1gKTtcblxuICAgIGlmIChBUEtTX0NBQ0hFLmhhcyhhcGtzSGFzaCkpIHtcbiAgICAgIGNvbnN0IHJlc3VsdFBhdGggPSBwYXRoLnJlc29sdmUoQVBLU19DQUNIRS5nZXQoYXBrc0hhc2gpLCAuLi5kc3RQYXRoKTtcbiAgICAgIGlmIChhd2FpdCBmcy5leGlzdHMocmVzdWx0UGF0aCkpIHtcbiAgICAgICAgcmV0dXJuIHJlc3VsdFBhdGg7XG4gICAgICB9XG4gICAgICBBUEtTX0NBQ0hFLmRlbChhcGtzSGFzaCk7XG4gICAgfVxuXG4gICAgY29uc3QgdG1wUm9vdCA9IGF3YWl0IHRlbXBEaXIub3BlbkRpcigpO1xuICAgIGxvZy5kZWJ1ZyhgVW5wYWNraW5nIGFwcGxpY2F0aW9uIGJ1bmRsZSBhdCAnJHthcGtzfScgdG8gJyR7dG1wUm9vdH0nYCk7XG4gICAgYXdhaXQgdW56aXBGaWxlKGFwa3MsIHRtcFJvb3QpO1xuICAgIGNvbnN0IHJlc3VsdFBhdGggPSBwYXRoLnJlc29sdmUodG1wUm9vdCwgLi4uZHN0UGF0aCk7XG4gICAgaWYgKCFhd2FpdCBmcy5leGlzdHMocmVzdWx0UGF0aCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgJHtkc3RQYXRoLmpvaW4ocGF0aC5zZXApfSBjYW5ub3QgYmUgZm91bmQgaW4gJyR7YXBrc30nIGJ1bmRsZS4gYCArXG4gICAgICAgIGBEb2VzIHRoZSBhcmNoaXZlIGNvbnRhaW4gYSB2YWxpZCBhcHBsaWNhdGlvbiBidW5kbGU/YCk7XG4gICAgfVxuICAgIEFQS1NfQ0FDSEUuc2V0KGFwa3NIYXNoLCB0bXBSb290KTtcbiAgICByZXR1cm4gcmVzdWx0UGF0aDtcbiAgfSk7XG59XG5cbmxldCBhcGtzVXRpbHNNZXRob2RzID0ge307XG5cbi8qKlxuICogRXhlY3V0ZXMgYnVuZGxldG9vbCB1dGlsaXR5IHdpdGggZ2l2ZW4gYXJndW1lbnRzIGFuZCByZXR1cm5zIHRoZSBhY3R1YWwgc3Rkb3V0XG4gKlxuICogQHBhcmFtIHtBcnJheTxTdHJpbmc+fSBhcmdzIC0gdGhlIGxpc3Qgb2YgYnVuZGxldG9vbCBhcmd1bWVudHNcbiAqIEBwYXJhbSB7c3RyaW5nfSBlcnJvck1zZyAtIFRoZSBjdXN0b21pemVkIGVycm9yIG1lc3NhZ2Ugc3RyaW5nXG4gKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgYWN0dWFsIGNvbW1hbmQgc3Rkb3V0XG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgYnVuZGxldG9vbCBqYXIgZG9lcyBub3QgZXhpc3QgaW4gUEFUSCBvciB0aGVyZSB3YXMgYW4gZXJyb3Igd2hpbGVcbiAqIGV4ZWN1dGluZyBpdFxuICovXG5hcGtzVXRpbHNNZXRob2RzLmV4ZWNCdW5kbGV0b29sID0gYXN5bmMgZnVuY3Rpb24gZXhlY0J1bmRsZXRvb2wgKGFyZ3MsIGVycm9yTXNnKSB7XG4gIGF3YWl0IHRoaXMuaW5pdEJ1bmRsZXRvb2woKTtcbiAgYXJncyA9IFtcbiAgICAnLWphcicsIHRoaXMuYmluYXJpZXMuYnVuZGxldG9vbCxcbiAgICAuLi5hcmdzXG4gIF07XG4gIGxvZy5kZWJ1ZyhgRXhlY3V0aW5nIGJ1bmRsZXRvb2wgd2l0aCBhcmd1bWVudHM6ICR7SlNPTi5zdHJpbmdpZnkoYXJncyl9YCk7XG4gIGxldCBzdGRvdXQ7XG4gIHRyeSB7XG4gICAgKHtzdGRvdXR9ID0gYXdhaXQgZXhlYyhhd2FpdCBnZXRKYXZhRm9yT3MoKSwgYXJncykpO1xuICAgIGxvZy5kZWJ1ZyhgQ29tbWFuZCBzdGRvdXQ6ICR7Xy50cnVuY2F0ZShzdGRvdXQsIHtsZW5ndGg6IDMwMH0pfWApO1xuICAgIHJldHVybiBzdGRvdXQ7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAoZS5zdGRvdXQpIHtcbiAgICAgIGxvZy5kZWJ1ZyhgQ29tbWFuZCBzdGRvdXQ6ICR7ZS5zdGRvdXR9YCk7XG4gICAgfVxuICAgIGlmIChlLnN0ZGVycikge1xuICAgICAgbG9nLmRlYnVnKGBDb21tYW5kIHN0ZGVycjogJHtlLnN0ZGVycn1gKTtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGAke2Vycm9yTXNnfS4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICB9XG59O1xuXG4vKipcbiAqIEBwYXJhbSB7c3RyaW5nfSBzcGVjTG9jYXRpb24gLSBUaGUgZnVsbCBwYXRoIHRvIHRoZSBnZW5lcmF0ZWQgZGV2aWNlIHNwZWMgbG9jYXRpb25cbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW1lIGBzcGVjTG9jYXRpb25gIHZhbHVlXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgaXQgaXMgbm90IHBvc3NpYmxlIHRvIHJldHJpZXZlIHRoZSBzcGVjIGZvciB0aGUgY3VycmVudCBkZXZpY2VcbiAqL1xuYXBrc1V0aWxzTWV0aG9kcy5nZXREZXZpY2VTcGVjID0gYXN5bmMgZnVuY3Rpb24gZ2V0RGV2aWNlU3BlYyAoc3BlY0xvY2F0aW9uKSB7XG4gIGNvbnN0IGFyZ3MgPSBbXG4gICAgJ2dldC1kZXZpY2Utc3BlYycsXG4gICAgJy0tYWRiJywgdGhpcy5leGVjdXRhYmxlLnBhdGgsXG4gICAgJy0tZGV2aWNlLWlkJywgdGhpcy5jdXJEZXZpY2VJZCxcbiAgICAnLS1vdXRwdXQnLCBzcGVjTG9jYXRpb24sXG4gIF07XG4gIGxvZy5kZWJ1ZyhgR2V0dGluZyB0aGUgc3BlYyBmb3IgdGhlIGRldmljZSAnJHt0aGlzLmN1ckRldmljZUlkfSdgKTtcbiAgYXdhaXQgdGhpcy5leGVjQnVuZGxldG9vbChhcmdzLCAnQ2Fubm90IHJldHJpZXZlIHRoZSBkZXZpY2Ugc3BlYycpO1xuICByZXR1cm4gc3BlY0xvY2F0aW9uO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBJbnN0YWxsQXBrc09wdGlvbnNcbiAqIEBwcm9wZXJ0eSB7P251bWJlcnxzdHJpbmd9IHRpbWVvdXQgWzIwMDAwXSAtIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgdW50aWxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSBpbnN0YWxsYXRpb24gaXMgY29tcGxldGVkXG4gKiBAcHJvcGVydHkge3N0cmluZ30gdGltZW91dENhcE5hbWUgW2FuZHJvaWRJbnN0YWxsVGltZW91dF0gLSBUaGUgdGltZW91dCBvcHRpb24gbmFtZVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXNlcnMgY2FuIGluY3JlYXNlIHRoZSB0aW1lb3V0LlxuICogQHByb3BlcnR5IHtib29sZWFufSBhbGxvd1Rlc3RQYWNrYWdlcyBbZmFsc2VdIC0gU2V0IHRvIHRydWUgaW4gb3JkZXIgdG8gYWxsb3cgdGVzdFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja2FnZXMgaW5zdGFsbGF0aW9uLlxuICogQHByb3BlcnR5IHtib29sZWFufSB1c2VTZGNhcmQgW2ZhbHNlXSAtIFNldCB0byB0cnVlIHRvIGluc3RhbGwgdGhlIGFwcCBvbiBzZGNhcmRcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnN0ZWFkIG9mIHRoZSBkZXZpY2UgbWVtb3J5LlxuICogQHByb3BlcnR5IHtib29sZWFufSBncmFudFBlcm1pc3Npb25zIFtmYWxzZV0gLSBTZXQgdG8gdHJ1ZSBpbiBvcmRlciB0byBncmFudCBhbGwgdGhlXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcm1pc3Npb25zIHJlcXVlc3RlZCBpbiB0aGUgYXBwbGljYXRpb24ncyBtYW5pZmVzdFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdXRvbWF0aWNhbGx5IGFmdGVyIHRoZSBpbnN0YWxsYXRpb24gaXMgY29tcGxldGVkXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuZGVyIEFuZHJvaWQgNisuXG4gKi9cblxuLyoqXG4gKiBJbnN0YWxscyB0aGUgZ2l2ZW4gLmFwa3MgcGFja2FnZSBpbnRvIHRoZSBkZXZpY2UgdW5kZXIgdGVzdFxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBhcGtzIC0gVGhlIGZ1bGwgcGF0aCB0byB0aGUgLmFwa3MgZmlsZVxuICogQHBhcmFtIHs/SW5zdGFsbEFwa3NPcHRpb25zfSBvcHRpb25zIC0gSW5zdGFsbGF0aW9uIG9wdGlvbnNcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgLmFwa3MgYnVuZGxlIGNhbm5vdCBiZSBpbnN0YWxsZWRcbiAqL1xuYXBrc1V0aWxzTWV0aG9kcy5pbnN0YWxsQXBrcyA9IGFzeW5jIGZ1bmN0aW9uIGluc3RhbGxBcGtzIChhcGtzLCBvcHRpb25zID0ge30pIHtcbiAgb3B0aW9ucyA9IF8uY2xvbmVEZWVwKG9wdGlvbnMpO1xuICBfLmRlZmF1bHRzKG9wdGlvbnMsIHtcbiAgICB0aW1lb3V0OiB0aGlzLmFkYkV4ZWNUaW1lb3V0ID09PSBERUZBVUxUX0FEQl9FWEVDX1RJTUVPVVQgPyBBUEtTX0lOU1RBTExfVElNRU9VVCA6IHRoaXMuYWRiRXhlY1RpbWVvdXQsXG4gICAgdGltZW91dENhcE5hbWU6ICdhbmRyb2lkSW5zdGFsbFRpbWVvdXQnLFxuICB9KTtcbiAgT2JqZWN0LmFzc2lnbihvcHRpb25zLCB7cmVwbGFjZTogdHJ1ZX0pO1xuXG4gIGNvbnN0IHRtcFJvb3QgPSBhd2FpdCB0ZW1wRGlyLm9wZW5EaXIoKTtcbiAgdHJ5IHtcbiAgICBjb25zdCBzcGVjUGF0aCA9IGF3YWl0IHRoaXMuZ2V0RGV2aWNlU3BlYyhwYXRoLnJlc29sdmUodG1wUm9vdCwgJ2RldmljZVNwZWMuanNvbicpKTtcbiAgICBjb25zdCBhcmdzID0gW1xuICAgICAgJ2V4dHJhY3QtYXBrcycsXG4gICAgICAnLS1hcGtzJywgYXBrcyxcbiAgICAgICctLW91dHB1dC1kaXInLCB0bXBSb290LFxuICAgICAgJy0tZGV2aWNlLXNwZWMnLCBzcGVjUGF0aCxcbiAgICBdO1xuICAgIGxvZy5kZWJ1ZyhgRXh0cmFjdGluZyB0aGUgYXBrIGZpbGVzIGZyb20gJyR7YXBrc30nYCk7XG4gICAgYXdhaXQgdGhpcy5leGVjQnVuZGxldG9vbChhcmdzLCBgQ2Fubm90IGV4dHJhY3QgdGhlIGFwcGxpY2F0aW9uIGJ1bmRsZSBhdCAnJHthcGtzfSdgKTtcbiAgICBjb25zdCBpbnN0YWxsQXJncyA9IGJ1aWxkSW5zdGFsbEFyZ3MoYXdhaXQgdGhpcy5nZXRBcGlMZXZlbCgpLCBvcHRpb25zKTtcbiAgICBjb25zdCBhcGtQYXRoc1RvSW5zdGFsbCA9IChhd2FpdCBmcy5yZWFkZGlyKHRtcFJvb3QpKVxuICAgICAgLmZpbHRlcigobmFtZSkgPT4gbmFtZS5lbmRzV2l0aChBUEtfRVhURU5TSU9OKSlcbiAgICAgIC5tYXAoKG5hbWUpID0+IHBhdGgucmVzb2x2ZSh0bXBSb290LCBuYW1lKSk7XG4gICAgbG9nLmRlYnVnKCdHb3QgdGhlIGZvbGxvd2luZyBhcGsgZmlsZXMgdG8gaW5zdGFsbDogJyArXG4gICAgICBKU09OLnN0cmluZ2lmeShhcGtQYXRoc1RvSW5zdGFsbC5tYXAoKHgpID0+IHBhdGguYmFzZW5hbWUoeCkpKSk7XG4gICAgY29uc3Qgb3V0cHV0ID0gYXdhaXQgdGhpcy5hZGJFeGVjKFsnaW5zdGFsbC1tdWx0aXBsZScsIC4uLmluc3RhbGxBcmdzLCAuLi5hcGtQYXRoc1RvSW5zdGFsbF0sIHtcbiAgICAgIHRpbWVvdXQ6IG9wdGlvbnMudGltZW91dCxcbiAgICAgIHRpbWVvdXRDYXBOYW1lOiBvcHRpb25zLnRpbWVvdXRDYXBOYW1lLFxuICAgIH0pO1xuICAgIGNvbnN0IHRydW5jYXRlZE91dHB1dCA9ICghXy5pc1N0cmluZyhvdXRwdXQpIHx8IG91dHB1dC5sZW5ndGggPD0gMzAwKSA/XG4gICAgICBvdXRwdXQgOiBgJHtvdXRwdXQuc3Vic3RyKDAsIDE1MCl9Li4uJHtvdXRwdXQuc3Vic3RyKG91dHB1dC5sZW5ndGggLSAxNTApfWA7XG4gICAgbG9nLmRlYnVnKGBJbnN0YWxsIGNvbW1hbmQgc3Rkb3V0OiAke3RydW5jYXRlZE91dHB1dH1gKTtcbiAgICBpZiAoXy5pbmNsdWRlcyhvdXRwdXQsICdJTlNUQUxMX0ZBSUxFRCcpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3Iob3V0cHV0KTtcbiAgICB9XG4gIH0gZmluYWxseSB7XG4gICAgYXdhaXQgZnMucmltcmFmKHRtcFJvb3QpO1xuICB9XG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIGFuZCByZXR1cm5zIHRoZSBmdWxsIHBhdGggdG8gdGhlIG1hc3RlciAuYXBrIGZpbGUgaW5zaWRlIHRoZSBidW5kbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwa3MgLSBUaGUgZnVsbCBwYXRoIHRvIHRoZSAuYXBrcyBmaWxlXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZnVsbCBwYXRoIHRvIHRoZSBtYXN0ZXIgYnVuZGxlIC5hcGtcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSB3YXMgYW4gZXJyb3Igd2hpbGUgZXh0cmFjdGluZy9maW5kaW5nIHRoZSBmaWxlXG4gKi9cbmFwa3NVdGlsc01ldGhvZHMuZXh0cmFjdEJhc2VBcGsgPSBhc3luYyBmdW5jdGlvbiBleHRyYWN0QmFzZUFwayAoYXBrcykge1xuICByZXR1cm4gYXdhaXQgZXh0cmFjdEZyb21BcGtzKGFwa3MsIFsnc3BsaXRzJywgQkFTRV9BUEtdKTtcbn07XG5cbi8qKlxuICogRXh0cmFjdHMgYW5kIHJldHVybnMgdGhlIGZ1bGwgcGF0aCB0byB0aGUgLmFwaywgd2hpY2ggY29udGFpbnMgdGhlIGNvcnJlc3BvbmRpbmdcbiAqIHJlc291cmNlcyBmb3IgdGhlIGdpdmVuIGxhbmd1YWdlIGluIHRoZSAuYXBrcyBidW5kbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwa3MgLSBUaGUgZnVsbCBwYXRoIHRvIHRoZSAuYXBrcyBmaWxlXG4gKiBAcGFyYW0gez9zdHJpbmd9IGxhbmd1YWdlIC0gVGhlIGxhbmd1YWdlIGFiYnJldmlhdGlvbi4gVGhlIGRlZmF1bHQgbGFuZ3VhZ2UgaXNcbiAqIGdvaW5nIHRvIGJlIHNlbGVjdGVkIGlmIGl0IGlzIG5vdCBzZXQuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZnVsbCBwYXRoIHRvIHRoZSBjb3JyZXNwb25kaW5nIGxhbmd1YWdlIC5hcGsgb3IgdGhlIG1hc3RlciAuYXBrXG4gKiBpZiBsYW5ndWFnZSBzcGxpdCBpcyBub3QgZW5hYmxlZCBmb3IgdGhlIGJ1bmRsZS5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSB3YXMgYW4gZXJyb3Igd2hpbGUgZXh0cmFjdGluZy9maW5kaW5nIHRoZSBmaWxlXG4gKi9cbmFwa3NVdGlsc01ldGhvZHMuZXh0cmFjdExhbmd1YWdlQXBrID0gYXN5bmMgZnVuY3Rpb24gZXh0cmFjdExhbmd1YWdlQXBrIChhcGtzLCBsYW5ndWFnZSA9IG51bGwpIHtcbiAgaWYgKGxhbmd1YWdlKSB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBleHRyYWN0RnJvbUFwa3MoYXBrcywgWydzcGxpdHMnLCBMQU5HVUFHRV9BUEsobGFuZ3VhZ2UpXSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgbG9nLmRlYnVnKGUubWVzc2FnZSk7XG4gICAgICBsb2cuaW5mbyhgQXNzdW1pbmcgdGhhdCBzcGxpdHRpbmcgYnkgbGFuZ3VhZ2UgaXMgbm90IGVuYWJsZWQgZm9yIHRoZSAnJHthcGtzfScgYnVuZGxlIGAgK1xuICAgICAgICBgYW5kIHJldHVybmluZyB0aGUgbWFpbiBhcGsgaW5zdGVhZGApO1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuZXh0cmFjdEJhc2VBcGsoYXBrcyk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgZGVmYXVsdExhbmd1YWdlcyA9IFsnZW4nLCAnZW5fdXMnXTtcbiAgZm9yIChjb25zdCBsYW5nIG9mIGRlZmF1bHRMYW5ndWFnZXMpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IGV4dHJhY3RGcm9tQXBrcyhhcGtzLCBbJ3NwbGl0cycsIExBTkdVQUdFX0FQSyhsYW5nKV0pO1xuICAgIH0gY2F0Y2ggKGlnbikge31cbiAgfVxuXG4gIGxvZy5pbmZvKGBDYW5ub3QgZmluZCBhbnkgc3BsaXQgYXBrIGZvciB0aGUgZGVmYXVsdCBsYW5ndWFnZXMgJHtKU09OLnN0cmluZ2lmeShkZWZhdWx0TGFuZ3VhZ2VzKX0uIGAgK1xuICAgIGBSZXR1cm5pbmcgdGhlIG1haW4gYXBrIGluc3RlYWQuYCk7XG4gIHJldHVybiBhd2FpdCB0aGlzLmV4dHJhY3RCYXNlQXBrKGFwa3MpO1xufTtcblxuYXBrc1V0aWxzTWV0aG9kcy5pc1Rlc3RQYWNrYWdlT25seUVycm9yID0gZnVuY3Rpb24gKG91dHB1dCkge1xuICByZXR1cm4gL1xcW0lOU1RBTExfRkFJTEVEX1RFU1RfT05MWVxcXS8udGVzdChvdXRwdXQpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgYXBrc1V0aWxzTWV0aG9kcztcbiJdLCJmaWxlIjoibGliL3Rvb2xzL2Fwa3MtdXRpbHMuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4ifQ==