appium-ios-simulator
Version:
iOS Simulator interface for Appium.
749 lines (590 loc) • 42.7 kB
JavaScript
require('source-map-support').install();
;
var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
var _getIterator = require('babel-runtime/core-js/get-iterator')['default'];
var _interopRequireWildcard = require('babel-runtime/helpers/interop-require-wildcard')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
var _ = require('../..');
var _nodeSimctl = require('node-simctl');
var simctl = _interopRequireWildcard(_nodeSimctl);
var _chai = require('chai');
var _chai2 = _interopRequireDefault(_chai);
var _chaiAsPromised = require('chai-as-promised');
var _chaiAsPromised2 = _interopRequireDefault(_chaiAsPromised);
var _appiumSupport = require('appium-support');
var _bluebird = require('bluebird');
var _bluebird2 = _interopRequireDefault(_bluebird);
var _sampleApps = require('sample-apps');
var _sampleApps2 = _interopRequireDefault(_sampleApps);
var LONG_TIMEOUT = 120 * 1000;
_chai2['default'].should();
_chai2['default'].use(_chaiAsPromised2['default']);
function runTests(deviceType) {
describe('simulator ' + deviceType.version, function () {
this.timeout(LONG_TIMEOUT);
var udid = undefined;
before(function callee$2$0() {
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.killAllSimulators)());
case 2:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
beforeEach(function callee$2$0() {
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap(simctl.createDevice('ios-simulator testing', deviceType.device, deviceType.version));
case 2:
udid = context$3$0.sent;
case 3:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
afterEach(function callee$2$0() {
var devicePresent;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap(simctl.getDevices());
case 2:
context$3$0.t0 = deviceType.version;
context$3$0.t1 = function (device) {
return device.udid === udid;
};
context$3$0.t2 = context$3$0.sent[context$3$0.t0].filter(context$3$0.t1).length;
devicePresent = context$3$0.t2 > 0;
if (!devicePresent) {
context$3$0.next = 11;
break;
}
context$3$0.next = 9;
return _regeneratorRuntime.awrap((0, _.killAllSimulators)());
case 9:
context$3$0.next = 11;
return _regeneratorRuntime.awrap(simctl.deleteDevice(udid));
case 11:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should detect whether a simulator has been run before', function callee$2$0() {
var sim;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.isFresh().should.eventually.equal(true));
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(sim.launchAndQuit());
case 7:
context$3$0.next = 9;
return _regeneratorRuntime.awrap(sim.isFresh().should.eventually.equal(false));
case 9:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should launch and shutdown a sim', function callee$2$0() {
var sim;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.launchAndQuit());
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(sim.stat());
case 7:
context$3$0.sent.state.should.equal('Shutdown');
case 8:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should launch and shutdown a sim, also starting safari', function callee$2$0() {
var sim;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.launchAndQuit(true));
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(sim.stat());
case 7:
context$3$0.sent.state.should.equal('Shutdown');
case 8:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should clean a sim', function callee$2$0() {
var sim;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.isFresh().should.eventually.equal(true));
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(sim.launchAndQuit());
case 7:
context$3$0.next = 9;
return _regeneratorRuntime.awrap(sim.isFresh().should.eventually.equal(false));
case 9:
context$3$0.next = 11;
return _regeneratorRuntime.awrap(sim.clean());
case 11:
context$3$0.next = 13;
return _regeneratorRuntime.awrap(sim.isFresh().should.eventually.equal(true));
case 13:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should not find any TestApp data or bundle directories on a fresh simulator', function callee$2$0() {
var sim, dirs;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.getAppDirs('TestApp', 'io.appium.TestApp'));
case 5:
dirs = context$3$0.sent;
dirs.should.have.length(0);
case 7:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should find both a data and bundle directory for TestApp', function callee$2$0() {
var sim, dirs;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.run());
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(simctl.installApp(udid, (0, _sampleApps2['default'])('TestApp')));
case 7:
context$3$0.next = 9;
return _regeneratorRuntime.awrap(simctl.launch(udid, 'io.appium.TestApp'));
case 9:
context$3$0.next = 11;
return _regeneratorRuntime.awrap(sim.getAppDirs('TestApp', 'io.appium.TestApp'));
case 11:
dirs = context$3$0.sent;
dirs.should.have.length(2);
dirs[0].should.contain('/Data/');
dirs[1].should.contain('/Bundle/');
case 15:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should delete custom app data', function callee$2$0() {
var sim, dirs;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.run());
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(simctl.installApp(udid, (0, _sampleApps2['default'])('TestApp')));
case 7:
context$3$0.next = 9;
return _regeneratorRuntime.awrap(simctl.launch(udid, 'io.appium.TestApp'));
case 9:
context$3$0.next = 11;
return _regeneratorRuntime.awrap(sim.cleanCustomApp('TestApp', 'io.appium.TestApp'));
case 11:
// clear paths to force the simulator to get a new list of directories
sim.appDataBundlePaths = {};
context$3$0.next = 14;
return _regeneratorRuntime.awrap(sim.getAppDirs('TestApp', 'io.appium.TestApp'));
case 14:
dirs = context$3$0.sent;
dirs.should.have.length(0);
case 16:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should delete a sim', function callee$2$0() {
var numDevices, sim, numDevicesAfter;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap(simctl.getDevices());
case 2:
context$3$0.t0 = deviceType.version;
numDevices = context$3$0.sent[context$3$0.t0].length;
numDevices.should.be.above(0);
context$3$0.next = 7;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 7:
sim = context$3$0.sent;
context$3$0.next = 10;
return _regeneratorRuntime.awrap(sim['delete']());
case 10:
context$3$0.next = 12;
return _regeneratorRuntime.awrap(simctl.getDevices());
case 12:
context$3$0.t1 = deviceType.version;
numDevicesAfter = context$3$0.sent[context$3$0.t1].length;
numDevicesAfter.should.equal(numDevices - 1);
case 15:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
var itText = 'should match a bundleId to its app directory on a used sim';
var bundleId = 'com.apple.mobilesafari';
if (deviceType.version === '7.1') {
itText = 'should match an app to its app directory on a used sim';
bundleId = 'MobileSafari';
}
it(itText, function callee$2$0() {
var sim, path;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.launchAndQuit());
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(sim.getAppDir(bundleId));
case 7:
path = context$3$0.sent;
context$3$0.next = 10;
return _regeneratorRuntime.awrap(_appiumSupport.fs.hasAccess(path).should.eventually.be['true']);
case 10:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
itText = 'should match a bundleId to its app directory on a fresh sim';
bundleId = 'com.apple.mobilesafari';
if (deviceType.version === '7.1') {
itText = 'should match an app to its app directory on a fresh sim';
bundleId = 'MobileSafari';
}
it(itText, function callee$2$0() {
var sim, path;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.getAppDir(bundleId));
case 5:
path = context$3$0.sent;
context$3$0.next = 8;
return _regeneratorRuntime.awrap(_appiumSupport.fs.hasAccess(path).should.eventually.be['true']);
case 8:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should start a sim using the "run" method', function callee$2$0() {
var sim, stat;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.run());
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(sim.stat());
case 7:
stat = context$3$0.sent;
stat.state.should.equal('Booted');
context$3$0.next = 11;
return _regeneratorRuntime.awrap(sim.shutdown());
case 11:
context$3$0.next = 13;
return _regeneratorRuntime.awrap(sim.stat());
case 13:
stat = context$3$0.sent;
stat.state.should.equal('Shutdown');
case 15:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should be able to start safari', function callee$2$0() {
var sim;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.run());
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(sim.openUrl('http://apple.com'));
case 7:
context$3$0.next = 9;
return _regeneratorRuntime.awrap(sim.shutdown());
case 9:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
// this test to catch errors in openUrl, that arise from bad sims or certain versions of xcode
it('should detect if a sim is running', function callee$2$0() {
var sim, running;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.isRunning());
case 5:
running = context$3$0.sent;
running.should.be['false'];
context$3$0.next = 9;
return _regeneratorRuntime.awrap(sim.run());
case 9:
context$3$0.next = 11;
return _regeneratorRuntime.awrap(sim.isRunning());
case 11:
running = context$3$0.sent;
running.should.be['true'];
context$3$0.next = 15;
return _regeneratorRuntime.awrap(sim.shutdown());
case 15:
context$3$0.next = 17;
return _regeneratorRuntime.awrap(sim.isRunning());
case 17:
running = context$3$0.sent;
running.should.be['false'];
case 19:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should isolate sim', function callee$2$0() {
var sim, numDevices;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 2:
sim = context$3$0.sent;
context$3$0.next = 5;
return _regeneratorRuntime.awrap(sim.isolateSim());
case 5:
context$3$0.next = 7;
return _regeneratorRuntime.awrap(simctl.getDevices());
case 7:
context$3$0.t0 = deviceType.version;
numDevices = context$3$0.sent[context$3$0.t0].length;
numDevices.should.equal(1);
case 10:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
});
describe('reuse an already-created already-run simulator ' + deviceType.version, function () {
this.timeout(LONG_TIMEOUT);
var sim = undefined;
before(function callee$2$0() {
var udid;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap((0, _.killAllSimulators)());
case 2:
context$3$0.next = 4;
return _regeneratorRuntime.awrap(simctl.createDevice('ios-simulator testing', deviceType.device, deviceType.version));
case 4:
udid = context$3$0.sent;
context$3$0.next = 7;
return _regeneratorRuntime.awrap((0, _.getSimulator)(udid));
case 7:
sim = context$3$0.sent;
context$3$0.next = 10;
return _regeneratorRuntime.awrap(sim.run());
case 10:
context$3$0.next = 12;
return _regeneratorRuntime.awrap(sim.shutdown());
case 12:
context$3$0.next = 14;
return _regeneratorRuntime.awrap(_bluebird2['default'].delay(4000));
case 14:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
after(function callee$2$0() {
var devicePresent;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap(simctl.getDevices());
case 2:
context$3$0.t0 = deviceType.version;
context$3$0.t1 = function (device) {
return device.udid === sim.udid;
};
context$3$0.t2 = context$3$0.sent[context$3$0.t0].filter(context$3$0.t1).length;
devicePresent = context$3$0.t2 > 0;
if (!devicePresent) {
context$3$0.next = 9;
break;
}
context$3$0.next = 9;
return _regeneratorRuntime.awrap(simctl.deleteDevice(sim.udid));
case 9:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
it('should start a sim using the "run" method', function callee$2$0() {
var stat;
return _regeneratorRuntime.async(function callee$2$0$(context$3$0) {
while (1) switch (context$3$0.prev = context$3$0.next) {
case 0:
context$3$0.next = 2;
return _regeneratorRuntime.awrap(sim.run());
case 2:
context$3$0.next = 4;
return _regeneratorRuntime.awrap(sim.stat());
case 4:
stat = context$3$0.sent;
stat.state.should.equal('Booted');
context$3$0.next = 8;
return _regeneratorRuntime.awrap(sim.shutdown());
case 8:
context$3$0.next = 10;
return _regeneratorRuntime.awrap(sim.stat());
case 10:
stat = context$3$0.sent;
stat.state.should.equal('Shutdown');
case 12:
case 'end':
return context$3$0.stop();
}
}, null, this);
});
});
}
var deviceTypes = [{
version: '8.4',
device: 'iPhone 6'
}, {
version: '9.0',
device: 'iPhone 6s'
}, {
version: '9.1',
device: 'iPhone 6s'
}];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _getIterator(deviceTypes), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var deviceType = _step.value;
runTests(deviceType);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
// only want to get rid of the device if it is present
// install & launch test app
// install & launch test app
// delete app directories
// only want to get rid of the device if it is present
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3Qvc2ltdWxhdG9yLWUyZS1zcGVjcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Z0JBRWdELE9BQU87OzBCQUMvQixhQUFhOztJQUF6QixNQUFNOztvQkFDRCxNQUFNOzs7OzhCQUNJLGtCQUFrQjs7Ozs2QkFDMUIsZ0JBQWdCOzt3QkFDckIsVUFBVTs7OzswQkFDRCxhQUFhOzs7O0FBR3BDLElBQU0sWUFBWSxHQUFHLEdBQUcsR0FBQyxJQUFJLENBQUM7O0FBRTlCLGtCQUFLLE1BQU0sRUFBRSxDQUFDO0FBQ2Qsa0JBQUssR0FBRyw2QkFBZ0IsQ0FBQzs7QUFFekIsU0FBUyxRQUFRLENBQUUsVUFBVSxFQUFFO0FBQzdCLFVBQVEsZ0JBQWMsVUFBVSxDQUFDLE9BQU8sRUFBSSxZQUFZO0FBQ3RELFFBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7QUFDM0IsUUFBSSxJQUFJLFlBQUEsQ0FBQztBQUNULFVBQU0sQ0FBQzs7Ozs7NkNBQ0MsMEJBQW1COzs7Ozs7O0tBQzFCLENBQUMsQ0FBQzs7QUFFSCxjQUFVLENBQUM7Ozs7OzZDQUNJLE1BQU0sQ0FBQyxZQUFZLENBQUMsdUJBQXVCLEVBQ3ZCLFVBQVUsQ0FBQyxNQUFNLEVBQ2pCLFVBQVUsQ0FBQyxPQUFPLENBQUM7OztBQUZwRCxnQkFBSTs7Ozs7OztLQUdMLENBQUMsQ0FBQztBQUNILGFBQVMsQ0FBQztVQUVKLGFBQWE7Ozs7OzZDQUFVLE1BQU0sQ0FBQyxVQUFVLEVBQUU7Ozs2QkFBRSxVQUFVLENBQUMsT0FBTzs7NkJBQ3hELFVBQUMsTUFBTSxFQUFLO0FBQ2xCLHFCQUFPLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDO2FBQzdCOzs4REFGQSxNQUFNLGlCQUVKLE1BQU07QUFIUCx5QkFBYSxvQkFHSCxDQUFDOztpQkFDWCxhQUFhOzs7Ozs7NkNBQ1QsMEJBQW1COzs7OzZDQUNuQixNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQzs7Ozs7OztL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aUJBQ1gsYUFBYTs7Ozs7OzZDQUNULE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQzs7Ozs7OztLQUV0QyxDQUFDLENBQUM7O0FBRUgsTUFBRSxDQUFDLDJDQUEyQyxFQUFFO1VBRzFDLElBQUk7Ozs7OzZDQUZGLEdBQUcsQ0FBQyxHQUFHLEVBQUU7Ozs7NkNBRUUsR0FBRyxDQUFDLElBQUksRUFBRTs7O0FBQXZCLGdCQUFJOztBQUNSLGdCQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7Ozs2Q0FFNUIsR0FBRyxDQUFDLFFBQVEsRUFBRTs7Ozs2Q0FDUCxHQUFHLENBQUMsSUFBSSxFQUFFOzs7QUFBdkIsZ0JBQUk7O0FBQ0osZ0JBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQzs7Ozs7OztLQUNyQyxDQUFDLENBQUM7R0FDSixDQUFDLENBQUM7Q0FDSjs7QUFFRCxJQUFNLFdBQVcsR0FBRyxDQUNsQjtBQUNFLFNBQU8sRUFBRSxLQUFLO0FBQ2QsUUFBTSxFQUFFLFVBQVU7Q0FDbkIsRUFDRDtBQUNFLFNBQU8sRUFBRSxLQUFLO0FBQ2QsUUFBTSxFQUFFLFdBQVc7Q0FDcEIsRUFDRDtBQUNFLFNBQU8sRUFBRSxLQUFLO0FBQ2QsUUFBTSxFQUFFLFdBQVc7Q0FDcEIsQ0FDRixDQUFDOzs7Ozs7QUFDRixvQ0FBdUIsV0FBVyw0R0FBRTtRQUEzQixVQUFVOztBQUNqQixZQUFRLENBQUMsVUFBVSxDQUFDLENBQUM7R0FDdEIiLCJmaWxlIjoidGVzdC9zaW11bGF0b3ItZTJlLXNwZWNzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gdHJhbnNwaWxlOm1vY2hhXG5cbmltcG9ydCB7IGdldFNpbXVsYXRvciwga2lsbEFsbFNpbXVsYXRvcnMgfSBmcm9tICcuLi8uLic7XG5pbXBvcnQgKiBhcyBzaW1jdGwgZnJvbSAnbm9kZS1zaW1jdGwnO1xuaW1wb3J0IGNoYWkgZnJvbSAnY2hhaSc7XG5pbXBvcnQgY2hhaUFzUHJvbWlzZWQgZnJvbSAnY2hhaS1hcy1wcm9taXNlZCc7XG5pbXBvcnQgeyBmcyB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCBCIGZyb20gJ2JsdWViaXJkJztcbmltcG9ydCBnZXRBcHBQYXRoIGZyb20gJ3NhbXBsZS1hcHBzJztcblxuXG5jb25zdCBMT05HX1RJTUVPVVQgPSAxMjAqMTAwMDtcblxuY2hhaS5zaG91bGQoKTtcbmNoYWkudXNlKGNoYWlBc1Byb21pc2VkKTtcblxuZnVuY3Rpb24gcnVuVGVzdHMgKGRldmljZVR5cGUpIHtcbiAgZGVzY3JpYmUoYHNpbXVsYXRvciAke2RldmljZVR5cGUudmVyc2lvbn1gLCBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy50aW1lb3V0KExPTkdfVElNRU9VVCk7XG4gICAgbGV0IHVkaWQ7XG4gICAgYmVmb3JlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGtpbGxBbGxTaW11bGF0b3JzKCk7XG4gICAgfSk7XG5cbiAgICBiZWZvcmVFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIHVkaWQgPSBhd2FpdCBzaW1jdGwuY3JlYXRlRGV2aWNlKCdpb3Mtc2ltdWxhdG9yIHRlc3RpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGV2aWNlVHlwZS5kZXZpY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXZpY2VUeXBlLnZlcnNpb24pO1xuICAgIH0pO1xuICAgIGFmdGVyRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBvbmx5IHdhbnQgdG8gZ2V0IHJpZCBvZiB0aGUgZGV2aWNlIGlmIGl0IGlzIHByZXNlbnRcbiAgICAgIGxldCBkZXZpY2VQcmVzZW50ID0gKGF3YWl0IHNpbWN0bC5nZXREZXZpY2VzKCkpW2RldmljZVR5cGUudmVyc2lvbl1cbiAgICAgICAgLmZpbHRlcigoZGV2aWNlKSA9PiB7XG4gICAgICAgICAgcmV0dXJuIGRldmljZS51ZGlkID09PSB1ZGlkO1xuICAgICAgICB9KS5sZW5ndGggPiAwO1xuICAgICAgaWYgKGRldmljZVByZXNlbnQpIHtcbiAgICAgICAgYXdhaXQga2lsbEFsbFNpbXVsYXRvcnMoKTtcbiAgICAgICAgYXdhaXQgc2ltY3RsLmRlbGV0ZURldmljZSh1ZGlkKTtcbiAgICAgIH1cbiAgICB9KTtcblxuXG4gICAgaXQoJ3Nob3VsZCBkZXRlY3Qgd2hldGhlciBhIHNpbXVsYXRvciBoYXMgYmVlbiBydW4gYmVmb3JlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHNpbSA9IGF3YWl0IGdldFNpbXVsYXRvcih1ZGlkKTtcbiAgICAgIGF3YWl0IHNpbS5pc0ZyZXNoKCkuc2hvdWxkLmV2ZW50dWFsbHkuZXF1YWwodHJ1ZSk7XG4gICAgICBhd2FpdCBzaW0ubGF1bmNoQW5kUXVpdCgpO1xuICAgICAgYXdhaXQgc2ltLmlzRnJlc2goKS5zaG91bGQuZXZlbnR1YWxseS5lcXVhbChmYWxzZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGxhdW5jaCBhbmQgc2h1dGRvd24gYSBzaW0nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgc2ltID0gYXdhaXQgZ2V0U2ltdWxhdG9yKHVkaWQpO1xuICAgICAgYXdhaXQgc2ltLmxhdW5jaEFuZFF1aXQoKTtcbiAgICAgIChhd2FpdCBzaW0uc3RhdCgpKS5zdGF0ZS5zaG91bGQuZXF1YWwoJ1NodXRkb3duJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGxhdW5jaCBhbmQgc2h1dGRvd24gYSBzaW0sIGFsc28gc3RhcnRpbmcgc2FmYXJpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHNpbSA9IGF3YWl0IGdldFNpbXVsYXRvcih1ZGlkKTtcbiAgICAgIGF3YWl0IHNpbS5sYXVuY2hBbmRRdWl0KHRydWUpO1xuICAgICAgKGF3YWl0IHNpbS5zdGF0KCkpLnN0YXRlLnNob3VsZC5lcXVhbCgnU2h1dGRvd24nKTtcbiAgICB9KTtcblxuXG4gICAgaXQoJ3Nob3VsZCBjbGVhbiBhIHNpbScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzaW0gPSBhd2FpdCBnZXRTaW11bGF0b3IodWRpZCk7XG4gICAgICBhd2FpdCBzaW0uaXNGcmVzaCgpLnNob3VsZC5ldmVudHVhbGx5LmVxdWFsKHRydWUpO1xuICAgICAgYXdhaXQgc2ltLmxhdW5jaEFuZFF1aXQoKTtcbiAgICAgIGF3YWl0IHNpbS5pc0ZyZXNoKCkuc2hvdWxkLmV2ZW50dWFsbHkuZXF1YWwoZmFsc2UpO1xuICAgICAgYXdhaXQgc2ltLmNsZWFuKCk7XG4gICAgICBhd2FpdCBzaW0uaXNGcmVzaCgpLnNob3VsZC5ldmVudHVhbGx5LmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBub3QgZmluZCBhbnkgVGVzdEFwcCBkYXRhIG9yIGJ1bmRsZSBkaXJlY3RvcmllcyBvbiBhIGZyZXNoIHNpbXVsYXRvcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzaW0gPSBhd2FpdCBnZXRTaW11bGF0b3IodWRpZCk7XG4gICAgICBsZXQgZGlycyA9IGF3YWl0IHNpbS5nZXRBcHBEaXJzKCdUZXN0QXBwJywgJ2lvLmFwcGl1bS5UZXN0QXBwJyk7XG4gICAgICBkaXJzLnNob3VsZC5oYXZlLmxlbmd0aCgwKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmluZCBib3RoIGEgZGF0YSBhbmQgYnVuZGxlIGRpcmVjdG9yeSBmb3IgVGVzdEFwcCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzaW0gPSBhd2FpdCBnZXRTaW11bGF0b3IodWRpZCk7XG4gICAgICBhd2FpdCBzaW0ucnVuKCk7XG5cbiAgICAgIC8vIGluc3RhbGwgJiBsYXVuY2ggdGVzdCBhcHBcbiAgICAgIGF3YWl0IHNpbWN0bC5pbnN0YWxsQXBwKHVkaWQsIGdldEFwcFBhdGgoJ1Rlc3RBcHAnKSk7XG4gICAgICBhd2FpdCBzaW1jdGwubGF1bmNoKHVkaWQsICdpby5hcHBpdW0uVGVzdEFwcCcpO1xuXG4gICAgICBsZXQgZGlycyA9IGF3YWl0IHNpbS5nZXRBcHBEaXJzKCdUZXN0QXBwJywgJ2lvLmFwcGl1bS5UZXN0QXBwJyk7XG4gICAgICBkaXJzLnNob3VsZC5oYXZlLmxlbmd0aCgyKTtcbiAgICAgIGRpcnNbMF0uc2hvdWxkLmNvbnRhaW4oJy9EYXRhLycpO1xuICAgICAgZGlyc1sxXS5zaG91bGQuY29udGFpbignL0J1bmRsZS8nKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZGVsZXRlIGN1c3RvbSBhcHAgZGF0YScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzaW0gPSBhd2FpdCBnZXRTaW11bGF0b3IodWRpZCk7XG4gICAgICBhd2FpdCBzaW0ucnVuKCk7XG5cbiAgICAgIC8vIGluc3RhbGwgJiBsYXVuY2ggdGVzdCBhcHBcbiAgICAgIGF3YWl0IHNpbWN0bC5pbnN0YWxsQXBwKHVkaWQsIGdldEFwcFBhdGgoJ1Rlc3RBcHAnKSk7XG4gICAgICBhd2FpdCBzaW1jdGwubGF1bmNoKHVkaWQsICdpby5hcHBpdW0uVGVzdEFwcCcpO1xuXG4gICAgICAvLyBkZWxldGUgYXBwIGRpcmVjdG9yaWVzXG4gICAgICBhd2FpdCBzaW0uY2xlYW5DdXN0b21BcHAoJ1Rlc3RBcHAnLCAnaW8uYXBwaXVtLlRlc3RBcHAnKTtcblxuICAgICAgLy8gY2xlYXIgcGF0aHMgdG8gZm9yY2UgdGhlIHNpbXVsYXRvciB0byBnZXQgYSBuZXcgbGlzdCBvZiBkaXJlY3Rvcmllc1xuICAgICAgc2ltLmFwcERhdGFCdW5kbGVQYXRocyA9IHt9O1xuXG4gICAgICBsZXQgZGlycyA9IGF3YWl0IHNpbS5nZXRBcHBEaXJzKCdUZXN0QXBwJywgJ2lvLmFwcGl1bS5UZXN0QXBwJyk7XG4gICAgICBkaXJzLnNob3VsZC5oYXZlLmxlbmd0aCgwKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZGVsZXRlIGEgc2ltJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IG51bURldmljZXMgPSAoYXdhaXQgc2ltY3RsLmdldERldmljZXMoKSlbZGV2aWNlVHlwZS52ZXJzaW9uXS5sZW5ndGg7XG4gICAgICBudW1EZXZpY2VzLnNob3VsZC5iZS5hYm92ZSgwKTtcblxuICAgICAgbGV0IHNpbSA9IGF3YWl0IGdldFNpbXVsYXRvcih1ZGlkKTtcbiAgICAgIGF3YWl0IHNpbS5kZWxldGUoKTtcbiAgICAgIGxldCBudW1EZXZpY2VzQWZ0ZXIgPSAoYXdhaXQgc2ltY3RsLmdldERldmljZXMoKSlbZGV2aWNlVHlwZS52ZXJzaW9uXS5sZW5ndGg7XG4gICAgICBudW1EZXZpY2VzQWZ0ZXIuc2hvdWxkLmVxdWFsKG51bURldmljZXMtMSk7XG4gICAgfSk7XG5cbiAgICBsZXQgaXRUZXh0ID0gJ3Nob3VsZCBtYXRjaCBhIGJ1bmRsZUlkIHRvIGl0cyBhcHAgZGlyZWN0b3J5IG9uIGEgdXNlZCBzaW0nO1xuICAgIGxldCBidW5kbGVJZCA9ICdjb20uYXBwbGUubW9iaWxlc2FmYXJpJztcbiAgICBpZiAoZGV2aWNlVHlwZS52ZXJzaW9uID09PSAnNy4xJykge1xuICAgICAgaXRUZXh0ID0gJ3Nob3VsZCBtYXRjaCBhbiBhcHAgdG8gaXRzIGFwcCBkaXJlY3Rvcnkgb24gYSB1c2VkIHNpbSc7XG4gICAgICBidW5kbGVJZCA9ICdNb2JpbGVTYWZhcmknO1xuICAgIH1cbiAgICBpdChpdFRleHQsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzaW0gPSBhd2FpdCBnZXRTaW11bGF0b3IodWRpZCk7XG4gICAgICBhd2FpdCBzaW0ubGF1bmNoQW5kUXVpdCgpO1xuXG4gICAgICBsZXQgcGF0aCA9IGF3YWl0IHNpbS5nZXRBcHBEaXIoYnVuZGxlSWQpO1xuICAgICAgYXdhaXQgZnMuaGFzQWNjZXNzKHBhdGgpLnNob3VsZC5ldmVudHVhbGx5LmJlLnRydWU7XG4gICAgfSk7XG5cbiAgICBpdFRleHQgPSAnc2hvdWxkIG1hdGNoIGEgYnVuZGxlSWQgdG8gaXRzIGFwcCBkaXJlY3Rvcnkgb24gYSBmcmVzaCBzaW0nO1xuICAgIGJ1bmRsZUlkID0gJ2NvbS5hcHBsZS5tb2JpbGVzYWZhcmknO1xuICAgIGlmIChkZXZpY2VUeXBlLnZlcnNpb24gPT09ICc3LjEnKSB7XG4gICAgICBpdFRleHQgPSAnc2hvdWxkIG1hdGNoIGFuIGFwcCB0byBpdHMgYXBwIGRpcmVjdG9yeSBvbiBhIGZyZXNoIHNpbSc7XG4gICAgICBidW5kbGVJZCA9ICdNb2JpbGVTYWZhcmknO1xuICAgIH1cbiAgICBpdChpdFRleHQsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzaW0gPSBhd2FpdCBnZXRTaW11bGF0b3IodWRpZCk7XG4gICAgICBsZXQgcGF0aCA9IGF3YWl0IHNpbS5nZXRBcHBEaXIoYnVuZGxlSWQpO1xuICAgICAgYXdhaXQgZnMuaGFzQWNjZXNzKHBhdGgpLnNob3VsZC5ldmVudHVhbGx5LmJlLnRydWU7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN0YXJ0IGEgc2ltIHVzaW5nIHRoZSBcInJ1blwiIG1ldGhvZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzaW0gPSBhd2FpdCBnZXRTaW11bGF0b3IodWRpZCk7XG5cbiAgICAgIGF3YWl0IHNpbS5ydW4oKTtcblxuICAgICAgbGV0IHN0YXQgPSBhd2FpdCBzaW0uc3RhdCgpO1xuICAgICAgc3RhdC5zdGF0ZS5zaG91bGQuZXF1YWwoJ0Jvb3RlZCcpO1xuXG4gICAgICBhd2FpdCBzaW0uc2h1dGRvd24oKTtcbiAgICAgIHN0YXQgPSBhd2FpdCBzaW0uc3RhdCgpO1xuICAgICAgc3RhdC5zdGF0ZS5zaG91bGQuZXF1YWwoJ1NodXRkb3duJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGJlIGFibGUgdG8gc3RhcnQgc2FmYXJpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHNpbSA9IGF3YWl0IGdldFNpbXVsYXRvcih1ZGlkKTtcblxuICAgICAgYXdhaXQgc2ltLnJ1bigpO1xuICAgICAgYXdhaXQgc2ltLm9wZW5VcmwoJ2h0dHA6Ly9hcHBsZS5jb20nKTtcbiAgICAgIGF3YWl0IHNpbS5zaHV0ZG93bigpO1xuXG4gICAgICAvLyB0aGlzIHRlc3QgdG8gY2F0Y2ggZXJyb3JzIGluIG9wZW5VcmwsIHRoYXQgYXJpc2UgZnJvbSBiYWQgc2ltcyBvciBjZXJ0YWluIHZlcnNpb25zIG9mIHhjb2RlXG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGRldGVjdCBpZiBhIHNpbSBpcyBydW5uaW5nJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHNpbSA9IGF3YWl0IGdldFNpbXVsYXRvcih1ZGlkKTtcbiAgICAgIGxldCBydW5uaW5nID0gYXdhaXQgc2ltLmlzUnVubmluZygpO1xuICAgICAgcnVubmluZy5zaG91bGQuYmUuZmFsc2U7XG5cbiAgICAgIGF3YWl0IHNpbS5ydW4oKTtcbiAgICAgIHJ1bm5pbmcgPSBhd2FpdCBzaW0uaXNSdW5uaW5nKCk7XG4gICAgICBydW5uaW5nLnNob3VsZC5iZS50cnVlO1xuXG4gICAgICBhd2FpdCBzaW0uc2h1dGRvd24oKTtcbiAgICAgIHJ1bm5pbmcgPSBhd2FpdCBzaW0uaXNSdW5uaW5nKCk7XG4gICAgICBydW5uaW5nLnNob3VsZC5iZS5mYWxzZTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgaXNvbGF0ZSBzaW0nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgc2ltID0gYXdhaXQgZ2V0U2ltdWxhdG9yKHVkaWQpO1xuICAgICAgYXdhaXQgc2ltLmlzb2xhdGVTaW0oKTtcblxuICAgICAgbGV0IG51bURldmljZXMgPSAoYXdhaXQgc2ltY3RsLmdldERldmljZXMoKSlbZGV2aWNlVHlwZS52ZXJzaW9uXS5sZW5ndGg7XG5cbiAgICAgIG51bURldmljZXMuc2hvdWxkLmVxdWFsKDEpO1xuICAgIH0pO1xuXG4gIH0pO1xuXG4gIGRlc2NyaWJlKGByZXVzZSBhbiBhbHJlYWR5LWNyZWF0ZWQgYWxyZWFkeS1ydW4gc2ltdWxhdG9yICR7ZGV2aWNlVHlwZS52ZXJzaW9ufWAsIGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnRpbWVvdXQoTE9OR19USU1FT1VUKTtcbiAgICBsZXQgc2ltO1xuICAgIGJlZm9yZShhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBraWxsQWxsU2ltdWxhdG9ycygpO1xuICAgICAgbGV0IHVkaWQgPSBhd2FpdCBzaW1jdGwuY3JlYXRlRGV2aWNlKCdpb3Mtc2ltdWxhdG9yIHRlc3RpbmcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGV2aWNlVHlwZS5kZXZpY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXZpY2VUeXBlLnZlcnNpb24pO1xuICAgICAgc2ltID0gYXdhaXQgZ2V0U2ltdWxhdG9yKHVkaWQpO1xuICAgICAgYXdhaXQgc2ltLnJ1bigpO1xuICAgICAgYXdhaXQgc2ltLnNodXRkb3duKCk7XG4gICAgICBhd2FpdCBCLmRlbGF5KDQwMDApO1xuICAgIH0pO1xuICAgIGFmdGVyKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIG9ubHkgd2FudCB0byBnZXQgcmlkIG9mIHRoZSBkZXZpY2UgaWYgaXQgaXMgcHJlc2VudFxuICAgICAgbGV0IGRldmljZVByZXNlbnQgPSAoYXdhaXQgc2ltY3RsLmdldERldmljZXMoKSlbZGV2aWNlVHlwZS52ZXJzaW9uXVxuICAgICAgICAuZmlsdGVyKChkZXZpY2UpID0+IHtcbiAgICAgICAgICByZXR1cm4gZGV2aWNlLnVkaWQgPT09IHNpbS51ZGlkO1xuICAgICAgICB9KS5sZW5ndGggPiAwO1xuICAgICAgaWYgKGRldmljZVByZXNlbnQpIHtcbiAgICAgICAgYXdhaXQgc2ltY3RsLmRlbGV0ZURldmljZShzaW0udWRpZCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN0YXJ0IGEgc2ltIHVzaW5nIHRoZSBcInJ1blwiIG1ldGhvZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IHNpbS5ydW4oKTtcblxuICAgICAgbGV0IHN0YXQgPSBhd2FpdCBzaW0uc3RhdCgpO1xuICAgICAgc3RhdC5zdGF0ZS5zaG91bGQuZXF1YWwoJ0Jvb3RlZCcpO1xuXG4gICAgICBhd2FpdCBzaW0uc2h1dGRvd24oKTtcbiAgICAgIHN0YXQgPSBhd2FpdCBzaW0uc3RhdCgpO1xuICAgICAgc3RhdC5zdGF0ZS5zaG91bGQuZXF1YWwoJ1NodXRkb3duJyk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG5jb25zdCBkZXZpY2VUeXBlcyA9IFtcbiAge1xuICAgIHZlcnNpb246ICc4LjQnLFxuICAgIGRldmljZTogJ2lQaG9uZSA2J1xuICB9LFxuICB7XG4gICAgdmVyc2lvbjogJzkuMCcsXG4gICAgZGV2aWNlOiAnaVBob25lIDZzJ1xuICB9LFxuICB7XG4gICAgdmVyc2lvbjogJzkuMScsXG4gICAgZGV2aWNlOiAnaVBob25lIDZzJ1xuICB9XG5dO1xuZm9yIChsZXQgZGV2aWNlVHlwZSBvZiBkZXZpY2VUeXBlcykge1xuICBydW5UZXN0cyhkZXZpY2VUeXBlKTtcbn1cbiJdfQ==