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