UNPKG

pouchdb-find

Version:
840 lines (751 loc) 4.3 MB
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"./test/test.js":[function(require,module,exports){ (function (process){ /*jshint expr:true */ 'use strict'; var queryString = require('query-string'); var Pouch = require('pouchdb'); var thePlugin = require('../'); Pouch.plugin(thePlugin); require('./test-utils'); var couch; if (typeof process === 'undefined' || process.browser) { couch = queryString.parse(location.search).couchHost || 'http://127.0.0.1:5984'; } else { couch = process.env.COUCH_HOST || 'http://127.0.0.1:5984'; } var dbs = 'testdb_find,' + couch + '/testdb_find'; dbs.split(',').forEach(function (db) { var dbType = /^http/.test(db) ? 'http' : 'local'; tests(db, dbType); }); function tests(dbName, dbType) { require('./test-suite-1')(dbName, dbType, Pouch); require('./test-suite-2')(dbName, dbType, Pouch); if (dbType === 'local') { require('./test-abstract-mapreduce')(dbName, dbType, Pouch); } } }).call(this,require('_process')) //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvdGVzdC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIvKmpzaGludCBleHByOnRydWUgKi9cbid1c2Ugc3RyaWN0JztcblxudmFyIHF1ZXJ5U3RyaW5nID0gcmVxdWlyZSgncXVlcnktc3RyaW5nJyk7XG52YXIgUG91Y2ggPSByZXF1aXJlKCdwb3VjaGRiJyk7XG52YXIgdGhlUGx1Z2luID0gcmVxdWlyZSgnLi4vJyk7XG5Qb3VjaC5wbHVnaW4odGhlUGx1Z2luKTtcblxucmVxdWlyZSgnLi90ZXN0LXV0aWxzJyk7XG5cbnZhciBjb3VjaDtcbmlmICh0eXBlb2YgcHJvY2VzcyA9PT0gJ3VuZGVmaW5lZCcgfHwgcHJvY2Vzcy5icm93c2VyKSB7XG4gIGNvdWNoID0gcXVlcnlTdHJpbmcucGFyc2UobG9jYXRpb24uc2VhcmNoKS5jb3VjaEhvc3QgfHxcbiAgICAnaHR0cDovLzEyNy4wLjAuMTo1OTg0Jztcbn0gZWxzZSB7XG4gIGNvdWNoID0gcHJvY2Vzcy5lbnYuQ09VQ0hfSE9TVCB8fCAnaHR0cDovLzEyNy4wLjAuMTo1OTg0Jztcbn1cblxudmFyICBkYnMgPSAndGVzdGRiX2ZpbmQsJyArIGNvdWNoICsgJy90ZXN0ZGJfZmluZCc7XG5cbmRicy5zcGxpdCgnLCcpLmZvckVhY2goZnVuY3Rpb24gKGRiKSB7XG4gIHZhciBkYlR5cGUgPSAvXmh0dHAvLnRlc3QoZGIpID8gJ2h0dHAnIDogJ2xvY2FsJztcbiAgdGVzdHMoZGIsIGRiVHlwZSk7XG59KTtcblxuZnVuY3Rpb24gdGVzdHMoZGJOYW1lLCBkYlR5cGUpIHtcblxuICByZXF1aXJlKCcuL3Rlc3Qtc3VpdGUtMScpKGRiTmFtZSwgZGJUeXBlLCBQb3VjaCk7XG4gIHJlcXVpcmUoJy4vdGVzdC1zdWl0ZS0yJykoZGJOYW1lLCBkYlR5cGUsIFBvdWNoKTtcblxuICBpZiAoZGJUeXBlID09PSAnbG9jYWwnKSB7XG4gICAgcmVxdWlyZSgnLi90ZXN0LWFic3RyYWN0LW1hcHJlZHVjZScpKGRiTmFtZSwgZGJUeXBlLCBQb3VjaCk7XG4gIH1cblxufVxuIl19 },{"../":"/Users/garren/dev/pouchdb-find/lib/index.js","./test-abstract-mapreduce":"/Users/garren/dev/pouchdb-find/test/test-abstract-mapreduce/index.js","./test-suite-1":"/Users/garren/dev/pouchdb-find/test/test-suite-1/index.js","./test-suite-2":"/Users/garren/dev/pouchdb-find/test/test-suite-2/index.js","./test-utils":"/Users/garren/dev/pouchdb-find/test/test-utils.js","_process":"/Users/garren/dev/pouchdb-find/node_modules/process/browser.js","pouchdb":"/Users/garren/dev/pouchdb-find/node_modules/pouchdb/lib/index.js","query-string":"/Users/garren/dev/pouchdb-find/node_modules/query-string/index.js"}],"/Users/garren/dev/pouchdb-find/lib/abstract-mapreduce/create-view.js":[function(require,module,exports){ 'use strict'; var upsert = require('./upsert'); var utils = require('./utils'); var Promise = utils.Promise; function stringify(input) { if (!input) { return 'undefined'; // backwards compat for empty reduce } // for backwards compat with mapreduce, functions/strings are stringified // as-is. everything else is JSON-stringified. switch (typeof input) { case 'function': // e.g. a mapreduce map return input.toString(); case 'string': // e.g. a mapreduce built-in _reduce function return input.toString(); default: // e.g. a JSON object in the case of mango queries return JSON.stringify(input); } } module.exports = function (opts) { var sourceDB = opts.db; var viewName = opts.viewName; var mapFun = opts.map; var reduceFun = opts.reduce; var temporary = opts.temporary; var pluginName = opts.pluginName; // the "undefined" part is for backwards compatibility var viewSignature = stringify(mapFun) + stringify(reduceFun) + 'undefined'; if (!temporary && sourceDB._cachedViews) { var cachedView = sourceDB._cachedViews[viewSignature]; if (cachedView) { return Promise.resolve(cachedView); } } return sourceDB.info().then(function (info) { var depDbName = info.db_name + '-mrview-' + (temporary ? 'temp' : utils.MD5(viewSignature)); // save the view name in the source PouchDB so it can be cleaned up if necessary // (e.g. when the _design doc is deleted, remove all associated view data) function diffFunction(doc) { doc.views = doc.views || {}; var fullViewName = viewName; if (fullViewName.indexOf('/') === -1) { fullViewName = viewName + '/' + viewName; } var depDbs = doc.views[fullViewName] = doc.views[fullViewName] || {}; /* istanbul ignore if */ if (depDbs[depDbName]) { return; // no update necessary } depDbs[depDbName] = true; return doc; } return upsert(sourceDB, '_local/' + pluginName, diffFunction).then(function () { return sourceDB.registerDependentDatabase(depDbName).then(function (res) { var db = res.db; db.auto_compaction = true; var view = { name: depDbName, db: db, sourceDB: sourceDB, adapter: sourceDB.adapter, mapFun: mapFun, reduceFun: reduceFun }; return view.db.get('_local/lastSeq').catch(function (err) { /* istanbul ignore if */ if (err.status !== 404) { throw err; } }).then(function (lastSeqDoc) { view.seq = lastSeqDoc ? lastSeqDoc.seq : 0; if (!temporary) { sourceDB._cachedViews = sourceDB._cachedViews || {}; sourceDB._cachedViews[viewSignature] = view; view.db.on('destroyed', function () { delete sourceDB._cachedViews[viewSignature]; }); } return view; }); }); }); }); }; },{"./upsert":"/Users/garren/dev/pouchdb-find/lib/abstract-mapreduce/upsert.js","./utils":"/Users/garren/dev/pouchdb-find/lib/abstract-mapreduce/utils.js"}],"/Users/garren/dev/pouchdb-find/lib/abstract-mapreduce/index.js":[function(require,module,exports){ (function (process){ 'use strict'; var pouchCollate = require('pouchdb-collate'); var TaskQueue = require('./taskqueue'); var collate = pouchCollate.collate; var toIndexableString = pouchCollate.toIndexableString; var normalizeKey = pouchCollate.normalizeKey; var createView = require('./create-view'); var log; /* istanbul ignore else */ if ((typeof console !== 'undefined') && (typeof console.log === 'function')) { log = Function.prototype.bind.call(console.log, console); } else { log = function () {}; } var utils = require('./utils'); var Promise = utils.Promise; var persistentQueues = {}; var tempViewQueue = new TaskQueue(); var CHANGES_BATCH_SIZE = 50; function QueryParseError(message) { this.status = 400; this.name = 'query_parse_error'; this.message = message; this.error = true; try { Error.captureStackTrace(this, QueryParseError); } catch (e) {} } utils.inherits(QueryParseError, Error); function NotFoundError(message) { this.status = 404; this.name = 'not_found'; this.message = message; this.error = true; try { Error.captureStackTrace(this, NotFoundError); } catch (e) {} } utils.inherits(NotFoundError, Error); function parseViewName(name) { // can be either 'ddocname/viewname' or just 'viewname' // (where the ddoc name is the same) return name.indexOf('/') === -1 ? [name, name] : name.split('/'); } function isGenOne(changes) { // only return true if the current change is 1- // and there are no other leafs return changes.length === 1 && /^1-/.test(changes[0].rev); } function sortByKeyThenValue(x, y) { var keyCompare = collate(x.key, y.key); return keyCompare !== 0 ? keyCompare : collate(x.value, y.value); } function sliceResults(results, limit, skip) { skip = skip || 0; if (typeof limit === 'number') { return results.slice(skip, limit + skip); } else if (skip > 0) { return results.slice(skip); } return results; } function rowToDocId(row) { var val = row.value; // Users can explicitly specify a joined doc _id, or it // defaults to the doc _id that emitted the key/value. var docId = (val && typeof val === 'object' && val._id) || row.id; return docId; } function emitError(db, e) { try { db.emit('error', e); } catch (err) { console.error( 'The user\'s map/reduce function threw an uncaught error.\n' + 'You can debug this error by doing:\n' + 'myDatabase.on(\'error\', function (err) { debugger; });\n' + 'Please double-check your map/reduce function.'); console.error(e); } } function tryCode(db, fun, args) { // emit an event if there was an error thrown by a map/reduce function. // putting try/catches in a single function also avoids deoptimizations. try { return { output : fun.apply(null, args) }; } catch (e) { emitError(db, e); return {error: e}; } } function checkQueryParseError(options, fun) { var startkeyName = options.descending ? 'endkey' : 'startkey'; var endkeyName = options.descending ? 'startkey' : 'endkey'; if (typeof options[startkeyName] !== 'undefined' && typeof options[endkeyName] !== 'undefined' && collate(options[startkeyName], options[endkeyName]) > 0) { throw new QueryParseError('No rows can match your key range, reverse your ' + 'start_key and end_key or set {descending : true}'); } else if (fun.reduce && options.reduce !== false) { if (options.include_docs) { throw new QueryParseError('{include_docs:true} is invalid for reduce'); } else if (options.keys && options.keys.length > 1 && !options.group && !options.group_level) { throw new QueryParseError('Multi-key fetches for reduce views must use {group: true}'); } } if (options.group_level) { if (typeof options.group_level !== 'number') { throw new QueryParseError('Invalid value for integer: "' + options.group_level + '"'); } if (options.group_level < 0) { throw new QueryParseError('Invalid value for positive integer: ' + '"' + options.group_level + '"'); } } } function defaultsTo(value) { return function (reason) { /* istanbul ignore else */ if (reason.status === 404) { return value; } else { throw reason; } }; } function createIndexer(def) { var pluginName = def.name; var mapper = def.mapper; var reducer = def.reducer; var ddocValidator = def.ddocValidator; // returns a promise for a list of docs to update, based on the input docId. // the order doesn't matter, because post-3.2.0, bulkDocs // is an atomic operation in all three adapters. function getDocsToPersist(docId, view, docIdsToChangesAndEmits) { var metaDocId = '_local/doc_' + docId; var defaultMetaDoc = {_id: metaDocId, keys: []}; var docData = docIdsToChangesAndEmits[docId]; var indexableKeysToKeyValues = docData.indexableKeysToKeyValues; var changes = docData.changes; function getMetaDoc() { if (isGenOne(changes)) { // generation 1, so we can safely assume initial state // for performance reasons (avoids unnecessary GETs) return Promise.resolve(defaultMetaDoc); } return view.db.get(metaDocId).catch(defaultsTo(defaultMetaDoc)); } function getKeyValueDocs(metaDoc) { if (!metaDoc.keys.length) { // no keys, no need for a lookup return Promise.resolve({rows: []}); } return view.db.allDocs({ keys: metaDoc.keys, include_docs: true }); } function processKvDocs(metaDoc, kvDocsRes) { var kvDocs = []; var oldKeysMap = {}; for (var i = 0, len = kvDocsRes.rows.length; i < len; i++) { var row = kvDocsRes.rows[i]; var doc = row.doc; if (!doc) { // deleted continue; } kvDocs.push(doc); oldKeysMap[doc._id] = true; doc._deleted = !indexableKeysToKeyValues[doc._id]; if (!doc._deleted) { var keyValue = indexableKeysToKeyValues[doc._id]; if ('value' in keyValue) { doc.value = keyValue.value; } } } var newKeys = Object.keys(indexableKeysToKeyValues); newKeys.forEach(function (key) { if (!oldKeysMap[key]) { // new doc var kvDoc = { _id: key }; var keyValue = indexableKeysToKeyValues[key]; if ('value' in keyValue) { kvDoc.value = keyValue.value; } kvDocs.push(kvDoc); } }); metaDoc.keys = utils.uniq(newKeys.concat(metaDoc.keys)); kvDocs.push(metaDoc); return kvDocs; } return getMetaDoc().then(function (metaDoc) { return getKeyValueDocs(metaDoc).then(function (kvDocsRes) { return processKvDocs(metaDoc, kvDocsRes); }); }); } // updates all emitted key/value docs and metaDocs in the mrview database // for the given batch of documents from the source database function saveKeyValues(view, docIdsToChangesAndEmits, seq) { var seqDocId = '_local/lastSeq'; return view.db.get(seqDocId) .catch(defaultsTo({_id: seqDocId, seq: 0})) .then(function (lastSeqDoc) { var docIds = Object.keys(docIdsToChangesAndEmits); return Promise.all(docIds.map(function (docId) { return getDocsToPersist(docId, view, docIdsToChangesAndEmits); })).then(function (listOfDocsToPersist) { var docsToPersist = utils.flatten(listOfDocsToPersist); lastSeqDoc.seq = seq; docsToPersist.push(lastSeqDoc); // write all docs in a single operation, update the seq once return view.db.bulkDocs({docs : docsToPersist}); }); }); } function getQueue(view) { var viewName = typeof view === 'string' ? view : view.name; var queue = persistentQueues[viewName]; if (!queue) { queue = persistentQueues[viewName] = new TaskQueue(); } return queue; } function updateView(view) { return utils.sequentialize(getQueue(view), function () { return updateViewInQueue(view); })(); } function updateViewInQueue(view) { // bind the emit function once var mapResults; var doc; function emit(key, value) { var output = {id: doc._id, key: normalizeKey(key)}; // Don't explicitly store the value unless it's defined and non-null. // This saves on storage space, because often people don't use it. if (typeof value !== 'undefined' && value !== null) { output.value = normalizeKey(value); } mapResults.push(output); } var mapFun = mapper(view.mapFun, emit); var currentSeq = view.seq || 0; function processChange(docIdsToChangesAndEmits, seq) { return function () { return saveKeyValues(view, docIdsToChangesAndEmits, seq); }; } var queue = new TaskQueue(); return new Promise(function (resolve, reject) { function complete() { queue.finish().then(function () { view.seq = currentSeq; resolve(); }); } function processNextBatch() { view.sourceDB.changes({ conflicts: true, include_docs: true, style: 'all_docs', since: currentSeq, limit: CHANGES_BATCH_SIZE }).on('complete', function (response) { var results = response.results; if (!results.length) { return complete(); } var docIdsToChangesAndEmits = {}; for (var i = 0, l = results.length; i < l; i++) { var change = results[i]; if (change.doc._id[0] !== '_') { mapResults = []; doc = change.doc; if (!doc._deleted) { tryCode(view.sourceDB, mapFun, [doc]); } mapResults.sort(sortByKeyThenValue); var indexableKeysToKeyValues = {}; var lastKey; for (var j = 0, jl = mapResults.length; j < jl; j++) { var obj = mapResults[j]; var complexKey = [obj.key, obj.id]; if (collate(obj.key, lastKey) === 0) { complexKey.push(j); // dup key+id, so make it unique } var indexableKey = toIndexableString(complexKey); indexableKeysToKeyValues[indexableKey] = obj; lastKey = obj.key; } docIdsToChangesAndEmits[change.doc._id] = { indexableKeysToKeyValues: indexableKeysToKeyValues, changes: change.changes }; } currentSeq = change.seq; } queue.add(processChange(docIdsToChangesAndEmits, currentSeq)); if (results.length < CHANGES_BATCH_SIZE) { return complete(); } return processNextBatch(); }).on('error', onError); /* istanbul ignore next */ function onError(err) { reject(err); } } processNextBatch(); }); } function reduceView(view, results, options) { if (options.group_level === 0) { delete options.group_level; } var shouldGroup = options.group || options.group_level; var reduceFun = reducer(view.reduceFun); var groups = []; var lvl = options.group_level; results.forEach(function (e) { var last = groups[groups.length - 1]; var key = shouldGroup ? e.key : null; // only set group_level for array keys if (shouldGroup && Array.isArray(key) && typeof lvl === 'number') { key = key.length > lvl ? key.slice(0, lvl) : key; } if (last && collate(last.key[0][0], key) === 0) { last.key.push([key, e.id]); last.value.push(e.value); return; } groups.push({key: [ [key, e.id] ], value: [e.value]}); }); for (var i = 0, len = groups.length; i < len; i++) { var e = groups[i]; var reduceTry = tryCode(view.sourceDB, reduceFun, [e.key, e.value, false]); // TODO: can't do instanceof BuiltInError because this class is buried // in mapreduce.js if (reduceTry.error && /BuiltInError/.test(reduceTry.error.constructor)) { // CouchDB returns an error if a built-in errors out throw reduceTry.error; } // CouchDB just sets the value to null if a non-built-in errors out e.value = reduceTry.error ? null : reduceTry.output; e.key = e.key[0][0]; } // no total_rows/offset when reducing return {rows: sliceResults(groups, options.limit, options.skip)}; } function queryView(view, opts) { return utils.sequentialize(getQueue(view), function () { return queryViewInQueue(view, opts); })(); } function queryViewInQueue(view, opts) { var totalRows; var shouldReduce = view.reduceFun && opts.reduce !== false; var skip = opts.skip || 0; if (typeof opts.keys !== 'undefined' && !opts.keys.length) { // equivalent query opts.limit = 0; delete opts.keys; } function fetchFromView(viewOpts) { viewOpts.include_docs = true; return view.db.allDocs(viewOpts).then(function (res) { totalRows = res.total_rows; return res.rows.map(function (result) { // implicit migration - in older versions of PouchDB, // we explicitly stored the doc as {id: ..., key: ..., value: ...} // this is tested in a migration test /* istanbul ignore next */ if ('value' in result.doc && typeof result.doc.value === 'object' && result.doc.value !== null) { var keys = Object.keys(result.doc.value).sort(); // this detection method is not perfect, but it's unlikely the user // emitted a value which was an object with these 3 exact keys var expectedKeys = ['id', 'key', 'value']; if (!(keys < expectedKeys || keys > expectedKeys)) { return result.doc.value; } } var parsedKeyAndDocId = pouchCollate.parseIndexableString(result.doc._id); return { key: parsedKeyAndDocId[0], id: parsedKeyAndDocId[1], value: ('value' in result.doc ? result.doc.value : null) }; }); }); } function onMapResultsReady(rows) { var finalResults; if (shouldReduce) { finalResults = reduceView(view, rows, opts); } else { finalResults = { total_rows: totalRows, offset: skip, rows: rows }; } if (opts.include_docs) { var docIds = utils.uniq(rows.map(rowToDocId)); return view.sourceDB.allDocs({ keys: docIds, include_docs: true, conflicts: opts.conflicts, attachments: opts.attachments, binary: opts.binary }).then(function (allDocsRes) { var docIdsToDocs = {}; allDocsRes.rows.forEach(function (row) { if (row.doc) { docIdsToDocs['$' + row.id] = row.doc; } }); rows.forEach(function (row) { var docId = rowToDocId(row); var doc = docIdsToDocs['$' + docId]; if (doc) { row.doc = doc; } }); return finalResults; }); } else { return finalResults; } } var flatten = function (array) { return array.reduce(function (prev, cur) { return prev.concat(cur); }); }; if (typeof opts.keys !== 'undefined') { var keys = opts.keys; var fetchPromises = keys.map(function (key) { var viewOpts = { startkey : toIndexableString([key]), endkey : toIndexableString([key, {}]) }; return fetchFromView(viewOpts); }); return Promise.all(fetchPromises).then(flatten).then(onMapResultsReady); } else { // normal query, no 'keys' var viewOpts = { descending : opts.descending }; if (typeof opts.startkey !== 'undefined') { viewOpts.startkey = opts.descending ? toIndexableString([opts.startkey, {}]) : toIndexableString([opts.startkey]); } if (typeof opts.endkey !== 'undefined') { var inclusiveEnd = opts.inclusive_end !== false; if (opts.descending) { inclusiveEnd = !inclusiveEnd; } viewOpts.endkey = toIndexableString(inclusiveEnd ? [opts.endkey, {}] : [opts.endkey]); } if (typeof opts.key !== 'undefined') { var keyStart = toIndexableString([opts.key]); var keyEnd = toIndexableString([opts.key, {}]); if (viewOpts.descending) { viewOpts.endkey = keyStart; viewOpts.startkey = keyEnd; } else { viewOpts.startkey = keyStart; viewOpts.endkey = keyEnd; } } if (!shouldReduce) { if (typeof opts.limit === 'number') { viewOpts.limit = opts.limit; } viewOpts.skip = skip; } return fetchFromView(viewOpts).then(onMapResultsReady); } } function localViewCleanup(db) { return db.get('_local/' + pluginName).then(function (metaDoc) { var docsToViews = {}; Object.keys(metaDoc.views).forEach(function (fullViewName) { var parts = parseViewName(fullViewName); var designDocName = '_design/' + parts[0]; var viewName = parts[1]; docsToViews[designDocName] = docsToViews[designDocName] || {}; docsToViews[designDocName][viewName] = true; }); var opts = { keys : Object.keys(docsToViews), include_docs : true }; return db.allDocs(opts).then(function (res) { var viewsToStatus = {}; res.rows.forEach(function (row) { var ddocName = row.key.substring(8); Object.keys(docsToViews[row.key]).forEach(function (viewName) { var fullViewName = ddocName + '/' + viewName; /* istanbul ignore if */ if (!metaDoc.views[fullViewName]) { // new format, without slashes, to support PouchDB 2.2.0 // migration test in pouchdb's browser.migration.js verifies this fullViewName = viewName; } var viewDBNames = Object.keys(metaDoc.views[fullViewName]); // design doc deleted, or view function nonexistent var statusIsGood = row.doc && row.doc.views && row.doc.views[viewName]; viewDBNames.forEach(function (viewDBName) { viewsToStatus[viewDBName] = viewsToStatus[viewDBName] || statusIsGood; }); }); }); var dbsToDelete = Object.keys(viewsToStatus).filter(function (viewDBName) { return !viewsToStatus[viewDBName]; }); var destroyPromises = dbsToDelete.map(function (viewDBName) { return utils.sequentialize(getQueue(viewDBName), function () { return new db.constructor(viewDBName, db.__opts).destroy(); })(); }); return Promise.all(destroyPromises).then(function () { return {ok: true}; }); }); }, defaultsTo({ok: true})); } function queryPromised(db, fun, opts) { if (typeof fun !== 'string') { // temp_view checkQueryParseError(opts, fun); var createViewOpts = { db : db, viewName : 'temp_view/temp_view', map : fun.map, reduce : fun.reduce, temporary : true, pluginName: pluginName }; tempViewQueue.add(function () { return createView(createViewOpts).then(function (view) { function cleanup() { return view.db.destroy(); } return utils.fin(updateView(view).then(function () { return queryView(view, opts); }), cleanup); }); }); return tempViewQueue.finish(); } else { // persistent view var fullViewName = fun; var parts = parseViewName(fullViewName); var designDocName = parts[0]; var viewName = parts[1]; return db.get('_design/' + designDocName).then(function (doc) { var fun = doc.views && doc.views[viewName]; if (!fun) { // basic validator; it's assumed that every subclass would want this throw new NotFoundError('ddoc ' + doc._id + ' has no view named ' + viewName); } ddocValidator(doc, viewName); checkQueryParseError(opts, fun); var createViewOpts = { db : db, viewName : fullViewName, map : fun.map, reduce : fun.reduce, pluginName: pluginName }; return createView(createViewOpts).then(function (view) { if (opts.stale === 'ok' || opts.stale === 'update_after') { if (opts.stale === 'update_after') { process.nextTick(function () { updateView(view); }); } return queryView(view, opts); } else { // stale not ok return updateView(view).then(function () { return queryView(view, opts); }); } }); }); } } var query = function (fun, opts, callback) { var db = this; if (typeof opts === 'function') { callback = opts; opts = {}; } opts = utils.extend(true, {}, opts); if (typeof fun === 'function') { fun = {map : fun}; } var promise = Promise.resolve().then(function () { return queryPromised(db, fun, opts); }); utils.promisedCallback(promise, callback); return promise; }; var viewCleanup = utils.callbackify(function () { var db = this; return localViewCleanup(db); }); return { query: query, viewCleanup: viewCleanup }; } module.exports = createIndexer; }).call(this,require('_process')) //# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9hYnN0cmFjdC1tYXByZWR1Y2UvaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbnZhciBwb3VjaENvbGxhdGUgPSByZXF1aXJlKCdwb3VjaGRiLWNvbGxhdGUnKTtcbnZhciBUYXNrUXVldWUgPSByZXF1aXJlKCcuL3Rhc2txdWV1ZScpO1xudmFyIGNvbGxhdGUgPSBwb3VjaENvbGxhdGUuY29sbGF0ZTtcbnZhciB0b0luZGV4YWJsZVN0cmluZyA9IHBvdWNoQ29sbGF0ZS50b0luZGV4YWJsZVN0cmluZztcbnZhciBub3JtYWxpemVLZXkgPSBwb3VjaENvbGxhdGUubm9ybWFsaXplS2V5O1xudmFyIGNyZWF0ZVZpZXcgPSByZXF1aXJlKCcuL2NyZWF0ZS12aWV3Jyk7XG52YXIgbG9nO1xuLyogaXN0YW5idWwgaWdub3JlIGVsc2UgKi9cbmlmICgodHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnKSAmJiAodHlwZW9mIGNvbnNvbGUubG9nID09PSAnZnVuY3Rpb24nKSkge1xuICBsb2cgPSBGdW5jdGlvbi5wcm90b3R5cGUuYmluZC5jYWxsKGNvbnNvbGUubG9nLCBjb25zb2xlKTtcbn0gZWxzZSB7XG4gIGxvZyA9IGZ1bmN0aW9uICgpIHt9O1xufVxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscycpO1xudmFyIFByb21pc2UgPSB1dGlscy5Qcm9taXNlO1xudmFyIHBlcnNpc3RlbnRRdWV1ZXMgPSB7fTtcbnZhciB0ZW1wVmlld1F1ZXVlID0gbmV3IFRhc2tRdWV1ZSgpO1xudmFyIENIQU5HRVNfQkFUQ0hfU0laRSA9IDUwO1xuXG5mdW5jdGlvbiBRdWVyeVBhcnNlRXJyb3IobWVzc2FnZSkge1xuICB0aGlzLnN0YXR1cyA9IDQwMDtcbiAgdGhpcy5uYW1lID0gJ3F1ZXJ5X3BhcnNlX2Vycm9yJztcbiAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcbiAgdGhpcy5lcnJvciA9IHRydWU7XG4gIHRyeSB7XG4gICAgRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UodGhpcywgUXVlcnlQYXJzZUVycm9yKTtcbiAgfSBjYXRjaCAoZSkge31cbn1cblxudXRpbHMuaW5oZXJpdHMoUXVlcnlQYXJzZUVycm9yLCBFcnJvcik7XG5cbmZ1bmN0aW9uIE5vdEZvdW5kRXJyb3IobWVzc2FnZSkge1xuICB0aGlzLnN0YXR1cyA9IDQwNDtcbiAgdGhpcy5uYW1lID0gJ25vdF9mb3VuZCc7XG4gIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XG4gIHRoaXMuZXJyb3IgPSB0cnVlO1xuICB0cnkge1xuICAgIEVycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsIE5vdEZvdW5kRXJyb3IpO1xuICB9IGNhdGNoIChlKSB7fVxufVxuXG51dGlscy5pbmhlcml0cyhOb3RGb3VuZEVycm9yLCBFcnJvcik7XG5cbmZ1bmN0aW9uIHBhcnNlVmlld05hbWUobmFtZSkge1xuICAvLyBjYW4gYmUgZWl0aGVyICdkZG9jbmFtZS92aWV3bmFtZScgb3IganVzdCAndmlld25hbWUnXG4gIC8vICh3aGVyZSB0aGUgZGRvYyBuYW1lIGlzIHRoZSBzYW1lKVxuICByZXR1cm4gbmFtZS5pbmRleE9mKCcvJykgPT09IC0xID8gW25hbWUsIG5hbWVdIDogbmFtZS5zcGxpdCgnLycpO1xufVxuXG5mdW5jdGlvbiBpc0dlbk9uZShjaGFuZ2VzKSB7XG4gIC8vIG9ubHkgcmV0dXJuIHRydWUgaWYgdGhlIGN1cnJlbnQgY2hhbmdlIGlzIDEtXG4gIC8vIGFuZCB0aGVyZSBhcmUgbm8gb3RoZXIgbGVhZnNcbiAgcmV0dXJuIGNoYW5nZXMubGVuZ3RoID09PSAxICYmIC9eMS0vLnRlc3QoY2hhbmdlc1swXS5yZXYpO1xufVxuXG5mdW5jdGlvbiBzb3J0QnlLZXlUaGVuVmFsdWUoeCwgeSkge1xuICB2YXIga2V5Q29tcGFyZSA9IGNvbGxhdGUoeC5rZXksIHkua2V5KTtcbiAgcmV0dXJuIGtleUNvbXBhcmUgIT09IDAgPyBrZXlDb21wYXJlIDogY29sbGF0ZSh4LnZhbHVlLCB5LnZhbHVlKTtcbn1cblxuZnVuY3Rpb24gc2xpY2VSZXN1bHRzKHJlc3VsdHMsIGxpbWl0LCBza2lwKSB7XG4gIHNraXAgPSBza2lwIHx8IDA7XG4gIGlmICh0eXBlb2YgbGltaXQgPT09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIHJlc3VsdHMuc2xpY2Uoc2tpcCwgbGltaXQgKyBza2lwKTtcbiAgfSBlbHNlIGlmIChza2lwID4gMCkge1xuICAgIHJldHVybiByZXN1bHRzLnNsaWNlKHNraXApO1xuICB9XG4gIHJldHVybiByZXN1bHRzO1xufVxuXG5mdW5jdGlvbiByb3dUb0RvY0lkKHJvdykge1xuICB2YXIgdmFsID0gcm93LnZhbHVlO1xuICAvLyBVc2VycyBjYW4gZXhwbGljaXRseSBzcGVjaWZ5IGEgam9pbmVkIGRvYyBfaWQsIG9yIGl0XG4gIC8vIGRlZmF1bHRzIHRvIHRoZSBkb2MgX2lkIHRoYXQgZW1pdHRlZCB0aGUga2V5L3ZhbHVlLlxuICB2YXIgZG9jSWQgPSAodmFsICYmIHR5cGVvZiB2YWwgPT09ICdvYmplY3QnICYmIHZhbC5faWQpIHx8IHJvdy5pZDtcbiAgcmV0dXJuIGRvY0lkO1xufVxuXG5mdW5jdGlvbiBlbWl0RXJyb3IoZGIsIGUpIHtcbiAgdHJ5IHtcbiAgICBkYi5lbWl0KCdlcnJvcicsIGUpO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBjb25zb2xlLmVycm9yKFxuICAgICAgJ1RoZSB1c2VyXFwncyBtYXAvcmVkdWNlIGZ1bmN0aW9uIHRocmV3IGFuIHVuY2F1Z2h0IGVycm9yLlxcbicgK1xuICAgICAgJ1lvdSBjYW4gZGVidWcgdGhpcyBlcnJvciBieSBkb2luZzpcXG4nICtcbiAgICAgICdteURhdGFiYXNlLm9uKFxcJ2Vycm9yXFwnLCBmdW5jdGlvbiAoZXJyKSB7IGRlYnVnZ2VyOyB9KTtcXG4nICtcbiAgICAgICdQbGVhc2UgZG91YmxlLWNoZWNrIHlvdXIgbWFwL3JlZHVjZSBmdW5jdGlvbi4nKTtcbiAgICBjb25zb2xlLmVycm9yKGUpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHRyeUNvZGUoZGIsIGZ1biwgYXJncykge1xuICAvLyBlbWl0IGFuIGV2ZW50IGlmIHRoZXJlIHdhcyBhbiBlcnJvciB0aHJvd24gYnkgYSBtYXAvcmVkdWNlIGZ1bmN0aW9uLlxuICAvLyBwdXR0aW5nIHRyeS9jYXRjaGVzIGluIGEgc2luZ2xlIGZ1bmN0aW9uIGFsc28gYXZvaWRzIGRlb3B0aW1pemF0aW9ucy5cbiAgdHJ5IHtcbiAgICByZXR1cm4ge1xuICAgICAgb3V0cHV0IDogZnVuLmFwcGx5KG51bGwsIGFyZ3MpXG4gICAgfTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGVtaXRFcnJvcihkYiwgZSk7XG4gICAgcmV0dXJuIHtlcnJvcjogZX07XG4gIH1cbn1cblxuZnVuY3Rpb24gY2hlY2tRdWVyeVBhcnNlRXJyb3Iob3B0aW9ucywgZnVuKSB7XG4gIHZhciBzdGFydGtleU5hbWUgPSBvcHRpb25zLmRlc2NlbmRpbmcgPyAnZW5ka2V5JyA6ICdzdGFydGtleSc7XG4gIHZhciBlbmRrZXlOYW1lID0gb3B0aW9ucy5kZXNjZW5kaW5nID8gJ3N0YXJ0a2V5JyA6ICdlbmRrZXknO1xuXG4gIGlmICh0eXBlb2Ygb3B0aW9uc1tzdGFydGtleU5hbWVdICE9PSAndW5kZWZpbmVkJyAmJlxuICAgIHR5cGVvZiBvcHRpb25zW2VuZGtleU5hbWVdICE9PSAndW5kZWZpbmVkJyAmJlxuICAgIGNvbGxhdGUob3B0aW9uc1tzdGFydGtleU5hbWVdLCBvcHRpb25zW2VuZGtleU5hbWVdKSA+IDApIHtcbiAgICB0aHJvdyBuZXcgUXVlcnlQYXJzZUVycm9yKCdObyByb3dzIGNhbiBtYXRjaCB5b3VyIGtleSByYW5nZSwgcmV2ZXJzZSB5b3VyICcgK1xuICAgICdzdGFydF9rZXkgYW5kIGVuZF9rZXkgb3Igc2V0IHtkZXNjZW5kaW5nIDogdHJ1ZX0nKTtcbiAgfSBlbHNlIGlmIChmdW4ucmVkdWNlICYmIG9wdGlvbnMucmVkdWNlICE9PSBmYWxzZSkge1xuICAgIGlmIChvcHRpb25zLmluY2x1ZGVfZG9jcykge1xuICAgICAgdGhyb3cgbmV3IFF1ZXJ5UGFyc2VFcnJvcigne2luY2x1ZGVfZG9jczp0cnVlfSBpcyBpbnZhbGlkIGZvciByZWR1Y2UnKTtcbiAgICB9IGVsc2UgaWYgKG9wdGlvbnMua2V5cyAmJiBvcHRpb25zLmtleXMubGVuZ3RoID4gMSAmJlxuICAgICAgIW9wdGlvbnMuZ3JvdXAgJiYgIW9wdGlvbnMuZ3JvdXBfbGV2ZWwpIHtcbiAgICAgIHRocm93IG5ldyBRdWVyeVBhcnNlRXJyb3IoJ011bHRpLWtleSBmZXRjaGVzIGZvciByZWR1Y2Ugdmlld3MgbXVzdCB1c2Uge2dyb3VwOiB0cnVlfScpO1xuICAgIH1cbiAgfVxuICBpZiAob3B0aW9ucy5ncm91cF9sZXZlbCkge1xuICAgIGlmICh0eXBlb2Ygb3B0aW9ucy5ncm91cF9sZXZlbCAhPT0gJ251bWJlcicpIHtcbiAgICAgIHRocm93IG5ldyBRdWVyeVBhcnNlRXJyb3IoJ0ludmFsaWQgdmFsdWUgZm9yIGludGVnZXI6IFwiJyArIG9wdGlvbnMuZ3JvdXBfbGV2ZWwgKyAnXCInKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuZ3JvdXBfbGV2ZWwgPCAwKSB7XG4gICAgICB0aHJvdyBuZXcgUXVlcnlQYXJzZUVycm9yKCdJbnZhbGlkIHZhbHVlIGZvciBwb3NpdGl2ZSBpbnRlZ2VyOiAnICtcbiAgICAgICdcIicgKyBvcHRpb25zLmdyb3VwX2xldmVsICsgJ1wiJyk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGRlZmF1bHRzVG8odmFsdWUpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uIChyZWFzb24pIHtcbiAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgZWxzZSAqL1xuICAgIGlmIChyZWFzb24uc3RhdHVzID09PSA0MDQpIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgcmVhc29uO1xuICAgIH1cbiAgfTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlSW5kZXhlcihkZWYpIHtcblxuICB2YXIgcGx1Z2luTmFtZSA9IGRlZi5uYW1lO1xuICB2YXIgbWFwcGVyID0gZGVmLm1hcHBlcjtcbiAgdmFyIHJlZHVjZXIgPSBkZWYucmVkdWNlcjtcbiAgdmFyIGRkb2NWYWxpZGF0b3IgPSBkZWYuZGRvY1ZhbGlkYXRvcjtcblxuXG4gIC8vIHJldHVybnMgYSBwcm9taXNlIGZvciBhIGxpc3Qgb2YgZG9jcyB0byB1cGRhdGUsIGJhc2VkIG9uIHRoZSBpbnB1dCBkb2NJZC5cbiAgLy8gdGhlIG9yZGVyIGRvZXNuJ3QgbWF0dGVyLCBiZWNhdXNlIHBvc3QtMy4yLjAsIGJ1bGtEb2NzXG4gIC8vIGlzIGFuIGF0b21pYyBvcGVyYXRpb24gaW4gYWxsIHRocmVlIGFkYXB0ZXJzLlxuICBmdW5jdGlvbiBnZXREb2NzVG9QZXJzaXN0KGRvY0lkLCB2aWV3LCBkb2NJZHNUb0NoYW5nZXNBbmRFbWl0cykge1xuICAgIHZhciBtZXRhRG9jSWQgPSAnX2xvY2FsL2RvY18nICsgZG9jSWQ7XG4gICAgdmFyIGRlZmF1bHRNZXRhRG9jID0ge19pZDogbWV0YURvY0lkLCBrZXlzOiBbXX07XG4gICAgdmFyIGRvY0RhdGEgPSBkb2NJZHNUb0NoYW5nZXNBbmRFbWl0c1tkb2NJZF07XG4gICAgdmFyIGluZGV4YWJsZUtleXNUb0tleVZhbHVlcyA9IGRvY0RhdGEuaW5kZXhhYmxlS2V5c1RvS2V5VmFsdWVzO1xuICAgIHZhciBjaGFuZ2VzID0gZG9jRGF0YS5jaGFuZ2VzO1xuXG4gICAgZnVuY3Rpb24gZ2V0TWV0YURvYygpIHtcbiAgICAgIGlmIChpc0dlbk9uZShjaGFuZ2VzKSkge1xuICAgICAgICAvLyBnZW5lcmF0aW9uIDEsIHNvIHdlIGNhbiBzYWZlbHkgYXNzdW1lIGluaXRpYWwgc3RhdGVcbiAgICAgICAgLy8gZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnMgKGF2b2lkcyB1bm5lY2Vzc2FyeSBHRVRzKVxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGRlZmF1bHRNZXRhRG9jKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB2aWV3LmRiLmdldChtZXRhRG9jSWQpLmNhdGNoKGRlZmF1bHRzVG8oZGVmYXVsdE1ldGFEb2MpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRLZXlWYWx1ZURvY3MobWV0YURvYykge1xuICAgICAgaWYgKCFtZXRhRG9jLmtleXMubGVuZ3RoKSB7XG4gICAgICAgIC8vIG5vIGtleXMsIG5vIG5lZWQgZm9yIGEgbG9va3VwXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoe3Jvd3M6IFtdfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdmlldy5kYi5hbGxEb2NzKHtcbiAgICAgICAga2V5czogbWV0YURvYy5rZXlzLFxuICAgICAgICBpbmNsdWRlX2RvY3M6IHRydWVcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHByb2Nlc3NLdkRvY3MobWV0YURvYywga3ZEb2NzUmVzKSB7XG4gICAgICB2YXIga3ZEb2NzID0gW107XG4gICAgICB2YXIgb2xkS2V5c01hcCA9IHt9O1xuXG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0ga3ZEb2NzUmVzLnJvd3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgdmFyIHJvdyA9IGt2RG9jc1Jlcy5yb3dzW2ldO1xuICAgICAgICB2YXIgZG9jID0gcm93LmRvYztcbiAgICAgICAgaWYgKCFkb2MpIHsgLy8gZGVsZXRlZFxuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGt2RG9jcy5wdXNoKGRvYyk7XG4gICAgICAgIG9sZEtleXNNYXBbZG9jLl9pZF0gPSB0cnVlO1xuICAgICAgICBkb2MuX2RlbGV0ZWQgPSAhaW5kZXhhYmxlS2V5c1RvS2V5VmFsdWVzW2RvYy5faWRdO1xuICAgICAgICBpZiAoIWRvYy5fZGVsZXRlZCkge1xuICAgICAgICAgIHZhciBrZXlWYWx1ZSA9IGluZGV4YWJsZUtleXNUb0tleVZhbHVlc1tkb2MuX2lkXTtcbiAgICAgICAgICBpZiAoJ3ZhbHVlJyBpbiBrZXlWYWx1ZSkge1xuICAgICAgICAgICAgZG9jLnZhbHVlID0ga2V5VmFsdWUudmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHZhciBuZXdLZXlzID0gT2JqZWN0LmtleXMoaW5kZXhhYmxlS2V5c1RvS2V5VmFsdWVzKTtcbiAgICAgIG5ld0tleXMuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgIGlmICghb2xkS2V5c01hcFtrZXldKSB7XG4gICAgICAgICAgLy8gbmV3IGRvY1xuICAgICAgICAgIHZhciBrdkRvYyA9IHtcbiAgICAgICAgICAgIF9pZDoga2V5XG4gICAgICAgICAgfTtcbiAgICAgICAgICB2YXIga2V5VmFsdWUgPSBpbmRleGFibGVLZXlzVG9LZXlWYWx1ZXNba2V5XTtcbiAgICAgICAgICBpZiAoJ3ZhbHVlJyBpbiBrZXlWYWx1ZSkge1xuICAgICAgICAgICAga3ZEb2MudmFsdWUgPSBrZXlWYWx1ZS52YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAga3ZEb2NzLnB1c2goa3ZEb2MpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIG1ldGFEb2Mua2V5cyA9IHV0aWxzLnVuaXEobmV3S2V5cy5jb25jYXQobWV0YURvYy5rZXlzKSk7XG4gICAgICBrdkRvY3MucHVzaChtZXRhRG9jKTtcblxuICAgICAgcmV0dXJuIGt2RG9jcztcbiAgICB9XG5cbiAgICByZXR1cm4gZ2V0TWV0YURvYygpLnRoZW4oZnVuY3Rpb24gKG1ldGFEb2MpIHtcbiAgICAgIHJldHVybiBnZXRLZXlWYWx1ZURvY3MobWV0YURvYykudGhlbihmdW5jdGlvbiAoa3ZEb2NzUmVzKSB7XG4gICAgICAgIHJldHVybiBwcm9jZXNzS3ZEb2NzKG1ldGFEb2MsIGt2RG9jc1Jlcyk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIHVwZGF0ZXMgYWxsIGVtaXR0ZWQga2V5L3ZhbHVlIGRvY3MgYW5kIG1ldGFEb2NzIGluIHRoZSBtcnZpZXcgZGF0YWJhc2VcbiAgLy8gZm9yIHRoZSBnaXZlbiBiYXRjaCBvZiBkb2N1bWVudHMgZnJvbSB0aGUgc291cmNlIGRhdGFiYXNlXG4gIGZ1bmN0aW9uIHNhdmVLZXlWYWx1ZXModmlldywgZG9jSWRzVG9DaGFuZ2VzQW5kRW1pdHMsIHNlcSkge1xuICAgIHZhciBzZXFEb2NJZCA9ICdfbG9jYWwvbGFzdFNlcSc7XG4gICAgcmV0dXJuIHZpZXcuZGIuZ2V0KHNlcURvY0lkKVxuICAgIC5jYXRjaChkZWZhdWx0c1RvKHtfaWQ6IHNlcURvY0lkLCBzZXE6IDB9KSlcbiAgICAudGhlbihmdW5jdGlvbiAobGFzdFNlcURvYykge1xuICAgICAgdmFyIGRvY0lkcyA9IE9iamVjdC5rZXlzKGRvY0lkc1RvQ2hhbmdlc0FuZEVtaXRzKTtcbiAgICAgIHJldHVybiBQcm9taXNlLmFsbChkb2NJZHMubWFwKGZ1bmN0aW9uIChkb2NJZCkge1xuICAgICAgICByZXR1cm4gZ2V0RG9jc1RvUGVyc2lzdChkb2NJZCwgdmlldywgZG9jSWRzVG9DaGFuZ2VzQW5kRW1pdHMpO1xuICAgICAgfSkpLnRoZW4oZnVuY3Rpb24gKGxpc3RPZkRvY3NUb1BlcnNpc3QpIHtcbiAgICAgICAgdmFyIGRvY3NUb1BlcnNpc3QgPSB1dGlscy5mbGF0dGVuKGxpc3RPZkRvY3NUb1BlcnNpc3QpO1xuICAgICAgICBsYXN0U2VxRG9jLnNlcSA9IHNlcTtcbiAgICAgICAgZG9jc1RvUGVyc2lzdC5wdXNoKGxhc3RTZXFEb2MpO1xuICAgICAgICAvLyB3cml0ZSBhbGwgZG9jcyBpbiBhIHNpbmdsZSBvcGVyYXRpb24sIHVwZGF0ZSB0aGUgc2VxIG9uY2VcbiAgICAgICAgcmV0dXJuIHZpZXcuZGIuYnVsa0RvY3Moe2RvY3MgOiBkb2NzVG9QZXJzaXN0fSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGdldFF1ZXVlKHZpZXcpIHtcbiAgICB2YXIgdmlld05hbWUgPSB0eXBlb2YgdmlldyA9PT0gJ3N0cmluZycgPyB2aWV3IDogdmlldy5uYW1lO1xuICAgIHZhciBxdWV1ZSA9IHBlcnNpc3RlbnRRdWV1ZXNbdmlld05hbWVdO1xuICAgIGlmICghcXVldWUpIHtcbiAgICAgIHF1ZXVlID0gcGVyc2lzdGVudFF1ZXVlc1t2aWV3TmFtZV0gPSBuZXcgVGFza1F1ZXVlKCk7XG4gICAgfVxuICAgIHJldHVybiBxdWV1ZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZVZpZXcodmlldykge1xuICAgIHJldHVybiB1dGlscy5zZXF1ZW50aWFsaXplKGdldFF1ZXVlKHZpZXcpLCBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gdXBkYXRlVmlld0luUXVldWUodmlldyk7XG4gICAgfSkoKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZVZpZXdJblF1ZXVlKHZpZXcpIHtcbiAgICAvLyBiaW5kIHRoZSBlbWl0IGZ1bmN0aW9uIG9uY2VcbiAgICB2YXIgbWFwUmVzdWx0cztcbiAgICB2YXIgZG9jO1xuXG4gICAgZnVuY3Rpb24gZW1pdChrZXksIHZhbHVlKSB7XG4gICAgICB2YXIgb3V0cHV0ID0ge2lkOiBkb2MuX2lkLCBrZXk6IG5vcm1hbGl6ZUtleShrZXkpfTtcbiAgICAgIC8vIERvbid0IGV4cGxpY2l0bHkgc3RvcmUgdGhlIHZhbHVlIHVubGVzcyBpdCdzIGRlZmluZWQgYW5kIG5vbi1udWxsLlxuICAgICAgLy8gVGhpcyBzYXZlcyBvbiBzdG9yYWdlIHNwYWNlLCBiZWNhdXNlIG9mdGVuIHBlb3BsZSBkb24ndCB1c2UgaXQuXG4gICAgICBpZiAodHlwZW9mIHZhbHVlICE9PSAndW5kZWZpbmVkJyAmJiB2YWx1ZSAhPT0gbnVsbCkge1xuICAgICAgICBvdXRwdXQudmFsdWUgPSBub3JtYWxpemVLZXkodmFsdWUpO1xuICAgICAgfVxuICAgICAgbWFwUmVzdWx0cy5wdXNoKG91dHB1dCk7XG4gICAgfVxuXG4gICAgdmFyIG1hcEZ1biA9IG1hcHBlcih2aWV3Lm1hcEZ1biwgZW1pdCk7XG5cbiAgICB2YXIgY3VycmVudFNlcSA9IHZpZXcuc2VxIHx8IDA7XG5cbiAgICBmdW5jdGlvbiBwcm9jZXNzQ2hhbmdlKGRvY0lkc1RvQ2hhbmdlc0FuZEVtaXRzLCBzZXEpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBzYXZlS2V5VmFsdWVzKHZpZXcsIGRvY0lkc1RvQ2hhbmdlc0FuZEVtaXRzLCBzZXEpO1xuICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgcXVldWUgPSBuZXcgVGFza1F1ZXVlKCk7XG5cbiAgICByZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24gKHJlc29sdmUsIHJlamVjdCkge1xuXG4gICAgICBmdW5jdGlvbiBjb21wbGV0ZSgpIHtcbiAgICAgICAgcXVldWUuZmluaXNoKCkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgdmlldy5zZXEgPSBjdXJyZW50U2VxO1xuICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIHByb2Nlc3NOZXh0QmF0Y2goKSB7XG4gICAgICAgIHZpZXcuc291cmNlREIuY2hhbmdlcyh7XG4gICAgICAgICAgY29uZmxpY3RzOiB0cnVlLFxuICAgICAgICAgIGluY2x1ZGVfZG9jczogdHJ1ZSxcbiAgICAgICAgICBzdHlsZTogJ2FsbF9kb2NzJyxcbiAgICAgICAgICBzaW5jZTogY3VycmVudFNlcSxcbiAgICAgICAgICBsaW1pdDogQ0hBTkdFU19CQVRDSF9TSVpFXG4gICAgICAgIH0pLm9uKCdjb21wbGV0ZScsIGZ1bmN0aW9uIChyZXNwb25zZSkge1xuICAgICAgICAgIHZhciByZXN1bHRzID0gcmVzcG9uc2UucmVzdWx0cztcbiAgICAgICAgICBpZiAoIXJlc3VsdHMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29tcGxldGUoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdmFyIGRvY0lkc1RvQ2hhbmdlc0FuZEVtaXRzID0ge307XG4gICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSByZXN1bHRzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgdmFyIGNoYW5nZSA9IHJlc3VsdHNbaV07XG4gICAgICAgICAgICBpZiAoY2hhbmdlLmRvYy5faWRbMF0gIT09ICdfJykge1xuICAgICAgICAgICAgICBtYXBSZXN1bHRzID0gW107XG4gICAgICAgICAgICAgIGRvYyA9IGNoYW5nZS5kb2M7XG5cbiAgICAgICAgICAgICAgaWYgKCFkb2MuX2RlbGV0ZWQpIHtcbiAgICAgICAgICAgICAgICB0cnlDb2RlKHZpZXcuc291cmNlREIsIG1hcEZ1biwgW2RvY10pO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIG1hcFJlc3VsdHMuc29ydChzb3J0QnlLZXlUaGVuVmFsdWUpO1xuXG4gICAgICAgICAgICAgIHZhciBpbmRleGFibGVLZXlzVG9LZXlWYWx1ZXMgPSB7fTtcbiAgICAgICAgICAgICAgdmFyIGxhc3RLZXk7XG4gICAgICAgICAgICAgIGZvciAodmFyIGogPSAwLCBqbCA9IG1hcFJlc3VsdHMubGVuZ3RoOyBqIDwgamw7IGorKykge1xuICAgICAgICAgICAgICAgIHZhciBvYmogPSBtYXBSZXN1bHRzW2pdO1xuICAgICAgICAgICAgICAgIHZhciBjb21wbGV4S2V5ID0gW29iai5rZXksIG9iai5pZF07XG4gICAgICAgICAgICAgICAgaWYgKGNvbGxhdGUob2JqLmtleSwgbGFzdEtleSkgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgIGNvbXBsZXhLZXkucHVzaChqKTsgLy8gZHVwIGtleStpZCwgc28gbWFrZSBpdCB1bmlxdWVcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdmFyIGluZGV4YWJsZUtleSA9IHRvSW5kZXhhYmxlU3RyaW5nKGNvbXBsZXhLZXkpO1xuICAgICAgICAgICAgICAgIGluZGV4YWJsZUtleXNUb0tleVZhbHVlc1tpbmRleGFibGVLZXldID0gb2JqO1xuICAgICAgICAgICAgICAgIGxhc3RLZXkgPSBvYmoua2V5O1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGRvY0lkc1RvQ2hhbmdlc0FuZEVtaXRzW2NoYW5nZS5kb2MuX2lkXSA9IHtcbiAgICAgICAgICAgICAgICBpbmRleGFibGVLZXlzVG9LZXlWYWx1ZXM6IGluZGV4YWJsZUtleXNUb0tleVZhbHVlcyxcbiAgICAgICAgICAgICAgICBjaGFuZ2VzOiBjaGFuZ2UuY2hhbmdlc1xuICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY3VycmVudFNlcSA9IGNoYW5nZS5zZXE7XG4gICAgICAgICAgfVxuICAgICAgICAgIHF1ZXVlLmFkZChwcm9jZXNzQ2hhbmdlKGRvY0lkc1RvQ2hhbmdlc0FuZEVtaXRzLCBjdXJyZW50U2VxKSk7XG4gICAgICAgICAgaWYgKHJlc3VsdHMubGVuZ3RoIDwgQ0hBTkdFU19CQVRDSF9TSVpFKSB7XG4gICAgICAgICAgICByZXR1cm4gY29tcGxldGUoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHByb2Nlc3NOZXh0QmF0Y2goKTtcbiAgICAgICAgfSkub24oJ2Vycm9yJywgb25FcnJvcik7XG4gICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgIGZ1bmN0aW9uIG9uRXJyb3IoZXJyKSB7XG4gICAgICAgICAgcmVqZWN0KGVycik7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcHJvY2Vzc05leHRCYXRjaCgpO1xuICAgIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gcmVkdWNlVmlldyh2aWV3LCByZXN1bHRzLCBvcHRpb25zKSB7XG4gICAgaWYgKG9wdGlvbnMuZ3JvdXBfbGV2ZWwgPT09IDApIHtcbiAgICAgIGRlbGV0ZSBvcHRpb25zLmdyb3VwX2xldmVsO1xuICAgIH1cblxuICAgIHZhciBzaG91bGRHcm91cCA9IG9wdGlvbnMuZ3JvdXAgfHwgb3B0aW9ucy5ncm91cF9sZXZlbDtcblxuICAgIHZhciByZWR1Y2VGdW4gPSByZWR1Y2VyKHZpZXcucmVkdWNlRnVuKTtcblxuICAgIHZhciBncm91cHMgPSBbXTtcbiAgICB2YXIgbHZsID0gb3B0aW9ucy5ncm91cF9sZXZlbDtcbiAgICByZXN1bHRzLmZvckVhY2goZnVuY3Rpb24gKGUpIHtcbiAgICAgIHZhciBsYXN0ID0gZ3JvdXBzW2dyb3Vwcy5sZW5ndGggLSAxXTtcbiAgICAgIHZhciBrZXkgPSBzaG91bGRHcm91cCA/IGUua2V5IDogbnVsbDtcblxuICAgICAgLy8gb25seSBzZXQgZ3JvdXBfbGV2ZWwgZm9yIGFycmF5IGtleXNcbiAgICAgIGlmIChzaG91bGRHcm91cCAmJiBBcnJheS5pc0FycmF5KGtleSkgJiYgdHlwZW9mIGx2bCA9PT0gJ251bWJlcicpIHtcbiAgICAgICAga2V5ID0ga2V5Lmxlbmd0aCA+IGx2bCA/IGtleS5zbGljZSgwLCBsdmwpIDoga2V5O1xuICAgICAgfVxuXG4gICAgICBpZiAobGFzdCAmJiBjb2xsYXRlKGxhc3Qua2V5WzBdWzBdLCBrZXkpID09PSAwKSB7XG4gICAgICAgIGxhc3Qua