ngx-webstorage-service
Version:
Angular service wrappers for the webstorage API
122 lines • 14.7 kB
JavaScript
import { BaseStorageService } from './base-storage.service';
import { StorageTranscoders } from './storage-transcoders';
/**
* An implementation of `StorageService` interface that uses an underlying (web) `Storage` object, such as `localStorage` and
* `sessionStorage`, as backing data store. This class basically wraps the `Storage` object so it can be accessed through the
* `StorageService` interface.
*/
export class WebStorageService extends BaseStorageService {
/**
* Creates a new `WebStorageService` instance that uses the specified (web) storage object as underlying backing storage.
*
* @param storage Storage object which is to be wrapped in a class that implements the `StorageService` interface.
*/
constructor(storage) {
super(StorageTranscoders.JSON);
this.storage = storage;
}
/**
* Checks whether an entry with the specified key exists in the storage.
*
* @param key Identifier of the entry for which its presence in the storage is to be checked.
* @returns `true` if an entry with the specified key exists in the storage, `false` if not.
*/
has(key) {
return this.storage.getItem(key) !== null;
}
/**
* Removes the entry that is identified by the specified key. Attempting to remove an entry for an unknown key will have no effect.
* Attempting to retrieve an entry via the `get` method after it has been removed will result in `undefined`.
*
* @param key Identifier of the entry which is to be removed.
*/
remove(key) {
this.storage.removeItem(key);
}
/**
* Clears the storage by removing all entries. Subsequent `get(x)` calls for a key *x* will return `undefined`, until a new value is set
* for key *x*.
*/
clear() {
this.storage.clear();
}
/**
* Performs the actual retrieval of a value from storage.
*
* @param key Identifier of the entry whose value is to be retrieved.
* @returns The value that is stored for the specified entry or `undefined` if no entry exists for the specified key.
*/
getItem(key) {
const value = this.storage.getItem(key);
return value !== null ? value : undefined;
}
/**
* Stores the provided value using specified key in the storage.
*
* @param key Identifier of the entry for which the value is to be stored.
* @param value The value that is to be stored.
*/
setItem(key, value) {
return this.storage.setItem(key, value);
}
}
/**
* Checks whether the specified (web) storage is available and functional. This might not be the case for older browsers. However even
* certain browsers that do support the web storage API can, under some circumstances, have non functional storage objects. For example,
* Safari is known to have `localStorage` and `sessionStorage` throw exceptions in private mode.
*
* @param storage Storage object which is to be tested for availability.
* @returns `true` if the specified storage can be used, `false` if not.
*/
export function isStorageAvailable(storage) {
// Check if storage is available.
if (!storage) {
return false;
}
// Check if the storage can actually be accessed.
try {
const now = Date.now();
const testItemKey = `storage-test-entry-${now}`;
const testItemValue = `storage-test-value-${now}`;
storage.setItem(testItemKey, testItemValue);
const retrievedItemValue = storage.getItem(testItemKey);
storage.removeItem(testItemKey);
return retrievedItemValue === testItemValue;
}
catch (error) {
return false;
}
}
/**
* Checks whether session storage is available and functional. This might not be the case for older browsers. However even certain browsers
* that do support the web storage API can, under some circumstances, have non functional storage objects. For example, Safari is known to
* have `sessionStorage` throw exceptions in private mode.
*
* @returns `true` if session storage can be used, `false` if not.
*/
export function isSessionStorageAvailable() {
try {
if (typeof sessionStorage !== 'undefined') {
return isStorageAvailable(sessionStorage);
}
}
catch { }
return false;
}
/**
* Checks whether local storage is available and functional. This might not be the case for older browsers. However even certain browsers
* that do support the web storage API can, under some circumstances, have non functional storage objects. For example, Safari is known to
* have `localStorage` throw exceptions in private mode.
*
* @returns `true` if local storage can be used, `false` if not.
*/
export function isLocalStorageAvailable() {
try {
if (typeof localStorage !== 'undefined') {
return isStorageAvailable(localStorage);
}
}
catch { }
return false;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViLXN0b3JhZ2Uuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2xpYi9zcmMvd2ViLXN0b3JhZ2Uuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM1RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUUzRDs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLGlCQUFrQixTQUFRLGtCQUF1QjtJQUUxRDs7OztPQUlHO0lBQ0gsWUFBNkIsT0FBZ0I7UUFDekMsS0FBSyxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBRE4sWUFBTyxHQUFQLE9BQU8sQ0FBUztJQUU3QyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxHQUFHLENBQUMsR0FBVztRQUNsQixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksQ0FBQztJQUM5QyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsR0FBVztRQUNyQixJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksS0FBSztRQUNSLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDekIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ08sT0FBTyxDQUFDLEdBQVc7UUFDekIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFeEMsT0FBTyxLQUFLLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUM5QyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDTyxPQUFPLENBQUMsR0FBVyxFQUFFLEtBQWE7UUFDeEMsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDNUMsQ0FBQztDQUVKO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxPQUFnQjtJQUMvQyxpQ0FBaUM7SUFDakMsSUFBSSxDQUFDLE9BQU8sRUFBRTtRQUNWLE9BQU8sS0FBSyxDQUFDO0tBQ2hCO0lBRUQsaURBQWlEO0lBQ2pELElBQUk7UUFDQSxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDdkIsTUFBTSxXQUFXLEdBQUcsc0JBQXNCLEdBQUcsRUFBRSxDQUFDO1FBQ2hELE1BQU0sYUFBYSxHQUFHLHNCQUFzQixHQUFHLEVBQUUsQ0FBQztRQUNsRCxPQUFPLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxhQUFhLENBQUMsQ0FBQztRQUM1QyxNQUFNLGtCQUFrQixHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDeEQsT0FBTyxDQUFDLFVBQVUsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUVoQyxPQUFPLGtCQUFrQixLQUFLLGFBQWEsQ0FBQztLQUMvQztJQUFDLE9BQU8sS0FBSyxFQUFFO1FBQ1osT0FBTyxLQUFLLENBQUM7S0FDaEI7QUFDTCxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QjtJQUNyQyxJQUFJO1FBQ0EsSUFBSSxPQUFPLGNBQXFCLEtBQUssV0FBVyxFQUFFO1lBQzlDLE9BQU8sa0JBQWtCLENBQUMsY0FBYyxDQUFDLENBQUM7U0FDN0M7S0FDSjtJQUFDLE1BQU0sR0FBRTtJQUVWLE9BQU8sS0FBSyxDQUFDO0FBQ2pCLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsdUJBQXVCO0lBQ25DLElBQUk7UUFDQSxJQUFJLE9BQU8sWUFBbUIsS0FBSyxXQUFXLEVBQUU7WUFDNUMsT0FBTyxrQkFBa0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztTQUMzQztLQUNKO0lBQUMsTUFBTSxHQUFFO0lBRVYsT0FBTyxLQUFLLENBQUM7QUFDakIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJhc2VTdG9yYWdlU2VydmljZSB9IGZyb20gJy4vYmFzZS1zdG9yYWdlLnNlcnZpY2UnO1xuaW1wb3J0IHsgU3RvcmFnZVRyYW5zY29kZXJzIH0gZnJvbSAnLi9zdG9yYWdlLXRyYW5zY29kZXJzJztcblxuLyoqXG4gKiBBbiBpbXBsZW1lbnRhdGlvbiBvZiBgU3RvcmFnZVNlcnZpY2VgIGludGVyZmFjZSB0aGF0IHVzZXMgYW4gdW5kZXJseWluZyAod2ViKSBgU3RvcmFnZWAgb2JqZWN0LCBzdWNoIGFzIGBsb2NhbFN0b3JhZ2VgIGFuZFxuICogYHNlc3Npb25TdG9yYWdlYCwgYXMgYmFja2luZyBkYXRhIHN0b3JlLiBUaGlzIGNsYXNzIGJhc2ljYWxseSB3cmFwcyB0aGUgYFN0b3JhZ2VgIG9iamVjdCBzbyBpdCBjYW4gYmUgYWNjZXNzZWQgdGhyb3VnaCB0aGVcbiAqIGBTdG9yYWdlU2VydmljZWAgaW50ZXJmYWNlLlxuICovXG5leHBvcnQgY2xhc3MgV2ViU3RvcmFnZVNlcnZpY2UgZXh0ZW5kcyBCYXNlU3RvcmFnZVNlcnZpY2U8YW55PiB7XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGVzIGEgbmV3IGBXZWJTdG9yYWdlU2VydmljZWAgaW5zdGFuY2UgdGhhdCB1c2VzIHRoZSBzcGVjaWZpZWQgKHdlYikgc3RvcmFnZSBvYmplY3QgYXMgdW5kZXJseWluZyBiYWNraW5nIHN0b3JhZ2UuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RvcmFnZSBTdG9yYWdlIG9iamVjdCB3aGljaCBpcyB0byBiZSB3cmFwcGVkIGluIGEgY2xhc3MgdGhhdCBpbXBsZW1lbnRzIHRoZSBgU3RvcmFnZVNlcnZpY2VgIGludGVyZmFjZS5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHN0b3JhZ2U6IFN0b3JhZ2UpIHtcbiAgICAgICAgc3VwZXIoU3RvcmFnZVRyYW5zY29kZXJzLkpTT04pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIGFuIGVudHJ5IHdpdGggdGhlIHNwZWNpZmllZCBrZXkgZXhpc3RzIGluIHRoZSBzdG9yYWdlLlxuICAgICAqXG4gICAgICogQHBhcmFtICAga2V5IElkZW50aWZpZXIgb2YgdGhlIGVudHJ5IGZvciB3aGljaCBpdHMgcHJlc2VuY2UgaW4gdGhlIHN0b3JhZ2UgaXMgdG8gYmUgY2hlY2tlZC5cbiAgICAgKiBAcmV0dXJucyAgICAgYHRydWVgIGlmIGFuIGVudHJ5IHdpdGggdGhlIHNwZWNpZmllZCBrZXkgZXhpc3RzIGluIHRoZSBzdG9yYWdlLCBgZmFsc2VgIGlmIG5vdC5cbiAgICAgKi9cbiAgICBwdWJsaWMgaGFzKGtleTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0b3JhZ2UuZ2V0SXRlbShrZXkpICE9PSBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIGVudHJ5IHRoYXQgaXMgaWRlbnRpZmllZCBieSB0aGUgc3BlY2lmaWVkIGtleS4gQXR0ZW1wdGluZyB0byByZW1vdmUgYW4gZW50cnkgZm9yIGFuIHVua25vd24ga2V5IHdpbGwgaGF2ZSBubyBlZmZlY3QuXG4gICAgICogQXR0ZW1wdGluZyB0byByZXRyaWV2ZSBhbiBlbnRyeSB2aWEgdGhlIGBnZXRgIG1ldGhvZCBhZnRlciBpdCBoYXMgYmVlbiByZW1vdmVkIHdpbGwgcmVzdWx0IGluIGB1bmRlZmluZWRgLlxuICAgICAqXG4gICAgICogQHBhcmFtIGtleSBJZGVudGlmaWVyIG9mIHRoZSBlbnRyeSB3aGljaCBpcyB0byBiZSByZW1vdmVkLlxuICAgICAqL1xuICAgIHB1YmxpYyByZW1vdmUoa2V5OiBzdHJpbmcpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5zdG9yYWdlLnJlbW92ZUl0ZW0oa2V5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGVhcnMgdGhlIHN0b3JhZ2UgYnkgcmVtb3ZpbmcgYWxsIGVudHJpZXMuIFN1YnNlcXVlbnQgYGdldCh4KWAgY2FsbHMgZm9yIGEga2V5ICp4KiB3aWxsIHJldHVybiBgdW5kZWZpbmVkYCwgdW50aWwgYSBuZXcgdmFsdWUgaXMgc2V0XG4gICAgICogZm9yIGtleSAqeCouXG4gICAgICovXG4gICAgcHVibGljIGNsZWFyKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnN0b3JhZ2UuY2xlYXIoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJmb3JtcyB0aGUgYWN0dWFsIHJldHJpZXZhbCBvZiBhIHZhbHVlIGZyb20gc3RvcmFnZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSAgIGtleSBJZGVudGlmaWVyIG9mIHRoZSBlbnRyeSB3aG9zZSB2YWx1ZSBpcyB0byBiZSByZXRyaWV2ZWQuXG4gICAgICogQHJldHVybnMgICAgIFRoZSB2YWx1ZSB0aGF0IGlzIHN0b3JlZCBmb3IgdGhlIHNwZWNpZmllZCBlbnRyeSBvciBgdW5kZWZpbmVkYCBpZiBubyBlbnRyeSBleGlzdHMgZm9yIHRoZSBzcGVjaWZpZWQga2V5LlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBnZXRJdGVtKGtleTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLnN0b3JhZ2UuZ2V0SXRlbShrZXkpO1xuXG4gICAgICAgIHJldHVybiB2YWx1ZSAhPT0gbnVsbCA/IHZhbHVlIDogdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN0b3JlcyB0aGUgcHJvdmlkZWQgdmFsdWUgdXNpbmcgc3BlY2lmaWVkIGtleSBpbiB0aGUgc3RvcmFnZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBrZXkgICBJZGVudGlmaWVyIG9mIHRoZSBlbnRyeSBmb3Igd2hpY2ggdGhlIHZhbHVlIGlzIHRvIGJlIHN0b3JlZC5cbiAgICAgKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRoYXQgaXMgdG8gYmUgc3RvcmVkLlxuICAgICAqL1xuICAgIHByb3RlY3RlZCBzZXRJdGVtKGtleTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIHJldHVybiB0aGlzLnN0b3JhZ2Uuc2V0SXRlbShrZXksIHZhbHVlKTtcbiAgICB9XG5cbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciB0aGUgc3BlY2lmaWVkICh3ZWIpIHN0b3JhZ2UgaXMgYXZhaWxhYmxlIGFuZCBmdW5jdGlvbmFsLiBUaGlzIG1pZ2h0IG5vdCBiZSB0aGUgY2FzZSBmb3Igb2xkZXIgYnJvd3NlcnMuIEhvd2V2ZXIgZXZlblxuICogY2VydGFpbiBicm93c2VycyB0aGF0IGRvIHN1cHBvcnQgdGhlIHdlYiBzdG9yYWdlIEFQSSBjYW4sIHVuZGVyIHNvbWUgY2lyY3Vtc3RhbmNlcywgaGF2ZSBub24gZnVuY3Rpb25hbCBzdG9yYWdlIG9iamVjdHMuIEZvciBleGFtcGxlLFxuICogU2FmYXJpIGlzIGtub3duIHRvIGhhdmUgYGxvY2FsU3RvcmFnZWAgYW5kIGBzZXNzaW9uU3RvcmFnZWAgdGhyb3cgZXhjZXB0aW9ucyBpbiBwcml2YXRlIG1vZGUuXG4gKlxuICogQHBhcmFtICAgc3RvcmFnZSBTdG9yYWdlIG9iamVjdCB3aGljaCBpcyB0byBiZSB0ZXN0ZWQgZm9yIGF2YWlsYWJpbGl0eS5cbiAqIEByZXR1cm5zICAgICAgICAgYHRydWVgIGlmIHRoZSBzcGVjaWZpZWQgc3RvcmFnZSBjYW4gYmUgdXNlZCwgYGZhbHNlYCBpZiBub3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1N0b3JhZ2VBdmFpbGFibGUoc3RvcmFnZTogU3RvcmFnZSk6IGJvb2xlYW4ge1xuICAgIC8vIENoZWNrIGlmIHN0b3JhZ2UgaXMgYXZhaWxhYmxlLlxuICAgIGlmICghc3RvcmFnZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHN0b3JhZ2UgY2FuIGFjdHVhbGx5IGJlIGFjY2Vzc2VkLlxuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gICAgICAgIGNvbnN0IHRlc3RJdGVtS2V5ID0gYHN0b3JhZ2UtdGVzdC1lbnRyeS0ke25vd31gO1xuICAgICAgICBjb25zdCB0ZXN0SXRlbVZhbHVlID0gYHN0b3JhZ2UtdGVzdC12YWx1ZS0ke25vd31gO1xuICAgICAgICBzdG9yYWdlLnNldEl0ZW0odGVzdEl0ZW1LZXksIHRlc3RJdGVtVmFsdWUpO1xuICAgICAgICBjb25zdCByZXRyaWV2ZWRJdGVtVmFsdWUgPSBzdG9yYWdlLmdldEl0ZW0odGVzdEl0ZW1LZXkpO1xuICAgICAgICBzdG9yYWdlLnJlbW92ZUl0ZW0odGVzdEl0ZW1LZXkpO1xuXG4gICAgICAgIHJldHVybiByZXRyaWV2ZWRJdGVtVmFsdWUgPT09IHRlc3RJdGVtVmFsdWU7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBzZXNzaW9uIHN0b3JhZ2UgaXMgYXZhaWxhYmxlIGFuZCBmdW5jdGlvbmFsLiBUaGlzIG1pZ2h0IG5vdCBiZSB0aGUgY2FzZSBmb3Igb2xkZXIgYnJvd3NlcnMuIEhvd2V2ZXIgZXZlbiBjZXJ0YWluIGJyb3dzZXJzXG4gKiB0aGF0IGRvIHN1cHBvcnQgdGhlIHdlYiBzdG9yYWdlIEFQSSBjYW4sIHVuZGVyIHNvbWUgY2lyY3Vtc3RhbmNlcywgaGF2ZSBub24gZnVuY3Rpb25hbCBzdG9yYWdlIG9iamVjdHMuIEZvciBleGFtcGxlLCBTYWZhcmkgaXMga25vd24gdG9cbiAqIGhhdmUgYHNlc3Npb25TdG9yYWdlYCB0aHJvdyBleGNlcHRpb25zIGluIHByaXZhdGUgbW9kZS5cbiAqXG4gKiBAcmV0dXJucyBgdHJ1ZWAgaWYgc2Vzc2lvbiBzdG9yYWdlIGNhbiBiZSB1c2VkLCBgZmFsc2VgIGlmIG5vdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2Vzc2lvblN0b3JhZ2VBdmFpbGFibGUoKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBzZXNzaW9uU3RvcmFnZSBhcyBhbnkgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICByZXR1cm4gaXNTdG9yYWdlQXZhaWxhYmxlKHNlc3Npb25TdG9yYWdlKTtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2gge31cblxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBsb2NhbCBzdG9yYWdlIGlzIGF2YWlsYWJsZSBhbmQgZnVuY3Rpb25hbC4gVGhpcyBtaWdodCBub3QgYmUgdGhlIGNhc2UgZm9yIG9sZGVyIGJyb3dzZXJzLiBIb3dldmVyIGV2ZW4gY2VydGFpbiBicm93c2Vyc1xuICogdGhhdCBkbyBzdXBwb3J0IHRoZSB3ZWIgc3RvcmFnZSBBUEkgY2FuLCB1bmRlciBzb21lIGNpcmN1bXN0YW5jZXMsIGhhdmUgbm9uIGZ1bmN0aW9uYWwgc3RvcmFnZSBvYmplY3RzLiBGb3IgZXhhbXBsZSwgU2FmYXJpIGlzIGtub3duIHRvXG4gKiBoYXZlIGBsb2NhbFN0b3JhZ2VgIHRocm93IGV4Y2VwdGlvbnMgaW4gcHJpdmF0ZSBtb2RlLlxuICpcbiAqIEByZXR1cm5zIGB0cnVlYCBpZiBsb2NhbCBzdG9yYWdlIGNhbiBiZSB1c2VkLCBgZmFsc2VgIGlmIG5vdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzTG9jYWxTdG9yYWdlQXZhaWxhYmxlKCk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2YgbG9jYWxTdG9yYWdlIGFzIGFueSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIHJldHVybiBpc1N0b3JhZ2VBdmFpbGFibGUobG9jYWxTdG9yYWdlKTtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2gge31cblxuICAgIHJldHVybiBmYWxzZTtcbn1cbiJdfQ==