mixpanel-browser 2.59.0 → 2.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4509,7 +4509,7 @@ var IncrementalSource = /* @__PURE__ */ ((IncrementalSource2) => {
4509
4509
 
4510
4510
  var Config = {
4511
4511
  DEBUG: false,
4512
- LIB_VERSION: '2.59.0'
4512
+ LIB_VERSION: '2.60.0'
4513
4513
  };
4514
4514
 
4515
4515
  // since es6 imports are static and we run unit tests from the console, window won't be defined when importing this file
@@ -8264,7 +8264,7 @@ function getPreviousElementSibling(el) {
8264
8264
  }
8265
8265
  }
8266
8266
 
8267
- function getPropertiesFromElement(el) {
8267
+ function getPropertiesFromElement(el, ev, blockAttrsSet, extraAttrs, allowElementCallback, allowSelectors) {
8268
8268
  var props = {
8269
8269
  '$classes': getClassName(el).split(' '),
8270
8270
  '$tag_name': el.tagName.toLowerCase()
@@ -8274,9 +8274,9 @@ function getPropertiesFromElement(el) {
8274
8274
  props['$id'] = elId;
8275
8275
  }
8276
8276
 
8277
- if (shouldTrackElement(el)) {
8278
- _.each(TRACKED_ATTRS, function(attr) {
8279
- if (el.hasAttribute(attr)) {
8277
+ if (shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors)) {
8278
+ _.each(TRACKED_ATTRS.concat(extraAttrs), function(attr) {
8279
+ if (el.hasAttribute(attr) && !blockAttrsSet[attr]) {
8280
8280
  var attrVal = el.getAttribute(attr);
8281
8281
  if (shouldTrackValue(attrVal)) {
8282
8282
  props['$attr-' + attr] = attrVal;
@@ -8300,8 +8300,21 @@ function getPropertiesFromElement(el) {
8300
8300
  return props;
8301
8301
  }
8302
8302
 
8303
- function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
8304
- blockSelectors = blockSelectors || [];
8303
+ function getPropsForDOMEvent(ev, config) {
8304
+ var allowElementCallback = config.allowElementCallback;
8305
+ var allowSelectors = config.allowSelectors || [];
8306
+ var blockAttrs = config.blockAttrs || [];
8307
+ var blockElementCallback = config.blockElementCallback;
8308
+ var blockSelectors = config.blockSelectors || [];
8309
+ var captureTextContent = config.captureTextContent || false;
8310
+ var captureExtraAttrs = config.captureExtraAttrs || [];
8311
+
8312
+ // convert array to set every time, as the config may have changed
8313
+ var blockAttrsSet = {};
8314
+ _.each(blockAttrs, function(attr) {
8315
+ blockAttrsSet[attr] = true;
8316
+ });
8317
+
8305
8318
  var props = null;
8306
8319
 
8307
8320
  var target = typeof ev.target === 'undefined' ? ev.srcElement : ev.target;
@@ -8309,7 +8322,11 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
8309
8322
  target = target.parentNode;
8310
8323
  }
8311
8324
 
8312
- if (shouldTrackDomEvent(target, ev)) {
8325
+ if (
8326
+ shouldTrackDomEvent(target, ev) &&
8327
+ isElementAllowed(target, ev, allowElementCallback, allowSelectors) &&
8328
+ !isElementBlocked(target, ev, blockElementCallback, blockSelectors)
8329
+ ) {
8313
8330
  var targetElementList = [target];
8314
8331
  var curEl = target;
8315
8332
  while (curEl.parentNode && !isTag(curEl, 'body')) {
@@ -8320,37 +8337,20 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
8320
8337
  var elementsJson = [];
8321
8338
  var href, explicitNoTrack = false;
8322
8339
  _.each(targetElementList, function(el) {
8323
- var shouldTrackEl = shouldTrackElement(el);
8340
+ var shouldTrackDetails = shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors);
8324
8341
 
8325
8342
  // if the element or a parent element is an anchor tag
8326
8343
  // include the href as a property
8327
- if (el.tagName.toLowerCase() === 'a') {
8344
+ if (!blockAttrsSet['href'] && el.tagName.toLowerCase() === 'a') {
8328
8345
  href = el.getAttribute('href');
8329
- href = shouldTrackEl && shouldTrackValue(href) && href;
8346
+ href = shouldTrackDetails && shouldTrackValue(href) && href;
8330
8347
  }
8331
8348
 
8332
- // allow users to programmatically prevent tracking of elements by adding classes such as 'mp-no-track'
8333
- var classes = getClasses(el);
8334
- _.each(OPT_OUT_CLASSES, function(cls) {
8335
- if (classes[cls]) {
8336
- explicitNoTrack = true;
8337
- }
8338
- });
8339
-
8340
- if (!explicitNoTrack) {
8341
- // programmatically prevent tracking of elements that match CSS selectors
8342
- _.each(blockSelectors, function(sel) {
8343
- try {
8344
- if (el['matches'](sel)) {
8345
- explicitNoTrack = true;
8346
- }
8347
- } catch (err) {
8348
- logger.critical('Error while checking selector: ' + sel, err);
8349
- }
8350
- });
8349
+ if (isElementBlocked(el, ev, blockElementCallback, blockSelectors)) {
8350
+ explicitNoTrack = true;
8351
8351
  }
8352
8352
 
8353
- elementsJson.push(getPropertiesFromElement(el));
8353
+ elementsJson.push(getPropertiesFromElement(el, ev, blockAttrsSet, captureExtraAttrs, allowElementCallback, allowSelectors));
8354
8354
  }, this);
8355
8355
 
8356
8356
  if (!explicitNoTrack) {
@@ -8364,9 +8364,17 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
8364
8364
  '$viewportHeight': Math.max(docElement['clientHeight'], win['innerHeight'] || 0),
8365
8365
  '$viewportWidth': Math.max(docElement['clientWidth'], win['innerWidth'] || 0)
8366
8366
  };
8367
+ _.each(captureExtraAttrs, function(attr) {
8368
+ if (!blockAttrsSet[attr] && target.hasAttribute(attr)) {
8369
+ var attrVal = target.getAttribute(attr);
8370
+ if (shouldTrackValue(attrVal)) {
8371
+ props['$el_attr__' + attr] = attrVal;
8372
+ }
8373
+ }
8374
+ });
8367
8375
 
8368
8376
  if (captureTextContent) {
8369
- elementText = getSafeText(target);
8377
+ elementText = getSafeText(target, ev, allowElementCallback, allowSelectors);
8370
8378
  if (elementText && elementText.length) {
8371
8379
  props['$el_text'] = elementText;
8372
8380
  }
@@ -8382,14 +8390,22 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
8382
8390
  }
8383
8391
  // prioritize text content from "real" click target if different from original target
8384
8392
  if (captureTextContent) {
8385
- var elementText = getSafeText(target);
8393
+ var elementText = getSafeText(target, ev, allowElementCallback, allowSelectors);
8386
8394
  if (elementText && elementText.length) {
8387
8395
  props['$el_text'] = elementText;
8388
8396
  }
8389
8397
  }
8390
8398
 
8391
8399
  if (target) {
8392
- var targetProps = getPropertiesFromElement(target);
8400
+ // target may have been recalculated; check allowlists and blocklists again
8401
+ if (
8402
+ !isElementAllowed(target, ev, allowElementCallback, allowSelectors) ||
8403
+ isElementBlocked(target, ev, blockElementCallback, blockSelectors)
8404
+ ) {
8405
+ return null;
8406
+ }
8407
+
8408
+ var targetProps = getPropertiesFromElement(target, ev, blockAttrsSet, captureExtraAttrs, allowElementCallback, allowSelectors);
8393
8409
  props['$target'] = targetProps;
8394
8410
  // pull up more props onto main event props
8395
8411
  props['$el_classes'] = targetProps['$classes'];
@@ -8405,19 +8421,20 @@ function getPropsForDOMEvent(ev, blockSelectors, captureTextContent) {
8405
8421
  }
8406
8422
 
8407
8423
 
8408
- /*
8424
+ /**
8409
8425
  * Get the direct text content of an element, protecting against sensitive data collection.
8410
8426
  * Concats textContent of each of the element's text node children; this avoids potential
8411
8427
  * collection of sensitive data that could happen if we used element.textContent and the
8412
8428
  * element had sensitive child elements, since element.textContent includes child content.
8413
8429
  * Scrubs values that look like they could be sensitive (i.e. cc or ssn number).
8414
8430
  * @param {Element} el - element to get the text of
8431
+ * @param {Array<string>} allowSelectors - CSS selectors for elements that should be included
8415
8432
  * @returns {string} the element's direct text content
8416
8433
  */
8417
- function getSafeText(el) {
8434
+ function getSafeText(el, ev, allowElementCallback, allowSelectors) {
8418
8435
  var elText = '';
8419
8436
 
8420
- if (shouldTrackElement(el) && el.childNodes && el.childNodes.length) {
8437
+ if (shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors) && el.childNodes && el.childNodes.length) {
8421
8438
  _.each(el.childNodes, function(child) {
8422
8439
  if (isTextNode(child) && child.textContent) {
8423
8440
  elText += _.trim(child.textContent)
@@ -8456,6 +8473,75 @@ function guessRealClickTarget(ev) {
8456
8473
  return target;
8457
8474
  }
8458
8475
 
8476
+ function isElementAllowed(el, ev, allowElementCallback, allowSelectors) {
8477
+ if (allowElementCallback) {
8478
+ try {
8479
+ if (!allowElementCallback(el, ev)) {
8480
+ return false;
8481
+ }
8482
+ } catch (err) {
8483
+ logger.critical('Error while checking element in allowElementCallback', err);
8484
+ return false;
8485
+ }
8486
+ }
8487
+
8488
+ if (!allowSelectors.length) {
8489
+ // no allowlist; all elements are fair game
8490
+ return true;
8491
+ }
8492
+
8493
+ for (var i = 0; i < allowSelectors.length; i++) {
8494
+ var sel = allowSelectors[i];
8495
+ try {
8496
+ if (el['matches'](sel)) {
8497
+ return true;
8498
+ }
8499
+ } catch (err) {
8500
+ logger.critical('Error while checking selector: ' + sel, err);
8501
+ }
8502
+ }
8503
+ return false;
8504
+ }
8505
+
8506
+ function isElementBlocked(el, ev, blockElementCallback, blockSelectors) {
8507
+ var i;
8508
+
8509
+ if (blockElementCallback) {
8510
+ try {
8511
+ if (blockElementCallback(el, ev)) {
8512
+ return true;
8513
+ }
8514
+ } catch (err) {
8515
+ logger.critical('Error while checking element in blockElementCallback', err);
8516
+ return true;
8517
+ }
8518
+ }
8519
+
8520
+ if (blockSelectors && blockSelectors.length) {
8521
+ // programmatically prevent tracking of elements that match CSS selectors
8522
+ for (i = 0; i < blockSelectors.length; i++) {
8523
+ var sel = blockSelectors[i];
8524
+ try {
8525
+ if (el['matches'](sel)) {
8526
+ return true;
8527
+ }
8528
+ } catch (err) {
8529
+ logger.critical('Error while checking selector: ' + sel, err);
8530
+ }
8531
+ }
8532
+ }
8533
+
8534
+ // allow users to programmatically prevent tracking of elements by adding default classes such as 'mp-no-track'
8535
+ var classes = getClasses(el);
8536
+ for (i = 0; i < OPT_OUT_CLASSES.length; i++) {
8537
+ if (classes[OPT_OUT_CLASSES[i]]) {
8538
+ return true;
8539
+ }
8540
+ }
8541
+
8542
+ return false;
8543
+ }
8544
+
8459
8545
  /*
8460
8546
  * Check whether a DOM node has nodeType Node.ELEMENT_NODE
8461
8547
  * @param {Node} node - node to check
@@ -8530,11 +8616,16 @@ function shouldTrackDomEvent(el, ev) {
8530
8616
  * Check whether a DOM element should be "tracked" or if it may contain sensitive data
8531
8617
  * using a variety of heuristics.
8532
8618
  * @param {Element} el - element to check
8619
+ * @param {Array<string>} allowSelectors - CSS selectors for elements that should be included
8533
8620
  * @returns {boolean} whether the element should be tracked
8534
8621
  */
8535
- function shouldTrackElement(el) {
8622
+ function shouldTrackElementDetails(el, ev, allowElementCallback, allowSelectors) {
8536
8623
  var i;
8537
8624
 
8625
+ if (!isElementAllowed(el, ev, allowElementCallback, allowSelectors)) {
8626
+ return false;
8627
+ }
8628
+
8538
8629
  for (var curEl = el; curEl.parentNode && !isTag(curEl, 'body'); curEl = curEl.parentNode) {
8539
8630
  var classes = getClasses(curEl);
8540
8631
  for (i = 0; i < SENSITIVE_DATA_CLASSES.length; i++) {
@@ -8624,9 +8715,17 @@ var PAGEVIEW_OPTION_FULL_URL = 'full-url';
8624
8715
  var PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING = 'url-with-path-and-query-string';
8625
8716
  var PAGEVIEW_OPTION_URL_WITH_PATH = 'url-with-path';
8626
8717
 
8718
+ var CONFIG_ALLOW_ELEMENT_CALLBACK = 'allow_element_callback';
8719
+ var CONFIG_ALLOW_SELECTORS = 'allow_selectors';
8720
+ var CONFIG_ALLOW_URL_REGEXES = 'allow_url_regexes';
8721
+ var CONFIG_BLOCK_ATTRS = 'block_attrs';
8722
+ var CONFIG_BLOCK_ELEMENT_CALLBACK = 'block_element_callback';
8627
8723
  var CONFIG_BLOCK_SELECTORS = 'block_selectors';
8628
8724
  var CONFIG_BLOCK_URL_REGEXES = 'block_url_regexes';
8725
+ var CONFIG_CAPTURE_EXTRA_ATTRS = 'capture_extra_attrs';
8629
8726
  var CONFIG_CAPTURE_TEXT_CONTENT = 'capture_text_content';
8727
+ var CONFIG_SCROLL_CAPTURE_ALL = 'scroll_capture_all';
8728
+ var CONFIG_SCROLL_CHECKPOINTS = 'scroll_depth_percent_checkpoints';
8630
8729
  var CONFIG_TRACK_CLICK = 'click';
8631
8730
  var CONFIG_TRACK_INPUT = 'input';
8632
8731
  var CONFIG_TRACK_PAGEVIEW = 'pageview';
@@ -8634,7 +8733,16 @@ var CONFIG_TRACK_SCROLL = 'scroll';
8634
8733
  var CONFIG_TRACK_SUBMIT = 'submit';
8635
8734
 
8636
8735
  var CONFIG_DEFAULTS = {};
8736
+ CONFIG_DEFAULTS[CONFIG_ALLOW_SELECTORS] = [];
8737
+ CONFIG_DEFAULTS[CONFIG_ALLOW_URL_REGEXES] = [];
8738
+ CONFIG_DEFAULTS[CONFIG_BLOCK_ATTRS] = [];
8739
+ CONFIG_DEFAULTS[CONFIG_BLOCK_ELEMENT_CALLBACK] = null;
8740
+ CONFIG_DEFAULTS[CONFIG_BLOCK_SELECTORS] = [];
8741
+ CONFIG_DEFAULTS[CONFIG_BLOCK_URL_REGEXES] = [];
8742
+ CONFIG_DEFAULTS[CONFIG_CAPTURE_EXTRA_ATTRS] = [];
8637
8743
  CONFIG_DEFAULTS[CONFIG_CAPTURE_TEXT_CONTENT] = false;
8744
+ CONFIG_DEFAULTS[CONFIG_SCROLL_CAPTURE_ALL] = false;
8745
+ CONFIG_DEFAULTS[CONFIG_SCROLL_CHECKPOINTS] = [25, 50, 75, 100];
8638
8746
  CONFIG_DEFAULTS[CONFIG_TRACK_CLICK] = true;
8639
8747
  CONFIG_DEFAULTS[CONFIG_TRACK_INPUT] = true;
8640
8748
  CONFIG_DEFAULTS[CONFIG_TRACK_PAGEVIEW] = PAGEVIEW_OPTION_FULL_URL;
@@ -8689,13 +8797,37 @@ Autocapture.prototype.getConfig = function(key) {
8689
8797
  };
8690
8798
 
8691
8799
  Autocapture.prototype.currentUrlBlocked = function() {
8800
+ var i;
8801
+ var currentUrl = _.info.currentUrl();
8802
+
8803
+ var allowUrlRegexes = this.getConfig(CONFIG_ALLOW_URL_REGEXES) || [];
8804
+ if (allowUrlRegexes.length) {
8805
+ // we're using an allowlist, only track if current URL matches
8806
+ var allowed = false;
8807
+ for (i = 0; i < allowUrlRegexes.length; i++) {
8808
+ var allowRegex = allowUrlRegexes[i];
8809
+ try {
8810
+ if (currentUrl.match(allowRegex)) {
8811
+ allowed = true;
8812
+ break;
8813
+ }
8814
+ } catch (err) {
8815
+ logger.critical('Error while checking block URL regex: ' + allowRegex, err);
8816
+ return true;
8817
+ }
8818
+ }
8819
+ if (!allowed) {
8820
+ // wasn't allowed by any regex
8821
+ return true;
8822
+ }
8823
+ }
8824
+
8692
8825
  var blockUrlRegexes = this.getConfig(CONFIG_BLOCK_URL_REGEXES) || [];
8693
8826
  if (!blockUrlRegexes || !blockUrlRegexes.length) {
8694
8827
  return false;
8695
8828
  }
8696
8829
 
8697
- var currentUrl = _.info.currentUrl();
8698
- for (var i = 0; i < blockUrlRegexes.length; i++) {
8830
+ for (i = 0; i < blockUrlRegexes.length; i++) {
8699
8831
  try {
8700
8832
  if (currentUrl.match(blockUrlRegexes[i])) {
8701
8833
  return true;
@@ -8723,11 +8855,15 @@ Autocapture.prototype.trackDomEvent = function(ev, mpEventName) {
8723
8855
  return;
8724
8856
  }
8725
8857
 
8726
- var props = getPropsForDOMEvent(
8727
- ev,
8728
- this.getConfig(CONFIG_BLOCK_SELECTORS),
8729
- this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT)
8730
- );
8858
+ var props = getPropsForDOMEvent(ev, {
8859
+ allowElementCallback: this.getConfig(CONFIG_ALLOW_ELEMENT_CALLBACK),
8860
+ allowSelectors: this.getConfig(CONFIG_ALLOW_SELECTORS),
8861
+ blockAttrs: this.getConfig(CONFIG_BLOCK_ATTRS),
8862
+ blockElementCallback: this.getConfig(CONFIG_BLOCK_ELEMENT_CALLBACK),
8863
+ blockSelectors: this.getConfig(CONFIG_BLOCK_SELECTORS),
8864
+ captureExtraAttrs: this.getConfig(CONFIG_CAPTURE_EXTRA_ATTRS),
8865
+ captureTextContent: this.getConfig(CONFIG_CAPTURE_TEXT_CONTENT)
8866
+ });
8731
8867
  if (props) {
8732
8868
  _.extend(props, DEFAULT_PROPS);
8733
8869
  this.mp.track(mpEventName, props);
@@ -8812,13 +8948,14 @@ Autocapture.prototype.initPageviewTracking = function() {
8812
8948
 
8813
8949
  var currentUrl = _.info.currentUrl();
8814
8950
  var shouldTrack = false;
8951
+ var didPathChange = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
8815
8952
  var trackPageviewOption = this.pageviewTrackingConfig();
8816
8953
  if (trackPageviewOption === PAGEVIEW_OPTION_FULL_URL) {
8817
8954
  shouldTrack = currentUrl !== previousTrackedUrl;
8818
8955
  } else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH_AND_QUERY_STRING) {
8819
8956
  shouldTrack = currentUrl.split('#')[0] !== previousTrackedUrl.split('#')[0];
8820
8957
  } else if (trackPageviewOption === PAGEVIEW_OPTION_URL_WITH_PATH) {
8821
- shouldTrack = currentUrl.split('#')[0].split('?')[0] !== previousTrackedUrl.split('#')[0].split('?')[0];
8958
+ shouldTrack = didPathChange;
8822
8959
  }
8823
8960
 
8824
8961
  if (shouldTrack) {
@@ -8826,6 +8963,10 @@ Autocapture.prototype.initPageviewTracking = function() {
8826
8963
  if (tracked) {
8827
8964
  previousTrackedUrl = currentUrl;
8828
8965
  }
8966
+ if (didPathChange) {
8967
+ this.lastScrollCheckpoint = 0;
8968
+ logger.log('Path change: re-initializing scroll depth checkpoints');
8969
+ }
8829
8970
  }
8830
8971
  }.bind(this)));
8831
8972
  };
@@ -8837,6 +8978,7 @@ Autocapture.prototype.initScrollTracking = function() {
8837
8978
  return;
8838
8979
  }
8839
8980
  logger.log('Initializing scroll tracking');
8981
+ this.lastScrollCheckpoint = 0;
8840
8982
 
8841
8983
  this.listenerScroll = win.addEventListener(EV_SCROLLEND, safewrap(function() {
8842
8984
  if (!this.getConfig(CONFIG_TRACK_SCROLL)) {
@@ -8846,6 +8988,11 @@ Autocapture.prototype.initScrollTracking = function() {
8846
8988
  return;
8847
8989
  }
8848
8990
 
8991
+ var shouldTrack = this.getConfig(CONFIG_SCROLL_CAPTURE_ALL);
8992
+ var scrollCheckpoints = (this.getConfig(CONFIG_SCROLL_CHECKPOINTS) || [])
8993
+ .slice()
8994
+ .sort(function(a, b) { return a - b; });
8995
+
8849
8996
  var scrollTop = win.scrollY;
8850
8997
  var props = _.extend({'$scroll_top': scrollTop}, DEFAULT_PROPS);
8851
8998
  try {
@@ -8853,10 +9000,25 @@ Autocapture.prototype.initScrollTracking = function() {
8853
9000
  var scrollPercentage = Math.round((scrollTop / (scrollHeight - win.innerHeight)) * 100);
8854
9001
  props['$scroll_height'] = scrollHeight;
8855
9002
  props['$scroll_percentage'] = scrollPercentage;
9003
+ if (scrollPercentage > this.lastScrollCheckpoint) {
9004
+ for (var i = 0; i < scrollCheckpoints.length; i++) {
9005
+ var checkpoint = scrollCheckpoints[i];
9006
+ if (
9007
+ scrollPercentage >= checkpoint &&
9008
+ this.lastScrollCheckpoint < checkpoint
9009
+ ) {
9010
+ props['$scroll_checkpoint'] = checkpoint;
9011
+ this.lastScrollCheckpoint = checkpoint;
9012
+ shouldTrack = true;
9013
+ }
9014
+ }
9015
+ }
8856
9016
  } catch (err) {
8857
9017
  logger.critical('Error while calculating scroll percentage', err);
8858
9018
  }
8859
- this.mp.track(MP_EV_SCROLL, props);
9019
+ if (shouldTrack) {
9020
+ this.mp.track(MP_EV_SCROLL, props);
9021
+ }
8860
9022
  }.bind(this)));
8861
9023
  };
8862
9024
 
@@ -10125,8 +10287,12 @@ MixpanelPersistence.prototype._add_to_people_queue = function(queue, data) {
10125
10287
  if (!(k in union_q)) {
10126
10288
  union_q[k] = [];
10127
10289
  }
10128
- // We may send duplicates, the server will dedup them.
10129
- union_q[k] = union_q[k].concat(v);
10290
+ // Prevent duplicate values
10291
+ _.each(v, function(item) {
10292
+ if (!_.include(union_q[k], item)) {
10293
+ union_q[k].push(item);
10294
+ }
10295
+ });
10130
10296
  }
10131
10297
  });
10132
10298
  this._pop_from_people_queue(UNSET_ACTION, q_data);