settings-client-commands.js 43.8 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 _logger = _interopRequireDefault(require("../logger.js"));

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

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

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

var _asyncbox = require("asyncbox");

var _utf = require("utf7");

const SETTINGS_HELPER_ID = 'io.appium.settings';
const SETTINGS_HELPER_MAIN_ACTIVITY = '.Settings';
const WIFI_CONNECTION_SETTING_RECEIVER = `${SETTINGS_HELPER_ID}/.receivers.WiFiConnectionSettingReceiver`;
const WIFI_CONNECTION_SETTING_ACTION = `${SETTINGS_HELPER_ID}.wifi`;
const DATA_CONNECTION_SETTING_RECEIVER = `${SETTINGS_HELPER_ID}/.receivers.DataConnectionSettingReceiver`;
const DATA_CONNECTION_SETTING_ACTION = `${SETTINGS_HELPER_ID}.data_connection`;
const ANIMATION_SETTING_RECEIVER = `${SETTINGS_HELPER_ID}/.receivers.AnimationSettingReceiver`;
const ANIMATION_SETTING_ACTION = `${SETTINGS_HELPER_ID}.animation`;
const LOCALE_SETTING_RECEIVER = `${SETTINGS_HELPER_ID}/.receivers.LocaleSettingReceiver`;
const LOCALE_SETTING_ACTION = `${SETTINGS_HELPER_ID}.locale`;
const LOCATION_SERVICE = `${SETTINGS_HELPER_ID}/.LocationService`;
const LOCATION_RECEIVER = `${SETTINGS_HELPER_ID}/.receivers.LocationInfoReceiver`;
const LOCATION_RETRIEVAL_ACTION = `${SETTINGS_HELPER_ID}.location`;
const CLIPBOARD_RECEIVER = `${SETTINGS_HELPER_ID}/.receivers.ClipboardReceiver`;
const CLIPBOARD_RETRIEVAL_ACTION = `${SETTINGS_HELPER_ID}.clipboard.get`;
const NOTIFICATIONS_RETRIEVAL_ACTION = `${SETTINGS_HELPER_ID}.notifications`;
const SMS_LIST_RECEIVER = `${SETTINGS_HELPER_ID}/.receivers.SmsReader`;
const SMS_LIST_RETRIEVAL_ACTION = `${SETTINGS_HELPER_ID}.sms.read`;
const APPIUM_IME = `${SETTINGS_HELPER_ID}/.AppiumIME`;
const UNICODE_IME = `${SETTINGS_HELPER_ID}/.UnicodeIME`;
const commands = {};

commands.requireRunningSettingsApp = async function requireRunningSettingsApp(opts = {}) {
  if (await this.processExists(SETTINGS_HELPER_ID)) {
    return this;
  }

  _logger.default.debug('Starting Appium Settings app');

  const {
    timeout = 5000
  } = opts;
  await this.startApp({
    pkg: SETTINGS_HELPER_ID,
    activity: SETTINGS_HELPER_MAIN_ACTIVITY,
    action: 'android.intent.action.MAIN',
    category: 'android.intent.category.LAUNCHER',
    stopApp: false,
    waitForLaunch: false
  });

  try {
    await (0, _asyncbox.waitForCondition)(async () => await this.processExists(SETTINGS_HELPER_ID), {
      waitMs: timeout,
      intervalMs: 300
    });
    return this;
  } catch (err) {
    throw new Error(`Appium Settings app is not running after ${timeout}ms`);
  }
};

commands.setWifiState = async function setWifiState(on, isEmulator = false) {
  if (isEmulator) {
    await this.shell(['svc', 'wifi', on ? 'enable' : 'disable'], {
      privileged: (await this.getApiLevel()) < 26
    });
  } else {
    await this.shell(['am', 'broadcast', '-a', WIFI_CONNECTION_SETTING_ACTION, '-n', WIFI_CONNECTION_SETTING_RECEIVER, '--es', 'setstatus', on ? 'enable' : 'disable']);
  }
};

commands.setDataState = async function setDataState(on, isEmulator = false) {
  if (isEmulator) {
    await this.shell(['svc', 'data', on ? 'enable' : 'disable'], {
      privileged: (await this.getApiLevel()) < 26
    });
  } else {
    await this.shell(['am', 'broadcast', '-a', DATA_CONNECTION_SETTING_ACTION, '-n', DATA_CONNECTION_SETTING_RECEIVER, '--es', 'setstatus', on ? 'enable' : 'disable']);
  }
};

commands.setAnimationState = async function setAnimationState(on) {
  await this.shell(['am', 'broadcast', '-a', ANIMATION_SETTING_ACTION, '-n', ANIMATION_SETTING_RECEIVER, '--es', 'setstatus', on ? 'enable' : 'disable']);
};

commands.setDeviceSysLocaleViaSettingApp = async function setDeviceSysLocaleViaSettingApp(language, country, script = null) {
  const params = ['am', 'broadcast', '-a', LOCALE_SETTING_ACTION, '-n', LOCALE_SETTING_RECEIVER, '--es', 'lang', language.toLowerCase(), '--es', 'country', country.toUpperCase()];

  if (script) {
    params.push('--es', 'script', script);
  }

  await this.shell(params);
};

commands.setGeoLocation = async function setGeoLocation(location, isEmulator = false) {
  const formatLocationValue = (valueName, isRequired = true) => {
    if (!_appiumSupport.util.hasValue(location[valueName])) {
      if (isRequired) {
        throw new Error(`${valueName} must be provided`);
      }

      return null;
    }

    const floatValue = parseFloat(location[valueName]);

    if (!isNaN(floatValue)) {
      return `${_lodash.default.ceil(floatValue, 5)}`;
    }

    if (isRequired) {
      throw new Error(`${valueName} is expected to be a valid float number. ` + `'${location[valueName]}' is given instead`);
    }

    return null;
  };

  const longitude = formatLocationValue('longitude');
  const latitude = formatLocationValue('latitude');
  const altitude = formatLocationValue('altitude', false);

  if (isEmulator) {
    await this.resetTelnetAuthToken();
    await this.adbExec(['emu', 'geo', 'fix', longitude, latitude]);
    await this.adbExec(['emu', 'geo', 'fix', longitude.replace('.', ','), latitude.replace('.', ',')]);
  } else {
    const args = ['am', 'startservice', '-e', 'longitude', longitude, '-e', 'latitude', latitude];

    if (_appiumSupport.util.hasValue(altitude)) {
      args.push('-e', 'altitude', altitude);
    }

    args.push(LOCATION_SERVICE);
    await this.shell(args);
  }
};

commands.getGeoLocation = async function getGeoLocation() {
  let output;

  try {
    output = await this.shell(['am', 'broadcast', '-n', LOCATION_RECEIVER, '-a', LOCATION_RETRIEVAL_ACTION]);
  } catch (err) {
    throw new Error(`Cannot retrieve the current geo coordinates from the device. ` + `Make sure the Appium Settings application is up to date and has location permissions. Also the location ` + `services must be enabled on the device. Original error: ${err.message}`);
  }

  const match = /data="(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)"/.exec(output);

  if (!match) {
    throw new Error(`Cannot parse the actual location values from the command output: ${output}`);
  }

  const location = {
    latitude: match[1],
    longitude: match[2],
    altitude: match[3]
  };

  _logger.default.debug(`Got geo coordinates: ${JSON.stringify(location)}`);

  return location;
};

commands.performEditorAction = async function performEditorAction(action) {
  _logger.default.debug(`Performing editor action: ${action}`);

  await this.runInImeContext(APPIUM_IME, async () => await this.shell(['input', 'text', `/${action}/`]));
};

commands.getClipboard = async function getClipboard() {
  _logger.default.debug('Getting the clipboard content');

  const retrieveClipboard = async () => await this.shell(['am', 'broadcast', '-n', CLIPBOARD_RECEIVER, '-a', CLIPBOARD_RETRIEVAL_ACTION]);

  let output;

  try {
    output = (await this.getApiLevel()) >= 29 ? await this.runInImeContext(APPIUM_IME, retrieveClipboard) : await retrieveClipboard();
  } catch (err) {
    throw new Error(`Cannot retrieve the current clipboard content from the device. ` + `Make sure the Appium Settings application is up to date. ` + `Original error: ${err.message}`);
  }

  const match = /data="([^"]*)"/.exec(output);

  if (!match) {
    throw new Error(`Cannot parse the actual cliboard content from the command output: ${output}`);
  }

  return _lodash.default.trim(match[1]);
};

commands.getNotifications = async function getNotifications() {
  _logger.default.debug('Retrieving notifications');

  await this.requireRunningSettingsApp();
  let output;

  try {
    output = await this.shell(['am', 'broadcast', '-a', NOTIFICATIONS_RETRIEVAL_ACTION]);
  } catch (err) {
    throw new Error(`Cannot retrieve notifications from the device. ` + `Make sure the Appium Settings application is installed and is up to date. ` + `Original error: ${err.message}`);
  }

  return (0, _helpers.parseJsonData)(output, 'notifications');
};

commands.getSmsList = async function getSmsList(opts = {}) {
  _logger.default.debug('Retrieving the recent SMS messages');

  const args = ['am', 'broadcast', '-n', SMS_LIST_RECEIVER, '-a', SMS_LIST_RETRIEVAL_ACTION];

  if (opts.max) {
    args.push('--es', 'max', opts.max);
  }

  let output;

  try {
    output = await this.shell(args);
  } catch (err) {
    throw new Error(`Cannot retrieve SMS list from the device. ` + `Make sure the Appium Settings application is installed and is up to date. ` + `Original error: ${err.message}`);
  }

  return (0, _helpers.parseJsonData)(output, 'SMS list');
};

commands.typeUnicode = async function typeUnicode(text) {
  if (_lodash.default.isNil(text)) {
    return false;
  }

  text = `${text}`;

  _logger.default.debug(`Typing ${_appiumSupport.util.pluralize('character', text.length, true)}`);

  if (!text) {
    return false;
  }

  await this.runInImeContext(UNICODE_IME, async () => await this.shell(['input', 'text', _utf.imap.encode(text)]));
  return true;
};

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


//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi90b29scy9zZXR0aW5ncy1jbGllbnQtY29tbWFuZHMuanMiXSwibmFtZXMiOlsiU0VUVElOR1NfSEVMUEVSX0lEIiwiU0VUVElOR1NfSEVMUEVSX01BSU5fQUNUSVZJVFkiLCJXSUZJX0NPTk5FQ1RJT05fU0VUVElOR19SRUNFSVZFUiIsIldJRklfQ09OTkVDVElPTl9TRVRUSU5HX0FDVElPTiIsIkRBVEFfQ09OTkVDVElPTl9TRVRUSU5HX1JFQ0VJVkVSIiwiREFUQV9DT05ORUNUSU9OX1NFVFRJTkdfQUNUSU9OIiwiQU5JTUFUSU9OX1NFVFRJTkdfUkVDRUlWRVIiLCJBTklNQVRJT05fU0VUVElOR19BQ1RJT04iLCJMT0NBTEVfU0VUVElOR19SRUNFSVZFUiIsIkxPQ0FMRV9TRVRUSU5HX0FDVElPTiIsIkxPQ0FUSU9OX1NFUlZJQ0UiLCJMT0NBVElPTl9SRUNFSVZFUiIsIkxPQ0FUSU9OX1JFVFJJRVZBTF9BQ1RJT04iLCJDTElQQk9BUkRfUkVDRUlWRVIiLCJDTElQQk9BUkRfUkVUUklFVkFMX0FDVElPTiIsIk5PVElGSUNBVElPTlNfUkVUUklFVkFMX0FDVElPTiIsIlNNU19MSVNUX1JFQ0VJVkVSIiwiU01TX0xJU1RfUkVUUklFVkFMX0FDVElPTiIsIkFQUElVTV9JTUUiLCJVTklDT0RFX0lNRSIsImNvbW1hbmRzIiwicmVxdWlyZVJ1bm5pbmdTZXR0aW5nc0FwcCIsIm9wdHMiLCJwcm9jZXNzRXhpc3RzIiwibG9nIiwiZGVidWciLCJ0aW1lb3V0Iiwic3RhcnRBcHAiLCJwa2ciLCJhY3Rpdml0eSIsImFjdGlvbiIsImNhdGVnb3J5Iiwic3RvcEFwcCIsIndhaXRGb3JMYXVuY2giLCJ3YWl0TXMiLCJpbnRlcnZhbE1zIiwiZXJyIiwiRXJyb3IiLCJzZXRXaWZpU3RhdGUiLCJvbiIsImlzRW11bGF0b3IiLCJzaGVsbCIsInByaXZpbGVnZWQiLCJnZXRBcGlMZXZlbCIsInNldERhdGFTdGF0ZSIsInNldEFuaW1hdGlvblN0YXRlIiwic2V0RGV2aWNlU3lzTG9jYWxlVmlhU2V0dGluZ0FwcCIsImxhbmd1YWdlIiwiY291bnRyeSIsInNjcmlwdCIsInBhcmFtcyIsInRvTG93ZXJDYXNlIiwidG9VcHBlckNhc2UiLCJwdXNoIiwic2V0R2VvTG9jYXRpb24iLCJsb2NhdGlvbiIsImZvcm1hdExvY2F0aW9uVmFsdWUiLCJ2YWx1ZU5hbWUiLCJpc1JlcXVpcmVkIiwidXRpbCIsImhhc1ZhbHVlIiwiZmxvYXRWYWx1ZSIsInBhcnNlRmxvYXQiLCJpc05hTiIsIl8iLCJjZWlsIiwibG9uZ2l0dWRlIiwibGF0aXR1ZGUiLCJhbHRpdHVkZSIsInJlc2V0VGVsbmV0QXV0aFRva2VuIiwiYWRiRXhlYyIsInJlcGxhY2UiLCJhcmdzIiwiZ2V0R2VvTG9jYXRpb24iLCJvdXRwdXQiLCJtZXNzYWdlIiwibWF0Y2giLCJleGVjIiwiSlNPTiIsInN0cmluZ2lmeSIsInBlcmZvcm1FZGl0b3JBY3Rpb24iLCJydW5JbkltZUNvbnRleHQiLCJnZXRDbGlwYm9hcmQiLCJyZXRyaWV2ZUNsaXBib2FyZCIsInRyaW0iLCJnZXROb3RpZmljYXRpb25zIiwiZ2V0U21zTGlzdCIsIm1heCIsInR5cGVVbmljb2RlIiwidGV4dCIsImlzTmlsIiwicGx1cmFsaXplIiwibGVuZ3RoIiwiaW1hcCIsImVuY29kZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFFQSxNQUFNQSxrQkFBa0IsR0FBRyxvQkFBM0I7QUFDQSxNQUFNQyw2QkFBNkIsR0FBRyxXQUF0QztBQUNBLE1BQU1DLGdDQUFnQyxHQUFJLEdBQUVGLGtCQUFtQiwyQ0FBL0Q7QUFDQSxNQUFNRyw4QkFBOEIsR0FBSSxHQUFFSCxrQkFBbUIsT0FBN0Q7QUFDQSxNQUFNSSxnQ0FBZ0MsR0FBSSxHQUFFSixrQkFBbUIsMkNBQS9EO0FBQ0EsTUFBTUssOEJBQThCLEdBQUksR0FBRUwsa0JBQW1CLGtCQUE3RDtBQUNBLE1BQU1NLDBCQUEwQixHQUFJLEdBQUVOLGtC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QyxJQUF6QyxDQUErQyxFQUFuRTs7QUFDQSxNQUFJLENBQUNILElBQUwsRUFBVztBQUNULFdBQU8sS0FBUDtBQUNEOztBQUNELFFBQU0sS0FBS1IsZUFBTCxDQUFxQjlELFdBQXJCLEVBQ0osWUFBWSxNQUFNLEtBQUtzQixLQUFMLENBQVcsQ0FBQyxPQUFELEVBQVUsTUFBVixFQUFrQm9ELFVBQUtDLE1BQUwsQ0FBWUwsSUFBWixDQUFsQixDQUFYLENBRGQsQ0FBTjtBQUVBLFNBQU8sSUFBUDtBQUNELENBYkQ7O2VBZWVyRSxRIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGxvZyBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgcGFyc2VKc29uRGF0YSB9IGZyb20gJy4uL2hlbHBlcnMuanMnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IHV0aWwgfSBmcm9tICdhcHBpdW0tc3VwcG9ydCc7XG5pbXBvcnQgeyB3YWl0Rm9yQ29uZGl0aW9uIH0gZnJvbSAnYXN5bmNib3gnO1xuaW1wb3J0IHsgaW1hcCB9IGZyb20gJ3V0ZjcnO1xuXG5jb25zdCBTRVRUSU5HU19IRUxQRVJfSUQgPSAnaW8uYXBwaXVtLnNldHRpbmdzJztcbmNvbnN0IFNFVFRJTkdTX0hFTFBFUl9NQUlOX0FDVElWSVRZID0gJy5TZXR0aW5ncyc7XG5jb25zdCBXSUZJX0NPTk5FQ1RJT05fU0VUVElOR19SRUNFSVZFUiA9IGAke1NFVFRJTkdTX0hFTFBFUl9JRH0vLnJlY2VpdmVycy5XaUZpQ29ubmVjdGlvblNldHRpbmdSZWNlaXZlcmA7XG5jb25zdCBXSUZJX0NPTk5FQ1RJT05fU0VUVElOR19BQ1RJT04gPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9LndpZmlgO1xuY29uc3QgREFUQV9DT05ORUNUSU9OX1NFVFRJTkdfUkVDRUlWRVIgPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9Ly5yZWNlaXZlcnMuRGF0YUNvbm5lY3Rpb25TZXR0aW5nUmVjZWl2ZXJgO1xuY29uc3QgREFUQV9DT05ORUNUSU9OX1NFVFRJTkdfQUNUSU9OID0gYCR7U0VUVElOR1NfSEVMUEVSX0lEfS5kYXRhX2Nvbm5lY3Rpb25gO1xuY29uc3QgQU5JTUFUSU9OX1NFVFRJTkdfUkVDRUlWRVIgPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9Ly5yZWNlaXZlcnMuQW5pbWF0aW9uU2V0dGluZ1JlY2VpdmVyYDtcbmNvbnN0IEFOSU1BVElPTl9TRVRUSU5HX0FDVElPTiA9IGAke1NFVFRJTkdTX0hFTFBFUl9JRH0uYW5pbWF0aW9uYDtcbmNvbnN0IExPQ0FMRV9TRVRUSU5HX1JFQ0VJVkVSID0gYCR7U0VUVElOR1NfSEVMUEVSX0lEfS8ucmVjZWl2ZXJzLkxvY2FsZVNldHRpbmdSZWNlaXZlcmA7XG5jb25zdCBMT0NBTEVfU0VUVElOR19BQ1RJT04gPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9LmxvY2FsZWA7XG5jb25zdCBMT0NBVElPTl9TRVJWSUNFID0gYCR7U0VUVElOR1NfSEVMUEVSX0lEfS8uTG9jYXRpb25TZXJ2aWNlYDtcbmNvbnN0IExPQ0FUSU9OX1JFQ0VJVkVSID0gYCR7U0VUVElOR1NfSEVMUEVSX0lEfS8ucmVjZWl2ZXJzLkxvY2F0aW9uSW5mb1JlY2VpdmVyYDtcbmNvbnN0IExPQ0FUSU9OX1JFVFJJRVZBTF9BQ1RJT04gPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9LmxvY2F0aW9uYDtcbmNvbnN0IENMSVBCT0FSRF9SRUNFSVZFUiA9IGAke1NFVFRJTkdTX0hFTFBFUl9JRH0vLnJlY2VpdmVycy5DbGlwYm9hcmRSZWNlaXZlcmA7XG5jb25zdCBDTElQQk9BUkRfUkVUUklFVkFMX0FDVElPTiA9IGAke1NFVFRJTkdTX0hFTFBFUl9JRH0uY2xpcGJvYXJkLmdldGA7XG5jb25zdCBOT1RJRklDQVRJT05TX1JFVFJJRVZBTF9BQ1RJT04gPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9Lm5vdGlmaWNhdGlvbnNgO1xuY29uc3QgU01TX0xJU1RfUkVDRUlWRVIgPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9Ly5yZWNlaXZlcnMuU21zUmVhZGVyYDtcbmNvbnN0IFNNU19MSVNUX1JFVFJJRVZBTF9BQ1RJT04gPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9LnNtcy5yZWFkYDtcbmNvbnN0IEFQUElVTV9JTUUgPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9Ly5BcHBpdW1JTUVgO1xuY29uc3QgVU5JQ09ERV9JTUUgPSBgJHtTRVRUSU5HU19IRUxQRVJfSUR9Ly5Vbmljb2RlSU1FYDtcblxuXG5jb25zdCBjb21tYW5kcyA9IHt9O1xuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IFNldHRpbmdzQXBwU3RhcnR1cE9wdGlvbnNcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSB0aW1lb3V0IFs1MDAwXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzXG4gKiB0byB3YWl0IHVudGlsIHRoZSBhcHAgaGFzIHN0YXJ0ZWRcbiAqL1xuXG4vKipcbiAqIEVuc3VyZXMgdGhhdCBBcHBpdW0gU2V0dGluZ3MgaGVscGVyIGFwcGxpY2F0aW9uIGlzIHJ1bm5pbmdcbiAqIGFuZCBzdGFydHMgaXQgaWYgbmVjZXNzYXJ5XG4gKlxuICogQHBhcmFtIHtTZXR0aW5nc0FwcFN0YXJ0dXBPcHRpb25zfSBvcHRzXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgQXBwaXVtIFNldHRpbmdzIGhhcyBmYWlsZWQgdG8gc3RhcnRcbiAqIEByZXR1cm5zIHtBREJ9IHNlbGYgaW5zdGFuY2UgZm9yIGNoYWluaW5nXG4gKi9cbmNvbW1hbmRzLnJlcXVpcmVSdW5uaW5nU2V0dGluZ3NBcHAgPSBhc3luYyBmdW5jdGlvbiByZXF1aXJlUnVubmluZ1NldHRpbmdzQXBwIChvcHRzID0ge30pIHtcbiAgaWYgKGF3YWl0IHRoaXMucHJvY2Vzc0V4aXN0cyhTRVRUSU5HU19IRUxQRVJfSUQpKSB7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICBsb2cuZGVidWcoJ1N0YXJ0aW5nIEFwcGl1bSBTZXR0aW5ncyBhcHAnKTtcbiAgY29uc3Qge1xuICAgIHRpbWVvdXQgPSA1MDAwLFxuICB9ID0gb3B0cztcbiAgYXdhaXQgdGhpcy5zdGFydEFwcCh7XG4gICAgcGtnOiBTRVRUSU5HU19IRUxQRVJfSUQsXG4gICAgYWN0aXZpdHk6IFNFVFRJTkdTX0hFTFBFUl9NQUlOX0FDVElWSVRZLFxuICAgIGFjdGlvbjogJ2FuZHJvaWQuaW50ZW50LmFjdGlvbi5NQUlOJyxcbiAgICBjYXRlZ29yeTogJ2FuZHJvaWQuaW50ZW50LmNhdGVnb3J5LkxBVU5DSEVSJyxcbiAgICBzdG9wQXBwOiBmYWxzZSxcbiAgICB3YWl0Rm9yTGF1bmNoOiBmYWxzZSxcbiAgfSk7XG4gIHRyeSB7XG4gICAgYXdhaXQgd2FpdEZvckNvbmRpdGlvbihhc3luYyAoKSA9PiBhd2FpdCB0aGlzLnByb2Nlc3NFeGlzdHMoU0VUVElOR1NfSEVMUEVSX0lEKSwge1xuICAgICAgd2FpdE1zOiB0aW1lb3V0LFxuICAgICAgaW50ZXJ2YWxNczogMzAwLFxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEFwcGl1bSBTZXR0aW5ncyBhcHAgaXMgbm90IHJ1bm5pbmcgYWZ0ZXIgJHt0aW1lb3V0fW1zYCk7XG4gIH1cbn07XG5cbi8qKlxuICogQ2hhbmdlIHRoZSBzdGF0ZSBvZiBXaUZpIG9uIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcGFyYW0ge2Jvb2xlYW59IG9uIC0gVHJ1ZSB0byBlbmFibGUgYW5kIGZhbHNlIHRvIGRpc2FibGUgaXQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzRW11bGF0b3IgW2ZhbHNlXSAtIFNldCBpdCB0byB0cnVlIGlmIHRoZSBkZXZpY2UgdW5kZXIgdGVzdFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcyBhbiBlbXVsYXRvciByYXRoZXIgdGhhbiBhIHJlYWwgZGV2aWNlLlxuICovXG5jb21tYW5kcy5zZXRXaWZpU3RhdGUgPSBhc3luYyBmdW5jdGlvbiBzZXRXaWZpU3RhdGUgKG9uLCBpc0VtdWxhdG9yID0gZmFsc2UpIHtcbiAgaWYgKGlzRW11bGF0b3IpIHtcbiAgICAvLyBUaGUgc3ZjIGNvbW1hbmQgZG9lcyBub3QgcmVxdWlyZSB0byBiZSByb290IHNpbmNlIEFQSSAyNlxuICAgIGF3YWl0IHRoaXMuc2hlbGwoWydzdmMnLCAnd2lmaScsIG9uID8gJ2VuYWJsZScgOiAnZGlzYWJsZSddLCB7XG4gICAgICBwcml2aWxlZ2VkOiBhd2FpdCB0aGlzLmdldEFwaUxldmVsKCkgPCAyNixcbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICBhd2FpdCB0aGlzLnNoZWxsKFtcbiAgICAgICdhbScsICdicm9hZGNhc3QnLFxuICAgICAgJy1hJywgV0lGSV9DT05ORUNUSU9OX1NFVFRJTkdfQUNUSU9OLFxuICAgICAgJy1uJywgV0lGSV9DT05ORUNUSU9OX1NFVFRJTkdfUkVDRUlWRVIsXG4gICAgICAnLS1lcycsICdzZXRzdGF0dXMnLCBvbiA/ICdlbmFibGUnIDogJ2Rpc2FibGUnXG4gICAgXSk7XG4gIH1cbn07XG5cbi8qKlxuICogQ2hhbmdlIHRoZSBzdGF0ZSBvZiBEYXRhIHRyYW5zZmVyIG9uIHRoZSBkZXZpY2UgdW5kZXIgdGVzdC5cbiAqXG4gKiBAcGFyYW0ge2Jvb2xlYW59IG9uIC0gVHJ1ZSB0byBlbmFibGUgYW5kIGZhbHNlIHRvIGRpc2FibGUgaXQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzRW11bGF0b3IgW2ZhbHNlXSAtIFNldCBpdCB0byB0cnVlIGlmIHRoZSBkZXZpY2UgdW5kZXIgdGVzdFxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcyBhbiBlbXVsYXRvciByYXRoZXIgdGhhbiBhIHJlYWwgZGV2aWNlLlxuICovXG5jb21tYW5kcy5zZXREYXRhU3RhdGUgPSBhc3luYyBmdW5jdGlvbiBzZXREYXRhU3RhdGUgKG9uLCBpc0VtdWxhdG9yID0gZmFsc2UpIHtcbiAgaWYgKGlzRW11bGF0b3IpIHtcbiAgICAvLyBUaGUgc3ZjIGNvbW1hbmQgZG9lcyBub3QgcmVxdWlyZSB0byBiZSByb290IHNpbmNlIEFQSSAyNlxuICAgIGF3YWl0IHRoaXMuc2hlbGwoWydzdmMnLCAnZGF0YScsIG9uID8gJ2VuYWJsZScgOiAnZGlzYWJsZSddLCB7XG4gICAgICBwcml2aWxlZ2VkOiBhd2FpdCB0aGlzLmdldEFwaUxldmVsKCkgPCAyNixcbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICBhd2FpdCB0aGlzLnNoZWxsKFtcbiAgICAgICdhbScsICdicm9hZGNhc3QnLFxuICAgICAgJy1hJywgREFUQV9DT05ORUNUSU9OX1NFVFRJTkdfQUNUSU9OLFxuICAgICAgJy1uJywgREFUQV9DT05ORUNUSU9OX1NFVFRJTkdfUkVDRUlWRVIsXG4gICAgICAnLS1lcycsICdzZXRzdGF0dXMnLCBvbiA/ICdlbmFibGUnIDogJ2Rpc2FibGUnXG4gICAgXSk7XG4gIH1cbn07XG5cbi8qKlxuICogQ2hhbmdlIHRoZSBzdGF0ZSBvZiBhbmltYXRpb24gb24gdGhlIGRldmljZSB1bmRlciB0ZXN0LlxuICogQW5pbWF0aW9uIG9uIHRoZSBkZXZpY2UgaXMgY29udHJvbGxlZCBieSB0aGUgZm9sbG93aW5nIGdsb2JhbCBwcm9wZXJ0aWVzOlxuICogW0FOSU1BVE9SX0RVUkFUSU9OX1NDQUxFXXtAbGluayBodHRwczovL2RldmVsb3Blci5hbmRyb2lkLmNvbS9yZWZlcmVuY2UvYW5kcm9pZC9wcm92aWRlci9TZXR0aW5ncy5HbG9iYWwuaHRtbCNBTklNQVRPUl9EVVJBVElPTl9TQ0FMRX0sXG4gKiBbVFJBTlNJVElPTl9BTklNQVRJT05fU0NBTEVde0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLmFuZHJvaWQuY29tL3JlZmVyZW5jZS9hbmRyb2lkL3Byb3ZpZGVyL1NldHRpbmdzLkdsb2JhbC5odG1sI1RSQU5TSVRJT05fQU5JTUFUSU9OX1NDQUxFfSxcbiAqIFtXSU5ET1dfQU5JTUFUSU9OX1NDQUxFXXtAbGluayBodHRwczovL2RldmVsb3Blci5hbmRyb2lkLmNvbS9yZWZlcmVuY2UvYW5kcm9pZC9wcm92aWRlci9TZXR0aW5ncy5HbG9iYWwuaHRtbCNXSU5ET1dfQU5JTUFUSU9OX1NDQUxFfS5cbiAqIFRoaXMgbWV0aG9kIHNldHMgYWxsIHRoaXMgcHJvcGVydGllcyB0byAwLjAgdG8gZGlzYWJsZSAoMS4wIHRvIGVuYWJsZSkgYW5pbWF0aW9uLlxuICpcbiAqIFR1cm5pbmcgb2ZmIGFuaW1hdGlvbiBtaWdodCBiZSB1c2VmdWwgdG8gaW1wcm92ZSBzdGFiaWxpdHlcbiAqIGFuZCByZWR1Y2UgdGVzdHMgZXhlY3V0aW9uIHRpbWUuXG4gKlxuICogQHBhcmFtIHtib29sZWFufSBvbiAtIFRydWUgdG8gZW5hYmxlIGFuZCBmYWxzZSB0byBkaXNhYmxlIGl0LlxuICovXG5jb21tYW5kcy5zZXRBbmltYXRpb25TdGF0ZSA9IGFzeW5jIGZ1bmN0aW9uIHNldEFuaW1hdGlvblN0YXRlIChvbikge1xuICBhd2FpdCB0aGlzLnNoZWxsKFtcbiAgICAnYW0nLCAnYnJvYWRjYXN0JyxcbiAgICAnLWEnLCBBTklNQVRJT05fU0VUVElOR19BQ1RJT04sXG4gICAgJy1uJywgQU5JTUFUSU9OX1NFVFRJTkdfUkVDRUlWRVIsXG4gICAgJy0tZXMnLCAnc2V0c3RhdHVzJywgb24gPyAnZW5hYmxlJyA6ICdkaXNhYmxlJ1xuICBdKTtcbn07XG5cbi8qKlxuICogQ2hhbmdlIHRoZSBsb2NhbGUgb24gdGhlIGRldmljZSB1bmRlciB0ZXN0LiBEb24ndCBuZWVkIHRvIHJlYm9vdCB0aGUgZGV2aWNlIGFmdGVyIGNoYW5naW5nIHRoZSBsb2NhbGUuXG4gKiBUaGlzIG1ldGhvZCBzZXRzIGFuIGFyYml0cmFyeSBsb2NhbGUgZm9sbG93aW5nOlxuICogICBodHRwczovL2RldmVsb3Blci5hbmRyb2lkLmNvbS9yZWZlcmVuY2UvamF2YS91dGlsL0xvY2FsZS5odG1sXG4gKiAgIGh0dHBzOi8vZGV2ZWxvcGVyLmFuZHJvaWQuY29tL3JlZmVyZW5jZS9qYXZhL3V0aWwvTG9jYWxlLmh0bWwjTG9jYWxlKGphdmEubGFuZy5TdHJpbmcsJTIwamF2YS5sYW5nLlN0cmluZylcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbGFuZ3VhZ2UgLSBMYW5ndWFnZS4gZS5nLiBlbiwgamFcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3VudHJ5IC0gQ291bnRyeS4gZS5nLiBVUywgSlBcbiAqIEBwYXJhbSB7P3N0cmluZ30gc2NyaXB0IC0gU2NyaXB0LiBlLmcuIEhhbnMgaW4gYHpoLUhhbnMtQ05gXG4gKi9cbmNvbW1hbmRzLnNldERldmljZVN5c0xvY2FsZVZpYVNldHRpbmdBcHAgPSBhc3luYyBmdW5jdGlvbiBzZXREZXZpY2VTeXNMb2NhbGVWaWFTZXR0aW5nQXBwIChsYW5ndWFnZSwgY291bnRyeSwgc2NyaXB0ID0gbnVsbCkge1xuICBjb25zdCBwYXJhbXMgPSBbXG4gICAgJ2FtJywgJ2Jyb2FkY2FzdCcsXG4gICAgJy1hJywgTE9DQUxFX1NFVFRJTkdfQUNUSU9OLFxuICAgICctbicsIExPQ0FMRV9TRVRUSU5HX1JFQ0VJVkVSLFxuICAgICctLWVzJywgJ2xhbmcnLCBsYW5ndWFnZS50b0xvd2VyQ2FzZSgpLFxuICAgICctLWVzJywgJ2NvdW50cnknLCBjb3VudHJ5LnRvVXBwZXJDYXNlKClcbiAgXTtcblxuICBpZiAoc2NyaXB0KSB7XG4gICAgcGFyYW1zLnB1c2goJy0tZXMnLCAnc2NyaXB0Jywgc2NyaXB0KTtcbiAgfVxuXG4gIGF3YWl0IHRoaXMuc2hlbGwocGFyYW1zKTtcbn07XG5cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBMb2NhdGlvblxuICogQHByb3BlcnR5IHtudW1iZXJ8c3RyaW5nfSBsb25naXR1ZGUgLSBWYWxpZCBsb25naXR1ZGUgdmFsdWUuXG4gKiBAcHJvcGVydHkge251bWJlcnxzdHJpbmd9IGxhdGl0dWRlIC0gVmFsaWQgbGF0aXR1ZGUgdmFsdWUuXG4gKiBAcHJvcGVydHkgez9udW1iZXJ8c3RyaW5nfSBhbHRpdHVkZSAtIFZhbGlkIGFsdGl0dWRlIHZhbHVlLlxuICovXG5cbi8qKlxuICogRW11bGF0ZSBnZW9sb2NhdGlvbiBjb29yZGluYXRlcyBvbiB0aGUgZGV2aWNlIHVuZGVyIHRlc3QuXG4gKlxuICogQHBhcmFtIHtMb2NhdGlvbn0gbG9jYXRpb24gLSBMb2NhdGlvbiBvYmplY3QuIFRoZSBgYWx0aXR1ZGVgIHZhbHVlIGlzIGlnbm9yZWRcbiAqIHdoaWxlIG1vY2tpbmcgdGhlIHBvc2l0aW9uLlxuICogQHBhcmFtIHtib29sZWFufSBpc0VtdWxhdG9yIFtmYWxzZV0gLSBTZXQgaXQgdG8gdHJ1ZSBpZiB0aGUgZGV2aWNlIHVuZGVyIHRlc3RcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMgYW4gZW11bGF0b3IgcmF0aGVyIHRoYW4gYSByZWFsIGRldmljZS5cbiAqL1xuY29tbWFuZHMuc2V0R2VvTG9jYXRpb24gPSBhc3luYyBmdW5jdGlvbiBzZXRHZW9Mb2NhdGlvbiAobG9jYXRpb24sIGlzRW11bGF0b3IgPSBmYWxzZSkge1xuICBjb25zdCBmb3JtYXRMb2NhdGlvblZhbHVlID0gKHZhbHVlTmFtZSwgaXNSZXF1aXJlZCA9IHRydWUpID0+IHtcbiAgICBpZiAoIXV0aWwuaGFzVmFsdWUobG9jYXRpb25bdmFsdWVOYW1lXSkpIHtcbiAgICAgIGlmIChpc1JlcXVpcmVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgJHt2YWx1ZU5hbWV9IG11c3QgYmUgcHJvdmlkZWRgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICBjb25zdCBmbG9hdFZhbHVlID0gcGFyc2VGbG9hdChsb2NhdGlvblt2YWx1ZU5hbWVdKTtcbiAgICBpZiAoIWlzTmFOKGZsb2F0VmFsdWUpKSB7XG4gICAgICByZXR1cm4gYCR7Xy5jZWlsKGZsb2F0VmFsdWUsIDUpfWA7XG4gICAgfVxuICAgIGlmIChpc1JlcXVpcmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCR7dmFsdWVOYW1lfSBpcyBleHBlY3RlZCB0byBiZSBhIHZhbGlkIGZsb2F0IG51bWJlci4gYCArXG4gICAgICAgIGAnJHtsb2NhdGlvblt2YWx1ZU5hbWVdfScgaXMgZ2l2ZW4gaW5zdGVhZGApO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfTtcbiAgY29uc3QgbG9uZ2l0dWRlID0gZm9ybWF0TG9jYXRpb25WYWx1ZSgnbG9uZ2l0dWRlJyk7XG4gIGNvbnN0IGxhdGl0dWRlID0gZm9ybWF0TG9jYXRpb25WYWx1ZSgnbGF0aXR1ZGUnKTtcbiAgY29uc3QgYWx0aXR1ZGUgPSBmb3JtYXRMb2NhdGlvblZhbHVlKCdhbHRpdHVkZScsIGZhbHNlKTtcbiAgaWYgKGlzRW11bGF0b3IpIHtcbiAgICBhd2FpdCB0aGlzLnJlc2V0VGVsbmV0QXV0aFRva2VuKCk7XG4gICAgYXdhaXQgdGhpcy5hZGJFeGVjKFsnZW11JywgJ2dlbycsICdmaXgnLCBsb25naXR1ZGUsIGxhdGl0dWRlXSk7XG4gICAgLy8gQSB3b3JrYXJvdW5kIGZvciBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL2FuZHJvaWQvaXNzdWVzL2RldGFpbD9pZD0yMDYxODBcbiAgICBhd2FpdCB0aGlzLmFkYkV4ZWMoWydlbXUnLCAnZ2VvJywgJ2ZpeCcsIGxvbmdpdHVkZS5yZXBsYWNlKCcuJywgJywnKSwgbGF0aXR1ZGUucmVwbGFjZSgnLicsICcsJyldKTtcbiAgfSBlbHNlIHtcbiAgICBjb25zdCBhcmdzID0gW1xuICAgICAgJ2FtJywgJ3N0YXJ0c2VydmljZScsXG4gICAgICAnLWUnLCAnbG9uZ2l0dWRlJywgbG9uZ2l0dWRlLFxuICAgICAgJy1lJywgJ2xhdGl0dWRlJywgbGF0aXR1ZGUsXG4gICAgXTtcbiAgICBpZiAodXRpbC5oYXNWYWx1ZShhbHRpdHVkZSkpIHtcbiAgICAgIGFyZ3MucHVzaCgnLWUnLCAnYWx0aXR1ZGUnLCBhbHRpdHVkZSk7XG4gICAgfVxuICAgIGFyZ3MucHVzaChMT0NBVElPTl9TRVJWSUNFKTtcbiAgICBhd2FpdCB0aGlzLnNoZWxsKGFyZ3MpO1xuICB9XG59O1xuXG4vKipcbiAqIEdldCB0aGUgY3VycmVudCBnZW8gbG9jYXRpb24gZnJvbSB0aGUgZGV2aWNlIHVuZGVyIHRlc3QuXG4gKlxuICogQHJldHVybnMge0xvY2F0aW9ufSBUaGUgY3VycmVudCBsb2NhdGlvblxuICogQHRocm93cyB7RXJyb3J9IElmIHRoZSBjdXJyZW50IGxvY2F0aW9uIGNhbm5vdCBiZSByZXRyaWV2ZWRcbiAqL1xuY29tbWFuZHMuZ2V0R2VvTG9jYXRpb24gPSBhc3luYyBmdW5jdGlvbiBnZXRHZW9Mb2NhdGlvbiAoKSB7XG4gIGxldCBvdXRwdXQ7XG4gIHRyeSB7XG4gICAgb3V0cHV0ID0gYXdhaXQgdGhpcy5zaGVsbChbXG4gICAgICAnYW0nLCAnYnJvYWRjYXN0JyxcbiAgICAgICctbicsIExPQ0FUSU9OX1JFQ0VJVkVSLFxuICAgICAgJy1hJywgTE9DQVRJT05fUkVUUklFVkFMX0FDVElPTixcbiAgICBdKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgcmV0cmlldmUgdGhlIGN1cnJlbnQgZ2VvIGNvb3JkaW5hdGVzIGZyb20gdGhlIGRldmljZS4gYCArXG4gICAgICBgTWFrZSBzdXJlIHRoZSBBcHBpdW0gU2V0dGluZ3MgYXBwbGljYXRpb24gaXMgdXAgdG8gZGF0ZSBhbmQgaGFzIGxvY2F0aW9uIHBlcm1pc3Npb25zLiBBbHNvIHRoZSBsb2NhdGlvbiBgICtcbiAgICAgIGBzZXJ2aWNlcyBtdXN0IGJlIGVuYWJsZWQgb24gdGhlIGRldmljZS4gT3JpZ2luYWwgZXJyb3I6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gIH1cblxuICBjb25zdCBtYXRjaCA9IC9kYXRhPVwiKC0/W1xcZC5dKylcXHMrKC0/W1xcZC5dKylcXHMrKC0/W1xcZC5dKylcIi8uZXhlYyhvdXRwdXQpO1xuICBpZiAoIW1hdGNoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgcGFyc2UgdGhlIGFjdHVhbCBsb2NhdGlvbiB2YWx1ZXMgZnJvbSB0aGUgY29tbWFuZCBvdXRwdXQ6ICR7b3V0cHV0fWApO1xuICB9XG4gIGNvbnN0IGxvY2F0aW9uID0ge1xuICAgIGxhdGl0dWRlOiBtYXRjaFsxXSxcbiAgICBsb25naXR1ZGU6IG1hdGNoWzJdLFxuICAgIGFsdGl0dWRlOiBtYXRjaFszXSxcbiAgfTtcbiAgbG9nLmRlYnVnKGBHb3QgZ2VvIGNvb3JkaW5hdGVzOiAke0pTT04uc3RyaW5naWZ5KGxvY2F0aW9uKX1gKTtcbiAgcmV0dXJuIGxvY2F0aW9uO1xufTtcblxuLyoqXG4gKiBQZXJmb3JtcyB0aGUgZ2l2ZW4gZWRpdG9yIGFjdGlvbiBvbiB0aGUgZm9jdXNlZCBpbnB1dCBmaWVsZC5cbiAqIFRoaXMgbWV0aG9kIHJlcXVpcmVzIEFwcGl1bSBTZXR0aW5ncyBoZWxwZXIgdG8gYmUgaW5zdGFsbGVkIG9uIHRoZSBkZXZpY2UuXG4gKiBObyBleGNlcHRpb24gaXMgdGhyb3duIGlmIHRoZXJlIHdhcyBhIGZhaWx1cmUgd2hpbGUgcGVyZm9ybWluZyB0aGUgYWN0aW9uLlxuICogWW91IG11c3QgaW52ZXN0aWdhdGUgdGhlIGxvZ2NhdCBvdXRwdXQgaWYgc29tZXRoaW5nIGRpZCBub3Qgd29yayBhcyBleHBlY3RlZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IGFjdGlvbiAtIEVpdGhlciBhY3Rpb24gY29kZSBvciBuYW1lLiBUaGUgZm9sbG93aW5nIGFjdGlvblxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyBhcmUgc3VwcG9ydGVkOiBgbm9ybWFsLCB1bnNwZWNpZmllZCwgbm9uZSxcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ28sIHNlYXJjaCwgc2VuZCwgbmV4dCwgZG9uZSwgcHJldmlvdXNgXG4gKi9cbmNvbW1hbmRzLnBlcmZvcm1FZGl0b3JBY3Rpb24gPSBhc3luYyBmdW5jdGlvbiBwZXJmb3JtRWRpdG9yQWN0aW9uIChhY3Rpb24pIHtcbiAgbG9nLmRlYnVnKGBQZXJmb3JtaW5nIGVkaXRvciBhY3Rpb246ICR7YWN0aW9ufWApO1xuICBhd2FpdCB0aGlzLnJ1bkluSW1lQ29udGV4dChBUFBJVU1fSU1FLFxuICAgIGFzeW5jICgpID0+IGF3YWl0IHRoaXMuc2hlbGwoWydpbnB1dCcsICd0ZXh0JywgYC8ke2FjdGlvbn0vYF0pKTtcbn07XG5cblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIHRleHQgY29udGVudCBvZiB0aGUgZGV2aWNlJ3MgY2xpcGJvYXJkLlxuICogVGhlIG1ldGhvZCB3b3JrcyBmb3IgQW5kcm9pZCBiZWxvdyBhbmQgYWJvdmUgMjkuXG4gKiBJdCB0ZW1vcmFyaWx5IGVuZm9yY2VzIHRoZSBJTUUgc2V0dGluZyBpbiBvcmRlciB0byB3b3JrYXJvdW5kXG4gKiBzZWN1cml0eSBsaW1pdGF0aW9ucyBpZiBuZWVkZWQuXG4gKiBUaGlzIG1ldGhvZCBvbmx5IHdvcmtzIGlmIEFwcGl1bSBTZXR0aW5ncyB2LiAyLjE1KyBpcyBpbnN0YWxsZWRcbiAqIG9uIHRoZSBkZXZpY2UgdW5kZXIgdGVzdFxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBhY3R1YWwgY29udGVudCBvZiB0aGUgbWFpbiBjbGlwYm9hcmQgYXNcbiAqIGJhc2U2NC1lbmNvZGVkIHN0cmluZyBvciBhbiBlbXB0eSBzdHJpbmcgaWYgdGhlIGNsaXBib2FyZCBpcyBlbXB0eVxuICogQHRocm93cyB7RXJyb3J9IElmIHRoZXJlIHdhcyBhIHByb2JsZW0gd2hpbGUgZ2V0dGluZyB0aGVcbiAqIGNsaXBib2FyZCBjb250YW50XG4gKi9cbmNvbW1hbmRzLmdldENsaXBib2FyZCA9IGFzeW5jIGZ1bmN0aW9uIGdldENsaXBib2FyZCAoKSB7XG4gIGxvZy5kZWJ1ZygnR2V0dGluZyB0aGUgY2xpcGJvYXJkIGNvbnRlbnQnKTtcbiAgY29uc3QgcmV0cmlldmVDbGlwYm9hcmQgPSBhc3luYyAoKSA9PiBhd2FpdCB0aGlzLnNoZWxsKFtcbiAgICAnYW0nLCAnYnJvYWRjYXN0JyxcbiAgICAnLW4nLCBDTElQQk9BUkRfUkVDRUlWRVIsXG4gICAgJy1hJywgQ0xJUEJPQVJEX1JFVFJJRVZBTF9BQ1RJT04sXG4gIF0pO1xuICBsZXQgb3V0cHV0O1xuICB0cnkge1xuICAgIG91dHB1dCA9IChhd2FpdCB0aGlzLmdldEFwaUxldmVsKCkgPj0gMjkpXG4gICAgICA/IChhd2FpdCB0aGlzLnJ1bkluSW1lQ29udGV4dChBUFBJVU1fSU1FLCByZXRyaWV2ZUNsaXBib2FyZCkpXG4gICAgICA6IChhd2FpdCByZXRyaWV2ZUNsaXBib2FyZCgpKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgcmV0cmlldmUgdGhlIGN1cnJlbnQgY2xpcGJvYXJkIGNvbnRlbnQgZnJvbSB0aGUgZGV2aWNlLiBgICtcbiAgICAgIGBNYWtlIHN1cmUgdGhlIEFwcGl1bSBTZXR0aW5ncyBhcHBsaWNhdGlvbiBpcyB1cCB0byBkYXRlLiBgICtcbiAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlcnIubWVzc2FnZX1gKTtcbiAgfVxuXG4gIGNvbnN0IG1hdGNoID0gL2RhdGE9XCIoW15cIl0qKVwiLy5leGVjKG91dHB1dCk7XG4gIGlmICghbWF0Y2gpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBwYXJzZSB0aGUgYWN0dWFsIGNsaWJvYXJkIGNvbnRlbnQgZnJvbSB0aGUgY29tbWFuZCBvdXRwdXQ6ICR7b3V0cHV0fWApO1xuICB9XG4gIHJldHVybiBfLnRyaW0obWF0Y2hbMV0pO1xufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgQW5kcm9pZCBub3RpZmljYXRpb25zIHZpYSBBcHBpdW0gU2V0dGluZ3MgaGVscGVyLlxuICogQXBwaXVtIFNldHRpbmdzIGFwcCBpdHNlbGYgbXVzdCBiZSAqbWFudWFsbHkqIGdyYW50ZWQgdG8gYWNjZXNzIG5vdGlmaWNhdGlvbnNcbiAqIHVuZGVyIGRldmljZSBTZXR0aW5ncyBpbiBvcmRlciB0byBtYWtlIHRoaXMgZmVhdHVyZSB3b3JraW5nLlxuICogQXBwaXVtIFNldHRpbmdzIGhlbHBlciBrZWVwcyBhbGwgdGhlIGFjdGl2ZSBub3RpZmljYXRpb25zIHBsdXNcbiAqIG5vdGlmaWNhdGlvbnMgdGhhdCBhcHBlYXJlZCB3aGlsZSBpdCB3YXMgcnVubmluZyBpbiB0aGUgaW50ZXJuYWwgYnVmZmVyLFxuICogYnV0IG5vIG1vcmUgdGhhbiAxMDAgaXRlbXMgYWx0b2dldGhlci4gTmV3bHkgYXBwZWFyZWQgbm90aWZpY2F0aW9uc1xuICogYXJlIGFsd2F5cyBhZGRlZCB0byB0aGUgaGVhZCBvZiB0aGUgbm90aWZpY2F0aW9ucyBhcnJheS5cbiAqIFRoZSBgaXNSZW1vdmVkYCBmbGFnIGlzIHNldCB0byBgdHJ1ZWAgZm9yIG5vdGlmaWNhdGlvbnMgdGhhdCBoYXZlIGJlZW4gcmVtb3ZlZC5cbiAqXG4gKiBTZWUgaHR0cHM6Ly9kZXZlbG9wZXIuYW5kcm9pZC5jb20vcmVmZXJlbmNlL2FuZHJvaWQvc2VydmljZS9ub3RpZmljYXRpb24vU3RhdHVzQmFyTm90aWZpY2F0aW9uXG4gKiBhbmQgaHR0cHM6Ly9kZXZlbG9wZXIuYW5kcm9pZC5jb20vcmVmZXJlbmNlL2FuZHJvaWQvYXBwL05vdGlmaWNhdGlvbi5odG1sXG4gKiBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBhdmFpbGFibGUgbm90aWZpY2F0aW9uIHByb3BlcnRpZXMgYW5kIHRoZWlyIHZhbHVlcy5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZXhhbXBsZSBvdXRwdXQgaXM6XG4gKiBgYGBqc29uXG4gKiB7XG4gKiAgIFwic3RhdHVzQmFyTm90aWZpY2F0aW9uc1wiOltcbiAqICAgICB7XG4gKiAgICAgICBcImlzR3JvdXBcIjpmYWxzZSxcbiAqICAgICAgIFwicGFja2FnZU5hbWVcIjpcImlvLmFwcGl1bS5zZXR0aW5nc1wiLFxuICogICAgICAgXCJpc0NsZWFyYWJsZVwiOmZhbHNlLFxuICogICAgICAgXCJpc09uZ29pbmdcIjp0cnVlLFxuICogICAgICAgXCJpZFwiOjEsXG4gKiAgICAgICBcInRhZ1wiOm51bGwsXG4gKiAgICAgICBcIm5vdGlmaWNhdGlvblwiOntcbiAqICAgICAgICAgXCJ0aXRsZVwiOm51bGwsXG4gKiAgICAgICAgIFwiYmlnVGl0bGVcIjpcIkFwcGl1bSBTZXR0aW5nc1wiLFxuICogICAgICAgICBcInRleHRcIjpudWxsLFxuICogICAgICAgICBcImJpZ1RleHRcIjpcIktlZXAgdGhpcyBzZXJ2aWNlIHJ1bm5pbmcsIHNvIEFwcGl1bSBmb3IgQW5kcm9pZCBjYW4gcHJvcGVybHkgaW50ZXJhY3Qgd2l0aCBzZXZlcmFsIHN5c3RlbSBBUElzXCIsXG4gKiAgICAgICAgIFwidGlja2VyVGV4dFwiOm51bGwsXG4gKiAgICAgICAgIFwic3ViVGV4dFwiOm51bGwsXG4gKiAgICAgICAgIFwiaW5mb1RleHRcIjpudWxsLFxuICogICAgICAgICBcInRlbXBsYXRlXCI6XCJhbmRyb2lkLmFwcC5Ob3RpZmljYXRpb24kQmlnVGV4dFN0eWxlXCJcbiAqICAgICAgIH0sXG4gKiAgICAgICBcInVzZXJIYW5kbGVcIjowLFxuICogICAgICAgXCJncm91cEtleVwiOlwiMHxpby5hcHBpdW0uc2V0dGluZ3N8MXxudWxsfDEwMTMzXCIsXG4gKiAgICAgICBcIm92ZXJyaWRlR3JvdXBLZXlcIjpudWxsLFxuICogICAgICAgXCJwb3N0VGltZVwiOjE1NzY4NTM1MTg4NTAsXG4gKiAgICAgICBcImtleVwiOlwiMHxpby5hcHBpdW0uc2V0dGluZ3N8MXxudWxsfDEwMTMzXCIsXG4gKiAgICAgICBcImlzUmVtb3ZlZFwiOmZhbHNlXG4gKiAgICAgfVxuICogICBdXG4gKiB9XG4gKiBgYGBcbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGVyZSB3YXMgYW4gZXJyb3Igd2hpbGUgZ2V0dGluZyB0aGUgbm90aWZpY2F0aW9ucyBsaXN0XG4gKi9cbmNvbW1hbmRzLmdldE5vdGlmaWNhdGlvbnMgPSBhc3luYyBmdW5jdGlvbiBnZXROb3RpZmljYXRpb25zICgpIHtcbiAgbG9nLmRlYnVnKCdSZXRyaWV2aW5nIG5vdGlmaWNhdGlvbnMnKTtcbiAgLy8gU29tZWhvdyBwcm92aWRpbmcgdGhlIGAtbmAgYXJnIHRvIHRoZSBgYW1gIHVuZGVybmVhdGhcbiAgLy8gcmVuZGVycyB0aGUgYnJvYWRjYXN0IHRvIGZhaWwgaW5zdGVhZCBvZiBzdGFydGluZyB0aGVcbiAgLy8gQXBwaXVtIFNldHRpbmdzIGFwcC4gVGhpcyBvbmx5IGhhcHBlbnMgdG8gdGhlIG5vdGlmaWNhdGlvbnNcbiAgLy8gcmVjZWl2ZXJcbiAgYXdhaXQgdGhpcy5yZXF1aXJlUnVubmluZ1NldHRpbmdzQXBwKCk7XG4gIGxldCBvdXRwdXQ7XG4gIHRyeSB7XG4gICAgb3V0cHV0ID0gYXdhaXQgdGhpcy5zaGVsbChbXG4gICAgICAnYW0nLCAnYnJvYWRjYXN0JyxcbiAgICAgICctYScsIE5PVElGSUNBVElPTlNfUkVUUklFVkFMX0FDVElPTixcbiAgICBdKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgcmV0cmlldmUgbm90aWZpY2F0aW9ucyBmcm9tIHRoZSBkZXZpY2UuIGAgK1xuICAgICAgYE1ha2Ugc3VyZSB0aGUgQXBwaXVtIFNldHRpbmdzIGFwcGxpY2F0aW9uIGlzIGluc3RhbGxlZCBhbmQgaXMgdXAgdG8gZGF0ZS4gYCArXG4gICAgICBgT3JpZ2luYWwgZXJyb3I6ICR7ZXJyLm1lc3NhZ2V9YCk7XG4gIH1cbiAgcmV0dXJuIHBhcnNlSnNvbkRhdGEob3V0cHV0LCAnbm90aWZpY2F0aW9ucycpO1xufTtcblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBTbXNMaXN0T3B0aW9uc1xuICogQHByb3BlcnR5IHtudW1iZXJ9IG1heCBbMTAwXSAtIFRoZSBtYXhpbXVtIGNvdW50IG9mIHJlY2VudCBtZXNzYWdlc1xuICogdG8gcmV0cmlldmVcbiAqL1xuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgbGlzdCBvZiB0aGUgbW9zdCByZWNlbnQgU01TXG4gKiBwcm9wZXJ0aWVzIGxpc3QgdmlhIEFwcGl1bSBTZXR0aW5ncyBoZWxwZXIuXG4gKiBNZXNzYWdlcyBhcmUgc29ydGVkIGJ5IGRhdGUgaW4gZGVzY2VuZGluZyBvcmRlci5cbiAqXG4gKiBAcGFyYW0ge1Ntc0xpc3RPcHRpb25zfSBvcHRzXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZXhhbXBsZSBvdXRwdXQgaXM6XG4gKiBgYGBqc29uXG4gKiB7XG4gKiAgIFwiaXRlbXNcIjpbXG4gKiAgICAge1xuICogICAgICAgXCJpZFwiOlwiMlwiLFxuICogICAgICAgXCJhZGRyZXNzXCI6XCIrMTIzNDU2Nzg5XCIsXG4gKiAgICAgICBcInBlcnNvblwiOm51bGwsXG4gKiAgICAgICBcImRhdGVcIjpcIjE1ODE5MzY0MjIyMDNcIixcbiAqICAgICAgIFwicmVhZFwiOlwiMFwiLFxuICogICAgICAgXCJzdGF0dXNcIjpcIi0xXCIsXG4gKiAgICAgICBcInR5cGVcIjpcIjFcIixcbiAqICAgICAgIFwic3ViamVjdFwiOm51bGwsXG4gKiAgICAgICBcImJvZHlcIjpcIlxcXCJ0ZXh0IG1lc3NhZ2UyXFxcIlwiLFxuICogICAgICAgXCJzZXJ2aWNlQ2VudGVyXCI6bnVsbFxuICogICAgIH0sXG4gKiAgICAge1xuICogICAgICAgXCJpZFwiOlwiMVwiLFxuICogICAgICAgXCJhZGRyZXNzXCI6XCIrMTIzNDU2Nzg5XCIsXG4gKiAgICAgICBcInBlcnNvblwiOm51bGwsXG4gKiAgICAgICBcImRhdGVcIjpcIjE1ODE5MzYzODI3NDBcIixcbiAqICAgICAgIFwicmVhZFwiOlwiMFwiLFxuICogICAgICAgXCJzdGF0dXNcIjpcIi0xXCIsXG4gKiAgICAgICBcInR5cGVcIjpcIjFcIixcbiAqICAgICAgIFwic3ViamVjdFwiOm51bGwsXG4gKiAgICAgICBcImJvZHlcIjpcIlxcXCJ0ZXh0IG1lc3NhZ2VcXFwiXCIsXG4gKiAgICAgICBcInNlcnZpY2VDZW50ZXJcIjpudWxsXG4gKiAgICAgfVxuICogICBdLFxuICogICBcInRvdGFsXCI6MlxuICogfVxuICogYGBgXG4gKiBAdGhyb3dzIHtFcnJvcn0gSWYgdGhlcmUgd2FzIGFuIGVycm9yIHdoaWxlIGdldHRpbmcgdGhlIFNNUyBsaXN0XG4gKi9cbmNvbW1hbmRzLmdldFNtc0xpc3QgPSBhc3luYyBmdW5jdGlvbiBnZXRTbXNMaXN0IChvcHRzID0ge30pIHtcbiAgbG9nLmRlYnVnKCdSZXRyaWV2aW5nIHRoZSByZWNlbnQgU01TIG1lc3NhZ2VzJyk7XG4gIGNvbnN0IGFyZ3MgPSBbXG4gICAgJ2FtJywgJ2Jyb2FkY2FzdCcsXG4gICAgJy1uJywgU01TX0xJU1RfUkVDRUlWRVIsXG4gICAgJy1hJywgU01TX0xJU1RfUkVUUklFVkFMX0FDVElPTixcbiAgXTtcbiAgaWYgKG9wdHMubWF4KSB7XG4gICAgYXJncy5wdXNoKCctLWVzJywgJ21heCcsIG9wdHMubWF4KTtcbiAgfVxuICBsZXQgb3V0cHV0O1xuICB0cnkge1xuICAgIG91dHB1dCA9IGF3YWl0IHRoaXMuc2hlbGwoYXJncyk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHJldHJpZXZlIFNNUyBsaXN0IGZyb20gdGhlIGRldmljZS4gYCArXG4gICAgICBgTWFrZSBzdXJlIHRoZSBBcHBpdW0gU2V0dGluZ3MgYXBwbGljYXRpb24gaXMgaW5zdGFsbGVkIGFuZCBpcyB1cCB0byBkYXRlLiBgICtcbiAgICAgIGBPcmlnaW5hbCBlcnJvcjogJHtlcnIubWVzc2FnZX1gKTtcbiAgfVxuICByZXR1cm4gcGFyc2VKc29uRGF0YShvdXRwdXQsICdTTVMgbGlzdCcpO1xufTtcblxuLyoqXG4gKiBUeXBlcyB0aGUgZ2l2ZW4gVW5pY29kZSBzdHJpbmcuXG4gKiBJdCBpcyBleHBlY3RlZCB0aGF0IHRoZSBmb2N1cyBpcyBhbHJlYWR5IHB1dFxuICogdG8gdGhlIGRlc3RpbmF0aW9uIGlucHV0IGZpZWxkIGJlZm9yZSB0aGlzIG1ldGhvZCBpcyBjYWxsZWQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgVGhlIHN0cmluZyB0byB0eXBlXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gYHRydWVgIGlmIHRoZSBpbnB1dCB0ZXh0IGhhcyBiZWVuIHN1Y2Nlc3NmdWxseSBzZW50IHRvIGFkYlxuICovXG5jb21tYW5kcy50eXBlVW5pY29kZSA9IGFzeW5jIGZ1bmN0aW9uIHR5cGVVbmljb2RlICh0ZXh0KSB7XG4gIGlmIChfLmlzTmlsKHRleHQpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdGV4dCA9IGAke3RleHR9YDtcbiAgbG9nLmRlYnVnKGBUeXBpbmcgJHt1dGlsLnBsdXJhbGl6ZSgnY2hhcmFjdGVyJywgdGV4dC5sZW5ndGgsIHRydWUpfWApO1xuICBpZiAoIXRleHQpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgYXdhaXQgdGhpcy5ydW5JbkltZUNvbnRleHQoVU5JQ09ERV9JTUUsXG4gICAgYXN5bmMgKCkgPT4gYXdhaXQgdGhpcy5zaGVsbChbJ2lucHV0JywgJ3RleHQnLCBpbWFwLmVuY29kZSh0ZXh0KV0pKTtcbiAgcmV0dXJuIHRydWU7XG59O1xuXG5leHBvcnQgZGVmYXVsdCBjb21tYW5kcztcbiJdLCJmaWxlIjoibGliL3Rvb2xzL3NldHRpbmdzLWNsaWVudC1jb21tYW5kcy5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLi8uLiJ9