RomeoEnhancer

Ergänzungen für die Romeo-Website

当前为 2021-11-21 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         RomeoEnhancer
// @version      1.8.10
// @author       braveguy (Romeo: braveguy / Gruppe RomeoEnhancer)
// @description  Ergänzungen für die Romeo-Website
// @require      https://code.jquery.com/jquery-3.3.1.min.js
// @include      https://*.romeo.com/*
// @include      https://83.98.143.20/*
// @include      https://www.hunqz.com/*
// @run-at       document-start
// @copyright    braveguy 12.10.2016 / 21.11.2021
// @namespace    https://greasyfork.org/users/139428
// @grant        GM_addStyle
// ==/UserScript==


/**
 * Copyright(c) braveguy (Romeo: braveguy / Gruppe RomeoEnhancer)
 *
 * Änderungen oder die Wiederverwendung von Code von RomeoEnhancer
 * erfordern meine ausdrückliche Zustimmung. Es ist nicht gestattet,
 * geänderte Versionen von RomeoEnhancer zu veröffentlichen.
 *
 * Das Skript wurde mit Tampermonkey in aktuellen Versionen von Safari, Chrome
 * und Firefox getestet. Dennoch geschieht die Benutzung auf eigenes Risiko.
 *
 * ** Datenschutz **
 * RomeoEnhancer enthält keinerlei Code, um Nutzer zu identifizieren
 * oder Daten auszuspähen. Es besteht keinerlei geschäftliches Interesse.
 *
 * Die aktuelle Version von RomeoEnhancer ist verfügbar unter:
 * https://greasyfork.org/scripts/31282-romeoenhancer
 *
 *
 * ****** English version *****
 *
 * Copyright(c) by braveguy (Romeo: braveguy / group RomeoEnhancer)
 *
 * Modifications and/or reuse of RomeoEnhancer code require my explicit consent.
 * You are NOT allowed to publish any changed version of RomeoEnhancer!
 *
 * All code has been tested with Tampermonkey in a recent Safari, Chrome,
 * and Firefox browser. However, the use of this script is at your own risk.
 *
 * ** Privacy **
 * RomeoEnhancer does NOT and never will include any code to identify you
 * or spy on your data. There is no commercial interest.
 *
 * The latest version of RomeoEnhancer is available on:
 * https://greasyfork.org/scripts/31282-romeoenhancer

*/


// ***** GM polyfill *****
if (typeof GM == 'undefined') {
  this.GM = {};
}

if (typeof GM_addStyle == 'undefined') {
  this.GM_addStyle = (aCss) => {
    'use strict';
    let head = document.getElementsByTagName('head')[0];
    if (head) {
      let style = document.createElement('style');
      style.setAttribute('type', 'text/css');
      style.textContent = aCss;
      head.appendChild(style);
      return style;
    }
    return null;
  };
}


// ***** CSS *****

//background colors
let color1 = '', color2 = '', color3 = '', color4 = '', color5 = '', color6 = '', color7 = '', color8 = '', color9 = '';
//localStorage.setItem('REcolorScheme', 'retroBlue')
switch (localStorage.getItem('REcolorScheme')) {
    case 'sexyDark':
        //Romeo default - Sexy Dark
        break;
    case 'lighterGrey':
        color1 = '#1f1f1f', color2 = '#1f1f1f', color3 = '#000', color4 = '#101010', color5 = '#1a1a1a', color6 = '#f0f0f0', color7 = '#cc2d2d', color8 = '#2a2a2a', color9 = '#2a2a2a'; // Lighter Grey
        break;
    case 'retroBlue':
        color1 = '#102c54', color2 = '#102c54', color3 = '#000', color4 = '#101010', color5 = '#122646', color6 = '#f0f0f0', color7 = '#f0f0f0', color8 = 'rgba(255,255,255,.08)', color9 = '#30415d'; // Retro Blue
        break;
    default: //fineGrey
        color1 = '#1a1a1a', color2 = '#171717', color3 = '#000', color4 = '#101010', color5 = '#232323', color6 = '#f0f0f0', color7 = '#cc2d2d', color8 = '#2a2a2a', color9 = '#2a2a2a'; // Fine Grey
        break;
}


GM_addStyle (

    //tweak dark design
    `html.js body, #activity-stream .layer__container, .content-nav__actions, .layer__column--background, .layer__column--detail, #group-preview .layer__container, .profile {background-color:${color1} !important}` +
    `div.js-wrapper section[class^="Section"], div.js-wrapper div[class^="slider_wrapper-"]:before, div.js-wrapper div[class^="slider_wrapper-"]:after {background-color:${color1} !important}` +
    `.ui-navbar--app {background-color:${color2}}` +
    `.listitem--selected > div {background-color:${color9} !important}` +
	`li[class^="stat-bar__item--"] {background-color:${color2}}` +
    `.listresult {background-color:${color2}}` +
    `.listresult:hover, :is(.js-chat, .js-contacts) .reactView > div:hover {background-color:${color8} !important}` +
    `.listresult .list-stat-bar__item, .icon-circular.icon-u {background-color:transparent}` +
    `.js-groups .reactView > button {background-color:${color9} !important}` +
    `:is(.js-post-edit, .js-post-list, #post, #group-post) textarea {background-color:${color4} !important}` +
    `.js-post-edit button[class*="ActionButton"] {background-color:${color1}}` +
    `.js-post-edit div[class*="Wrapper-"] {background-color:${color5} !important}` +
    `.js-post-list div[class^="Container"], :is(#group-post, #post) :is(.js-post, .js-post div[class^="Container"], div.js-comment) {background-color:${color5} !important}` +
    `section.js-main-stage div[class^="Grid-"] div[class*="Wrapper-"], section.js-main-stage div[class^="Grid-"] + div[class^="Wrapper-"] {background-color:${color5} !important}` +
    `.message__text {background-color:${color6}}` +
    `:is(.js-groups, .js-main .js-navigation li) svg[class^="Icon__Svg-sc-"] {color:${color7}}` +

    //bigger text in messages, groups, profiles; wrap long links
    ':is(#messages-list div.reactView, div[class^="TruncateBlock__Content-"]) > p[class^="BaseText-sc-"],' +
    '.profile section.profile__stats section > div > p[class^="BaseText-sc-"] {font-size:.9375rem; line-height:1.375; padding-bottom:.125rem; word-break:break-word}' +

    //fix scroll on larger screens
    '.js-chat .js-scrollable, .Xjs-main .js-sidebar {max-height:1270px !important}' +

	//icons, links
	'a.re-icon {position:relative; top:.1em; font-size:.9em}' +
    '.listresult__infos a.re-icon {top:inherit; font-size:.9rem}' +
    'a.re-idle {color:rgba(255,255,255,.8)}' +
	'a.re-icon:hover, a.re-idle:hover {color:rgba(102,215,255,.8)}' +
    '.touchevents a.re-icon {padding:.25em .5em}' +
    '.touchevents a[class*="Tabbed-nav-link"] span {padding:0 .5em}' +
    'a.re-link {color:#00bdff}' +
    '[class*="hunqz"] a.re-link {color:#fc193c}' +
	'a.re-link-idle {color:#fafafa}' +
    ':is(a.re-link, a.re-link-idle, .js-report-icon svg):hover {color:#66d7ff}' +
    '[class*="hunqz"] :is(a.re-link, a.re-link-idle, a.re-icon, .js-report-icon svg):hover {color:#fd5871}' +

    //filter icon, bookmark name
    '.cmuYcO, .edfjQb, .cpJGzS, .fILOaS {padding-top:.33em!important; border:0!important}' +
    '.re-filter-bookmark-name {position:absolute; right:0}' +
    '.is-filter-collapsed .re-filter-bookmark-name {display:none!important}' +
    '.is-filter-opened .re-filter-options-text, .is-filter-opened div.js-filter-button svg + span + span:not(.re-filter-bookmark-name) {display:none!important}' +

	//text
	'span.re-posts-view {font-family: "Gibson Bold"; font-weight:500; text-transform:uppercase; background-color:transparent; color:#fff; height:auto; cursor:pointer; padding-left:2rem;}' +
	'span.re-list-head, span.re-list-view, span.re-list-load {font-family:"Helvetica Neue",Helvetica,Arial,"Open Sans",sans-serif; text-transform:uppercase; color:rgb(255,255,255,.5); height:auto}' +
	'span.re-list-view, span.re-list-load {font-family: "Gibson Bold"; font-weight:500; color:rgb(250,250,250); cursor:pointer;}' +
	'span.re-list-load:before {display:inline-block; transform:scaleX(-1)}' +

    //expand truncated location names on hover
    '.typo-small.txt-truncate:hover {white-space:normal; word-break:break-all}' +

    //expand headline in big tiles
    '.tile__headline {font-size:.875rem !important; word-break:break-word}' +
    '.tile__headline:hover {white-space:normal}' +

	//more dense list view, more headline text
	'.list-stat-bar__item {width:inherit; color:rgba(255,255,255,.75)}' +
    'blockquote.listresult__quote {white-space:normal; color:rgba(255,255,255,.625)}' +

    //bigger emojis on hover
    'span[class^="formatEmoji_"] {font-size:1.25em; line-height:1em}' +
	'span.emoji:hover, span[class^="formatEmoji_"]:hover, span span[role="img"]:hover {font-size:1.8rem; line-height:1.33rem; margin-left:-.4rem; position:relative; right:-.2rem; padding-bottom:.33rem}' +
    '.message__hover {z-index:-1}' +

    //messenger
    '#messenger .message__content--attachment {max-width:80%}' +
    '#messenger .message--sent .message__content--attachment {max-width:15rem}' +
    '#messenger .message__content a {word-break:break-word}' +
    '#messenger :is(div.js-header-region, div.js-header) div.reactView > div {grid-template-columns:1fr 4fr 1fr}' +
    '#messenger :is(div.js-header-region, div.js-header) div.reactView a > img[style="margin-top: 0.375em;"] {margin-top:0!important}' +
    '#messenger .re-location {font-size:.75rem; font-weight:500; letter-spacing:0; line-height:1.25; text-transform:none}' +
    ':is(.js-chat, .js-contacts, #manage) svg[class*="OnlineStatus__"] {font-size:1em}' +
    ':is(.js-chat, .js-contacts, #manage) svg[class*="OnlineStatus__Sex"] {font-size:1.125em}' +
    '.js-chat .typo-headline-small {font-size:inherit}' +
    '.fQIYNa {font-weight:550}' +
    '.online-favourites__item {margin:0 .475rem !important}' +
    '.online-favourites__itemName {width:4rem; margin:0 -.125rem}' +
    'section.emoji-mart button.emoji-mart-anchor:hover {color:rgba(255,255,255,.5)}' +

    //stream
    'div.stream__content .tile__onlinestate {position:absolute; left:-3px; top:-3px}' +
    'div.stream__content .tile__onlinestate span.icon {display:flex; align-items:center; justify-content:center; background-color:#1f1f1f; border-radius:50%; height:19px; width:19px; margin-top:0!important}' +

	//profile stats, separators, groups tiles, icons
    '.profile div[aria-label] > div[role="figure"] {border-color:rgba(255,255,255,0.33)}' +
    '.profile .re-profile-stats {color:rgba(255,255,255,0.6); font-size:.875rem !important}' +
    //'.Grid--2PNxe .TextContainer--26w7l span[class^="Name-"] {font-size:.875rem; margin-bottom:0; margin-right:0}' +
    //'.Grid--2PNxe .TextContainer--26w7l .js-privacy {margin-left:.25rem}' +
    //'.Grid--2PNxe .TextContainer--26w7l .js-is-official {display:none}' +
    //'.Grid--2PNxe .Container--ZG9VQ {font-size:.825rem; margin-bottom:.15rem}' +
    '.js-report-icon div {margin-left:.25rem}' +
    '.js-report-icon a {border-width:.125rem}' +
    '.js-report-icon svg {font-size:1.75em}' +
    '.profile .js-age-name-location {margin-right: 3.5rem}' +
    '.profile .bg-raise {background:linear-gradient(transparent,rgba(0,0,0,.375))}' +
    '.profile .js-authenticity button {display:flex; align-items:center; flex-direction:columns; justify-content:center}' +
    '.profile .js-authenticity button span {position:absolute; top:19px; font-size:.75rem; font-weight:500; color:rgba(0,0,0,.8)}' +
    '.profile .js-authenticity button span.white {top:18px; color:rgba(250,250,250,1)}' +
    '.profile .js-authenticity svg {filter:none}' +
    '.re-img-count {position:absolute; bottom:.5rem; left:.5rem; display:flex; align-items:center; justify-items:center}' +
    '.re-img-count div {color:rgba(255,255,255,.87); background-color:rgb(18,18,18); border-radius:.125rem; padding:0 .25rem; height:1.125rem; line-height:1rem}' +
    '.profile__image-strip .re-img-count {margin-left:.5rem}' +

    //photo album captions
	'#photos div[class^="Description"] {font-size:.85rem}' +
    '#photos div.js-username + div.txt-quiet {color:rgba(255,255,255,0.5)}' +

    //group tiles
    '.js-members-count > div {background-color:rgba(0,0,0,.66)!important}' +
    //'.re-group-tile > div {background:linear-gradient(transparent,rgba(0,0,0,.375)) !important}' +
    '.re-group-tile > div > p + div {position:absolute; bottom:2rem; left:.5rem}' +
    '.re-group-tile > div > p {font-size:.925rem; width:auto; background:linear-gradient(rgba(0,0,0,.02),rgba(0,0,0,.125),rgba(0,0,0,.02))}' +
    '.re-common-group span.icon-group-members, .re-common-group p:last-child {color:#6ddc00}' +
    '.js-members-count + div > span {margin-bottom:0}' +
    'div[class*="NameAndOfficialBadgeWrapper"] {flex-flow:unset}' +
    '.re-icon-official {display:inline; margin:0 .175rem .175rem 0; vertical-align:middle; height:1.125em; width:1.125em}' +

	//groups
	'.js-date .reactView span {font-size:.85em}' +
	'div.Container--3h4tt div.js-groups > div.pt- {display:none}' +
	'.Content--YvjYm a {overflow-wrap:break-word}' +
    'button.js-show-more.ShowMoreButton--2xOu8.is-hidden {display:block!important}' +
    'div[class^="CommentsArea"] div[class^="TruncateBlock__Content"] {-webkit-line-clamp:unset}' +
    'div[class^="CommentsArea"] div[class^="TruncateBlock__Container"] p button {display:none}' +
    '.js-main .js-sidebar {max-height:inherit !important}' +
    '.js-main .js-sidebar .js-groups {padding-bottom:1rem}' +

    //groups list
    '.re-groups-listitem {display:flex; align-items:center; border:0; border-radius:.25em; padding:.5em; width:100%}' +
    `.re-groups-listitem:hover {background-color:${color8}}` +
    '.re-groups-tile {display:flex; flex-shrink:0; margin-right:1em; background-size:cover; border-radius:50%; height:3em; width:3em}' +
    '.re-groups-entry {flex-grow:1; flex-shrink:1; min-width:0; display:flex; align-items:center}' +
    '.re-groups-text {font-family:"Helvetica Neue",Helvetica,Arial,"Open Sans",sans-serif; font-size:1em; font-weight:500; letter-spacing:.5px; line-height:1.375em; word-break:break-word; margin-right:.25em; display:block; overflow:hidden}' +
    '.re-groups-name {color:rgb(0,163,228); font-weight:500; display:inline-block; overflow:hidden; text-overflow:ellipsis; word-wrap:normal}' +
    '.re-groups-time {color:rgba(250,250,250,.625); font-size:.85em}' +
    '.re-groups-admin {display:flex; align-items:center; color:rgb(0,0,0,.8); background-color:rgb(0,189,255); padding:0 .25rem; border-radius:.25rem; font-size:0.625rem}' +
    '.re-groups-new {display:flex; align-items:center; color:rgb(250,250,250,.8); font-size:0.8em}' +
    '.re-groups-new svg {display:inline-block; height:1em; width:1.125em; vertical-align:middle}' +
    '.re-groups-new svg path {fill:currentcolor}' +

    //travel
    '.re-member-travel, .re-radar-travel, .re-edit-travel {color:#00bdff; text-transform:initial}' +
    '.re-member-travel:hover, .re-radar-travel:hover, .re-edit-travel:hover {color:#66d7ff}' +
    '.re-member-travel.re-selected, .re-radar-travel.re-selected {color:#fff}' +

	//more big tiles per page
	'@media screen and (min-width:55rem) {' +
	'.search-results--big-tiles .search-results__item {padding-bottom:25% !important; width:25% !important}' +
	':is(.is-filter-opened, .is-stream-opened) .search-results--big-tiles .search-results__item {padding-bottom:33.33333% !important; width:33.33333% !important}' +
	'.is-stream-opened .is-filter-opened div.search-results--big-tiles div.search-results__item {padding-bottom:50% !important; width:50% !important} }' +
	'@media screen and (min-width:75rem) {' +
	'.search-results--big-tiles .search-results__item {padding-bottom:20% !important; width:20% !important}' +
	':is(.is-filter-opened, .is-stream-opened) .search-results--big-tiles .search-results__item {padding-bottom:25% !important; width:25% !important}' +
	'.is-stream-opened .is-filter-opened div.search-results--big-tiles div.search-results__item {padding-bottom:33.33333% !important; width:33.33333% !important} }' +
	'@media screen and (min-width:95rem) {' +
	'.search-results--big-tiles .search-results__item {padding-bottom:16.66666% !important; width:16.66666% !important}' +
	':is(.is-filter-opened, .is-stream-opened) .search-results--big-tiles .search-results__item {padding-bottom:20% !important; width:20% !important}' +
	'.is-stream-opened .is-filter-opened div.search-results--big-tiles div.search-results__item {padding-bottom:25% !important; width:25% !important} }' +
	'@media screen and (min-width:120rem) {' +
	'.search-results--big-tiles .search-results__item {padding-bottom:12.5% !important; width:12.5% !important}' +
	':is(.is-filter-opened, .is-stream-opened) .search-results--big-tiles .search-results__item {padding-bottom:16.66666% !important; width:16.66666% !important}' +
	'.is-stream-opened .is-filter-opened div.search-results--big-tiles div.search-results__item {padding-bottom:20% !important; width:20% !important} }' +
	'@media screen and (min-width:140rem) {' +
	'.search-results--big-tiles .search-results__item {padding-bottom:12.5% !important; width:12.5% !important}' +
	':is(.is-filter-opened, .is-stream-opened) .search-results--big-tiles .search-results__item {padding-bottom:12.5% !important; width:12.5% !important}' +
	'.is-stream-opened .is-filter-opened div.search-results--big-tiles div.search-results__item {padding-bottom:16.66666% !important; width:16.66666% !important} }' +


    //*** desktop ***
	'@media screen and (min-width:768px) {' +

    //general
    '.re-mobi {display:none!important}' +

    '}' +


    //*** desktop >= 1024px ***
    '@media screen and (min-width: 1024px) {' +

    //stream
    '.stream {width:18.5rem!important}'+

    '}' +


	//*** mobile ***
	'@media screen and (max-width:767px) {' +

    //general
    '.re-desk {display:none!important}' +

    //tweak dark design
    `.ui-navbar--app, .ui-navbar--app ul, .ui-navbar.content-nav ul {background-color:#000 !important}` +

    //main menu
    'header.js-header {height:4.25rem; padding-bottom:.5rem}' +
    '.layer--nav-primary {bottom:4.25rem}' +

    //stream
    'div.stream__content {top:3.75rem}' +

    //bigger icons
	'a.re-icon {font-size:1em}' +

    //no block icon in message thread
    'div.js-correspondence div.js-header-region div.reactView > div > span > div > a {display:none}' +

    //fix scroll in photo album
    //'.profile-section--gallery .scrollable {max-height:155vw !important}' +
    //'[id^="single-album-"] {max-height:171vw !important}' +

    '}'

);


// ***** Clean up old settings *****
localStorage.removeItem('contactsSelection');
localStorage.removeItem('REgroupPostsView');
localStorage.removeItem('reRatingMax');


// ***** Viewport *****
var mobile = window.matchMedia("(max-width:767px)");


// **************************************************************
// ***** The following function is taken from:
// ***** https://gist.github.com/BrockA
// ***** https://gist.github.com/raw/2625891/waitForKeyElements.js


/*--- waitForKeyElements():  A utility function, for Greasemonkey scripts,
    that detects and handles AJAXed content.

    Usage example:

        waitForKeyElements (
            "div.comments"
            , commentCallbackFunction
        );

        //--- Page-specific function to do what we want when the node is found.
        function commentCallbackFunction (jNode) {
            jNode.text ("This comment changed by waitForKeyElements().");
        }

    IMPORTANT: This function requires your script to have loaded jQuery.
*/
function waitForKeyElements (
selectorTxt,    /* Required: The jQuery selector string that
                        specifies the desired element(s).
                    */
 actionFunction, /* Required: The code to run when elements are
                        found. It is passed a jNode to the matched
                        element.
                    */
 bWaitOnce,      /* Optional: If false, will continue to scan for
                        new elements even after the first match is
                        found.
                    */
 iframeSelector  /* Optional: If set, identifies the iframe to
                        search.
                    */
) {
	var targetNodes, btargetsFound;

	if (typeof iframeSelector == "undefined")
		targetNodes     = $(selectorTxt);
	else
		targetNodes     = $(iframeSelector).contents ()
			.find (selectorTxt);

	if (targetNodes  &&  targetNodes.length > 0) {
		btargetsFound   = true;
		/*--- Found target node(s).  Go through each and act if they
            are new.
        */
		targetNodes.each ( function () {
			var jThis        = $(this);
			var alreadyFound = jThis.data ('alreadyFound')  ||  false;

			if (!alreadyFound) {
				//--- Call the payload function.
				var cancelFound     = actionFunction (jThis);
				if (cancelFound)
					btargetsFound   = false;
				else
					jThis.data ('alreadyFound', true);
			}
		} );
	}
	else {
		btargetsFound   = false;
	}

	//--- Get the timer-control variable for this selector.
	var controlObj      = waitForKeyElements.controlObj  ||  {};
	var controlKey      = selectorTxt.replace (/[^\w]/g, "_");
	var timeControl     = controlObj [controlKey];

	//--- Now set or clear the timer as appropriate.
	if (btargetsFound  &&  bWaitOnce  &&  timeControl) {
		//--- The only condition where we need to clear the timer.
		clearInterval (timeControl);
		delete controlObj [controlKey];
	}
	else {
		//--- Set a timer, if needed.
		if ( ! timeControl ) {
			timeControl = setInterval ( function () {
				waitForKeyElements (    selectorTxt,
									actionFunction,
									bWaitOnce,
									iframeSelector
								   );
			},
									   300
									  );
			controlObj [controlKey] = timeControl;
		}
	}
	waitForKeyElements.controlObj   = controlObj;
}

// ***** end
// **************************************************************


// ***** Set AJAX headers *****
var key0 = window.atob('WC1TZXNzaW9uLUlk');
var key1 = window.atob('WC1BcGktS2V5');
var val1 = window.atob('OEpOdlBiVjNJOUtMaU5xUFNxc2NOVFllZzd1aXd2TUk=');
function ajaxHead(){
	return {[key0]: JSON.parse(localStorage.getItem('PR_SETTINGS:SESSION_ID')), [key1]: val1};
}


// ***** Replace URLs with links *****
// ***** Adopted from https://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links/37687#37687 *****
function linkify(text) {

	//Email addresses
	var pattern1 = /(^|\s|<br>)(([-\w\.\+])+@[-\w]+?(\.[A-Z]{2,6})+)/gim;
	text = text.replace(pattern1, '$1<a href="mailto:$2" class="plain-text-link">$2</a>');

	//URLs starting with http:// or https://
	var pattern2 = /(^|\s|<br>)(https?:\/\/[-\w+&@#\/\(\)%?=~|!:,.;]*[-\w+&@#\/\(\)%=~|])/gim;
	text = text.replace(pattern2, '$1<a target="_blank" href="$2" rel="noreferrer noopener" class="plain-text-link">$2</a>');

	//URLs without http:// or https://
	var pattern3 = /(^|\s|<br>)([-\w]+\.[a-z][-\w+&#\/\(\)%?=~|!:,.;]*[-\w+&#\/\(\)%=~|])/gm;
	text = text.replace(pattern3, '$1<a target="_blank" href="http://$2" rel="noreferrer noopener" class="plain-text-link">$2</a>');

	//keep internal links in same window
	var pattern4 = /(target="_blank" )(href="https?:\/\/(www\.)?((planet)?romeo|hunqz)\.com)/gim;
	text = text.replace(pattern4, '$2');

	return text;
}


// ***** Format date/time *****
function dateTime(timeStamp, dateOnly) {
    // 1s...59s; 1min...59min; hh:mm; gestern hh:mm; tt.mm.jjjj, hh:mm
    var timeNow = new Date();
    var timeNow1 = new Date (timeNow - 1000*60*60*24);
    var timeTag = "";
    if (timeStamp) {
        if (timeNow.toLocaleDateString() == timeStamp.toLocaleDateString()) {
            timeTag = 'heute ' + timeStamp.toLocaleTimeString('de-DE').slice(0,-3);
        } else if (timeNow1.toLocaleDateString() == timeStamp.toLocaleDateString()) {
            timeTag = 'gestern ' + timeStamp.toLocaleTimeString('de-DE').slice(0,-3);
        } else {
            timeTag = dateOnly ? timeStamp.toLocaleDateString('de-DE') : timeStamp.toLocaleString('de-DE').slice(0,-3);
        }
    }
    return timeTag;
}


// ***** Change URL without reloading the page *****
function changeUrl(url) {
	history.pushState({}, document.title, url);
	history.pushState({}, document.title, url);
	history.back();
}


// ***** Open message thread or contact info by profile name *****
// (not working for blocked/blocking/deactivated profiles)
function openByName(baseUrl, profileLink, profileName) {
	var profileType = 'profiles';
	if (profileLink.match(/^\/hunq\//)) {
		profileType = 'hunqz/profiles';
	/*} else if (profileLink.match(/^\/groups?\//)) {
		profileType = 'groups';*/
	}
	$.ajax({url: `/api/v4/${profileType}?pick=items.*.(id,name)&lang=de&length=1&filter[fulltext_search_mode]=EXACT&filter[fulltext]=@${profileName}`,
			headers: ajaxHead()
		   })
	.done(function (data) {
		if (data.items[0] && data.items[0].name == profileName) {
			changeUrl(baseUrl + data.items[0].id);
        } else {
            $.ajax({headers: ajaxHead(), url: `/api/v4/${profileType}/${profileName}/full?lang=de&lookup_type=NAME`})
            .done(function (data) {
                if (data.id) {
                    changeUrl(baseUrl + data.id);
                }
            });
        }
	});
}


// ***** Hide visit *****
function hideVisit(profileId) {
	if (profileId > 0) {
		$.ajax({url: `/api/v4/visits/${profileId}`,
				headers: ajaxHead(),
				method: 'DELETE'
			   })
		.done(function () {
			$('div.profile-topnav__hide').hide();
		})
	}
}


// ***** Search profile id *****
function searchInput(jNode) {
	$('#search a.re-add').remove();
	$(jNode).parent().on('keyup mouseout', function() {
		$('#search a.re-add').off('click').remove();
		if ($(jNode).val().match(/^[1-9]\d{2,8}$/)) {
			$('#search div.js-input').after(
                `<a style="font-size:1rem" class="re-add re-link mr-">Profil-ID ${$(jNode).val()} anzeigen</a>`
			).next('.re-add').click(function() {
				openById($(jNode).val());
				return false;
			});
		}
	});
}


// ***** Open profile by ID *****
function openById(id) {
    $.ajax({headers: ajaxHead(), url: `/api/v4/profiles/${id}?expand=partner&lang=de`})

	.done(function (data) {
		var type = (data.type) ? data.type : '';
		var name = (data.name) ? data.name : '';
        var profileType = 'profile';
        if (type == 'ESCORT') {
            profileType = 'hunq';
        } else if (type == 'CLUB') {
            profileType = 'group';
        }
        changeUrl(`/${profileType}/${name}`);
    })

   	.fail(function (data) {
		changeUrl('/profile/-');
	});
}


// ***** Picture upload month/year *****

//init
var imgTable = [
    0x00000000,0x00000000,0x000076f1,0x0000c0c2,0x000113ac,0x000193c7,0x00022adb,0x0002e59b,0x0003c274,0x0004bdda,0x0005cb8f,0x0006f792, //2003
    0x00083008,0x0009e166,0x000bc399,0x000dc70d,0x000fcad1,0x001219f5,0x0014e794,0x00180a61,0x001b7a83,0x001eeaaa,0x0022a968,0x0026aaf2, //2004
    0x002b9863,0x00313036,0x003679aa,0x003c52ab,0x0042260d,0x00489386,0x004f0bc3,0x00563896,0x005d5713,0x006425db,0x006bc70e,0x0072db1e, //2005
    0x007a330c,0x00827630,0x0089c35c,0x00920af4,0x009ae16c,0x00a3fd57,0x00ad0670,0x00b72f32,0x00c1ea95,0x00cb8a91,0x00d5b890,0x00df6c5b, //2006
    0x00e8faad,0x00f42dc0,0x00fe1ca0,0x0108f04e,0x01140217,0x011feaa7,0x012b87da,0x0137a036,0x014368b3,0x014eaa9b,0x015adefd,0x01665546, //2007
    0x01721afe,0x017ecdd9,0x018a8ee3,0x0197bf46,0x01a3fca7,0x01b1bb65,0x01bf6f5a,0x01ce39de,0x01dd1952,0x01eb6283,0x01fa1c2d,0x020876c2, //2008
    0x021703cc,0x0226d437,0x0234d31f,0x02552e25,0x02676bf0,0x027aa2a8,0x028d92c6,0x02a15073,0x02b5f6c7,0x02c9adb5,0x02ddb5e1,0x02f0ec81, //2009
    0x0304f1c0,0x031b41a8,0x032e68b1,0x0342c994,0x03570786,0x036c9395,0x0381b90a,0x03985a47,0x03b09c6d,0x03c663e5,0x03dd7e4e,0x03f43921, //2010
    0x040ae598,0x0423dced,0x0439c138,0x0452752e,0x046b1bac,0x0485592a,0x04a06d43,0x04bcd456,0x04d9b67e,0x04f52d38,0x0511e53d,0x052de12e, //2011
    0x054a0d31,0x0568a266,0x0584c09c,0x05a25176,0x05c0ba75,0x05df7ee8,0x05fe3605,0x061e623c,0x063f5c2e,0x065e0e92,0x067e22b7,0x069dbc58, //2012
    0x06c0304b,0x06e63d7d,0x0707d372,0x072e182f,0x0751b8f1,0x077862c9,0x079c0d65,0x07c1d1fd,0x07e86b65,0x080da891,0x08320879,0x08558d00, //2013
    0x087b78bc,0x08a21715,0x08c4f43a,0x08eaa130,0x0911cb58,0x0939ac93,0x0960c758,0x098a963b,0x09b76d90,0x09e02d40,0x0a0906c0,0x0a3047ac, //2014
    0x0a810e27,0x0adaffd0,0x0b295113,0x0b7d3b5d,0x0bcf0d62,0x0c249600,0x0c755b5b,0x0ccd27fa,0x0d23c7df,0x0d7376dc,0x0dc57294,0x0e140406, //2015
    0x0e65e5c9,0x0ebde62a,0x0f0cd756,0x0f603ba6,0x0fb360d2,0x100b35e6,0x105e79ed,0x10b8b874,0x1115ce52,0x116ae973,0x11be384e,0x121244b8, //2016
    0x1267dfa9,0x12c42272,0x1315847b,0x136e2e12,0x13c61e4f,0x141f5987,0x147b12a6,0x14ddb823,0x154191ae,0x159e77ae,0x1601dc30,0x16657d11, //2017
    0x16cb7cc6,0x1734ec50,0x179299df,0x17fa28e5,0x185ec78c,0x18c9c40a,0x193229c7,0x19a1e789,0x1a12bcdd,0x1a797ec2,0x1ae1e760,0x1b47eede, //2018
    0x1bb4ac1f,0x1c23cf3d,0x1c84c7c3,0x1cf2f6a5,0x1d61d7f8,0x1ddb56d8,0x1e596089,0x1ede97da,0x1f66d255,0x1fe23935,0x205eafbb,0x20d26c98, //2019
    0x21483492,0x21c24ba6,0x2230dfdb,0x22a6d66f,0x2312ebbd,0x2384611d,0x23f45e42,0x246cd05d,0x24eb9338,0x255dcbe7,0x25d2f0b9,0x264389a4, //2020
    0x26b9cb56,0x2730b46d,0x27982ebf,0x28072efc,0x2870c5b3,0x28e20ee3,0x294ea8bd,0x29bdfadb,0x2a2f47a5,0x2a9bebca,0x2b0c55a2,0x2b78f9c7, //2021
    0x2be93cfe,0x2c598035,0x2cbee635,0x2d2f02cc,0x2d9ba6f0,0x2e0bea27,0x2e788e4c,0x2ee8d183,0x2f5914ba,0x2fc5b8df,0x303622b7,0x30a2c6dc, //2022
    0xffffffff];

function uploadDate(imgName) {
    const monthYearIndex = (element) => element >= parseInt(imgName, 16);
    var index = imgTable.findIndex(monthYearIndex) - 1;
    var year = 2003 + Math.trunc(index / 12);
    var month = 1 + index % 12;
    return `≈ ${month}.${year}${imgTable[index + 1] == 0xffffffff ? '+' : ''}`;
}


// ***** Copy message thread to clipboard *****
function copyMessageThread() {
	var profileId = location.pathname.match(/\d{3,}/);
	var loadTime = new Date().toLocaleString('de-DE').slice(0,-3);
	var msgCount = '', header = '', msgThread = '', msgTime = '', name = '';
	var profileName = $('#messenger div.js-correspondence').find('a > span[lang], div span[disabled], a > img').attr('title').trim();
	var ownName = $('img.avatar__image').attr('alt');
	var jsonParam = `lang=de&length=10000&filter[folders][]=SENT&filter[folders][]=RECEIVED&filter[partner_id]=${profileId}`;
	$.ajax({headers: ajaxHead(), url: `/api/v4/messages?${jsonParam}`})

	.done(function (data) {

		//gather data
		if (data.items_total) {
			msgCount = data.items_total;
			header = 'Message-Verlauf von ' + ownName + ' mit ' + profileName + ' (Profil-ID ' + profileId + ') vom ' + loadTime + '\n\n\n';
			for (var i = msgCount-1; i >= 0; i--) {
				msgTime = new Date(data.items[i].date.slice(0,-5)+'.000Z');
				name = (data.items[i].folder == 'SENT') ? ownName : profileName;
				msgThread += msgCount-i + '. ' + name + '  •  ' + msgTime.toLocaleString('de-DE').slice(0,-3);
				msgThread += (data.items[i].unread == true) ? ' [ungelesen]' : '';
				msgThread += (data.items[i].locked == true) ? ' [gespeichert]' : '';
				msgThread += (data.items[i].spam == true) ? ' [Spam]' : '';
				msgThread += '\n-------------------------------------------------------------------';
				msgThread += '\n' + data.items[i].text+ '\n\n\n';
			}
			msgThread += '\n====================\n\n';
		}

		//confirm copy
		$('#messenger div.js-correspondence').after(
`<div class="re-bubble layout layout--h-center">
<div class="ui-bubble ui-bubble--dark" style="width:auto; top:72px">
<div class="ui-bubble__content [ js-content ] [ js-scrollable ] scrollable">
<div class="confirm-box">
<div class="txt-right" style="margin:-.5rem -.5rem -.75rem">
<a class="re-copy-cancel re-link icon icon-larger icon-cross"></a>
</div>
<div class="confirm-box__label" style="margin-bottom:1.125rem">
<p>Message-Verlauf kopieren</p>
</div>
<div class="confirm-box__actions">
<button class="re-copy-email ui-button ui-button--transparent">E-Mail-Entwurf</button>
<button class="re-copy-confirm ui-button ui-button--primary">Zwischenablage</button>
</div>
</div>
</div>
</div>
</div>
<div class="layer ui-bubble__overlay l-fancy"></div>`
		);
		$('button.re-copy-confirm').focus().click(function() {
            copyToClipboard(header + msgThread);
			$('div.re-bubble, div.ui-bubble__overlay').hide();
		});
		$('button.re-copy-email').click(function() {
            location.href = `mailto:?subject=${encodeURIComponent(header)}&body=${encodeURIComponent(msgThread)}`;
			$('div.re-bubble, div.ui-bubble__overlay').hide();
		});
		$('a.re-copy-cancel, div.ui-bubble__overlay').click(function() {
			$('div.re-bubble, div.ui-bubble__overlay').hide();
		});
	});
}


// ***** copy data to clipboard *****
const copyToClipboard = msgThread => {
	const el = document.createElement('textarea');
	el.value = msgThread;
	el.setAttribute('readonly', '');
	el.style.position = 'absolute';
	el.style.left = '-9999px';
	document.body.appendChild(el);
	const selected =
		  document.getSelection().rangeCount > 0
	? document.getSelection().getRangeAt(0)
	: false;
	el.select();
	document.execCommand('copy');
	document.body.removeChild(el);
	if (selected) {
		document.getSelection().removeAllRanges();
		document.getSelection().addRange(selected);
	}
}


// ***** Fix scrolling on larger screens for messages, my groups, and mobile album lists *****
function fixScroll (jNode) {
    $(jNode).parents('.js-chat .js-scrollable, .Xjs-main .js-sidebar, .profile-section--gallery .scrollable, [id^="single-album-"]').attr('style', 'max-height:inherit !important');
    //console.log('fix scroll');
}


// ***** Add double tap to menu items, change behavior for mobile *****
function menuLinks (jNode) {
    $(jNode).has('#radar-menu').off('dblclick').dblclick(function() { changeUrl('/search/romeos'); });
    //$(jNode).filter('[href="/search"]').off('dblclick').dblclick(function() { changeUrl('/search/romeos'); });
    $(jNode).has('#visitors-menu').off('dblclick').dblclick(function() { changeUrl('/visitors/me'); });
    $(jNode).has('#messages-menu').off('dblclick').dblclick(function() { changeUrl('/messenger/contacts'); });
    $(jNode).has('[href="/me"]').off('dblclick').dblclick(function() { changeUrl('/stream'); });
    //$(jNode).has('[href="/stream"]').off('click').click(function() { (location.pathname.match(/^\/(visitors|messenger)/)) ? history.back(); return false; : return true; });
    if (mobile.matches) {
        //$(jNode).has('#visitors-menu').off('click').click(function() { changeUrl('/visitors'); return false; });
        //$(jNode).has('#messages-menu').off('click').click(function() { changeUrl('/messenger/chat'); return false; });
        $(jNode).has('#groups-menu').off('click').click(function() { changeUrl('/groups/member'); return false; });
    }

    /*var status = $('aside .avatar__status').html();
    $('nav li[class*="Hamburger"]').not('.is-selected').find('a').not(':has(span.js-badge)').append(
        `<span class="js-badge">${status}</span>`
        //`<span class="avatar__status avatar__status--small">${status}</span>`
    );*/
}


// ***** Add contacts etc. to navigation bar *****
function navLinks (jNode) {

	//icons on radar and guycandy
	$('main nav.js-navigation ul').has('a[href^="/radar/"], a[href^="/guycandy/"]').find('li.re-add').remove();
    if (!mobile.matches) {
        $('main nav.js-navigation ul').has('a[href^="/radar/"], a[href^="/guycandy/"]').append(
            '<li class="Tabbed-nav-item--2iOWw mr pr- re-add"><span class="re-add re-radar-travel icon icon-airplane" style="cursor:pointer" title="Travel"><span class="pl-"></span></span></li>'
        );
        $('main nav.js-navigation ul').has('a[href^="/radar/"], a[href^="/guycandy/"]').append(
            '<li class="Tabbed-nav-item--2iOWw re-add"><a style="cursor:default">|</a></li>' +
            '<li class="Tabbed-nav-item--2iOWw re-add"><a href="/messenger/contacts" class="js-nav-item Tabbed-nav-link--xyQY6" title="Kontakte"><span class="icon icon-save-contact"></span></a></li>' +
            '<li class="Tabbed-nav-item--2iOWw re-add"><a href="/groups/member" class="js-nav-item Tabbed-nav-link--xyQY6" title="Meine Gruppen"><span class="icon icon-group-members"></span></a></li>'
        );
    } else {
        $('main nav.js-navigation ul').has('a[href^="/radar/"], a[href^="/guycandy/"]').prepend(
            '<li class="Tabbed-nav-item--2iOWw mr pr- re-add"><span class="re-add re-radar-travel icon icon-airplane" style="cursor:pointer" title="Travel"><span class="pl-"></span></span></li>'
        );
    }

    //travel
    if ($('main nav.js-navigation ul').has('a[href^="/radar/"], a[href^="/guycandy/"]')) {
    	var viewMode = localStorage.getItem('REradarTravelLocation');
    	var toggleTravel = 'span.re-radar-travel';
    	var refreshClick = 'li.Tabbed-nav-item--2iOWw a.is-selected';
    	handleTravelLocation(viewMode, toggleTravel, refreshClick);
    	$('span.re-radar-travel').click(function() {
			var viewMode = localStorage.getItem('REradarTravelLocation');
	  	    var toggleTravel = 'span.re-radar-travel';
	   	    var refreshClick = 'li.Tabbed-nav-item--2iOWw a.is-selected';
			viewMode = (viewMode == 'travel') ? 'default' : 'travel';
			localStorage.setItem('REradarTravelLocation', viewMode);
			handleTravelLocation(viewMode, toggleTravel, refreshClick);
		});
    }

    //icons on groups
    if (!mobile.matches) {
        $('div.js-navigation ul').has('a[href="/groups/discover"]').not(':has(li.re-add)').append(
            '<li class="Tabbed-nav-item--2iOWw re-add"><a style="cursor:default">|</a></li>' +
            '<li class="Tabbed-nav-item--2iOWw re-add"><a href="/messenger/contacts" class="js-nav-item Tabbed-nav-link--xyQY6" title="Kontakte"><span class="icon icon-save-contact"></span></a></li>'
        );
    }
    $('div.js-navigation ul li').not('.re-add').find('a[href="/groups/member"]').attr('title', `${commonGroupsList.length.toLocaleString()} Gruppen abonniert`);

    //remove GR-Tools hint
    $('li.re-grtools').remove();
}


// ***** Show versions and online users in menu, selected bookmark in filter icon title and text *****
function handleVersionBookmark (jNode) {

    //menu
    if ($('#offcanvas-nav div[class^="Version"]').length) {
        var reVersion = `${(typeof GM_info != 'undefined') ? `${GM_info.script.name} ${GM_info.script.version}` : 'RomeoEnhancer'}`;
        var onlineAll = '';
        $.ajax({url: `/api/services/landing/online-count`}).done(function (data) {
            if (data.online_count) {
                onlineAll = `${data.online_count.toLocaleString()} Profile online`;
            }
            $('#offcanvas-nav div[class^="Version"] .re-add').remove();
            $('#offcanvas-nav div[class^="Version"]').addClass('txt-preserve').append(`<div class="re-add">${reVersion}\n${onlineAll}</div>`);
            var profileType = ($('li.is-selected, li[class*="list__item--active"]').find('a[href*="/hunqz"]').length) ? '/hunqz/profiles' : '/profiles';
            var users = '', online = '';
            $.ajax({headers: ajaxHead(), url: `/api/v4${profileType}?pick=items_total&lang=de&length=1`}).done(function (data) {
                if (data.items_total) {
                    users = `${data.items_total.toLocaleString()} User`;
                }
                $.ajax({headers: ajaxHead(), url: `/api/v4${profileType}?pick=items_total&lang=de&length=1&filter[online_status][]=ONLINE&filter[online_status][]=DATE&filter[online_status][]=SEX`}).done(function (data) {
                    if (data.items_total) {
                        online = `${data.items_total.toLocaleString()} online`;
                    }
                    $('#offcanvas-nav div[class^="Version"]').off().on('dblclick', function() {
                        $('#offcanvas-nav div[class^="Version"] div').replaceWith(`<div class="re-add">${reVersion}\n${onlineAll}\n${users} • ${online}</div>`);
                    });
                });
            });
        });

    } else {

    //filter icon title and text
        var selectedBookmark = $('div[class^="js-bookmarks-list"] div[class*="item__is-selected"] a').text().trim();
        var searchOptions = $('div.js-filter-button button title').text().trim();
        if (selectedBookmark) {
            $('div.js-filter-button button').attr('style', 'color:rgb(250,250,250); background-color:transparent');
            $('div.js-filter-button button title').text(`Lesezeichen: ${selectedBookmark}\r${searchOptions}`);
            $('div.js-filter-button button span:not(.re-add)').addClass('re-filter-options-text');
            $('div.js-filter-button button').not(':has(.re-add)').append(`<span class="re-add re-filter-bookmark-name mr">${selectedBookmark}</span>`);
            $('div.js-filter-button button span').attr('title', `Lesezeichen: ${selectedBookmark}\r${searchOptions}`);
            $('button.ui-navbar__button--bookmarks').attr('title', 'Lesezeichen auswählen');
        } else {
            $('div.js-filter-button button span.re-filter-options-text').removeClass('re-filter-options-text');
            $('div.js-filter-button button span.re-add').remove();
        }
    }
}


// ***** Preview unread messages in title tag, delete by clicking blue badge *****
function previewMessage (jNode) {
	var profileId = $(jNode).parent().parent().attr('href').match(/\d{3,}/);
    if (profileId) {
	    $(jNode).parent().parent().addClass('re-id' + profileId);
	    var msgCount = parseInt($(jNode).text());
	    var jsonParam = 'lang=de&length=' + msgCount + '&filter[folders][]=RECEIVED&filter[partner_id]=' + profileId;
	    var msgText = '';
	    var thisId = '.re-id' + profileId;
	    $.ajax({headers: ajaxHead(), url: '/api/v4/messages?' + jsonParam}).done(function (data) {

    		//preview
	    	for (var i = msgCount-1; i >= 0; i--) {
		    	msgText += '\r' + data.items[i].text + '\r';
    		}
	    	$(thisId).attr('title', msgText);
            $(thisId).find('img').parent('div').attr('title', msgText);

		    //delete unread
    		$(jNode).attr('title', 'Löschen').click(function () {
	    		if (confirm(msgCount + ' Message(s) ungelesen löschen?')) {
		    		for (var i = msgCount-1; i >= 0; i--) {
			    		$.ajax({url: '/api/v4/messages/' + data.items[i].id + '?expand=from',
                                headers: ajaxHead(),
                                method: 'DELETE'
                               })
                        .done(function (data) {
                            //$('#messenger li.Tabbed-nav-item--8Ou8b a').first().get(0).click();
                        })
                    }
                    //changeUrl('/messenger/chat');
                    //$('#messenger li.Tabbed-nav-item--8Ou8b.is-selected a').get(0).click();
    			}
	    	})
	    });
    }
}


// ***** Show id, last login, and location in message thread and contact info *****
function showLoginLocation (jNode) {
	var profileId = location.pathname.match(/\d{3,}$/);
	//var id = `<span style="opacity:.5" title="Profil-ID ${profileId}"><span class="re-desk">Profil-ID</span><span class="re-mobi">#</span> ${profileId}</span>`;
	var id = `<span class="re-desk" style="opacity:.5" title="Profil-ID"># ${profileId} • </span>`;
	var name = '', country = '', distance = '', sensor = '';
	$.ajax({headers: ajaxHead(), url: '/api/v4/profiles/' + profileId + '?expand=partner&lang=de'})

	.done(function (data) {

		//last login
		if (data.last_login) {
			var loginTime = new Date(data.last_login.slice(0,-5)+'.000Z');
            var loginLocalTime = dateTime(loginTime);
			var timeTag = dateTime(loginTime, !mobile.matches);
			$(jNode).find('a svg[class*="OnlineStatus__"] title').text(`Online seit ${loginLocalTime}`);
			$(jNode).find('a div > svg').removeAttr('title').parent().attr('title', `Zuletzt online ${loginLocalTime}`);
            $(jNode).find('a').not(':has(svg[class*="OnlineStatus__"], div > svg)').find('span, img').after(
                `<span class="icon icon-last-login-hours mh--" style="color:rgba(250,250,250,.75)" title="Zuletzt online ${loginLocalTime}"> ${timeTag}</span>`
			);
		}

		//location, distance
		if (data.location.name) {
			name = `<a target="_blank" href="https://google.com/maps/place/${data.location.name}" rel="noreferrer noopener" title="Ort in Google Maps anzeigen">${data.location.name.trim()}</a>`;
		}
        if (data.location.country && (data.location.distance > 50000 || data.location.distance == null)) {
            country = ` - ${data.location.country}`;
        }
		if (data.location.distance >= 0) {
			if (data.location.distance < 1000) {
				distance = ' • ' + data.location.distance + 'm';
			} else {
				distance = ' • ' + (Math.round(data.location.distance/100)/10).toLocaleString() + ' km';
			}
		}
		if (data.location.sensor) {
			sensor = '<span class="icon icon-gps-needle icon-badge ml--" style="font-size:.85em"></span>';
		}
	})

	.always(function (data) {
		$(jNode).find('a').has('span[lang]').not(':has(a)').after(
			`<div class="re-location">${id}${name}${country}${distance}${sensor}</div>`
		);
	});
}


// ***** Add copy to message thread options menu *****
function threadOptionsMenu (jNode) {
	$(jNode).find('li').first().clone().prependTo($(jNode)).click(function() {
        copyMessageThread();
		return false;
	}).attr('id', 'options_copy').find('span').text('Kopieren');
}


// ***** Link contact icons in messages list entries *****
function contactsMessage (jNode) {
	var profileId = new Array;
    profileId = $(jNode).attr('href').match(/\d{3,}/);
	if (! profileId) profileId = location.pathname.match(/\d{3,}/);
    $(jNode).find('svg.eesqBN, svg.gClpgj').wrap(
		`<a href="/messenger/contacts/all/${profileId}"></a>`
	);
	$(jNode).find('svg.BqJLH').wrap(
		`<a href="/messenger/contacts/blocked/${profileId}"></a>`
	);

    //fix hunqz readability
    $(jNode).has('svg[label="HUNQZ"]').find('span[lang]').first().attr('style', 'font-weight:550');
}


// ***** Add message icons to contact list entries *****
function messageContacts (jNode) {
	var profileId = new Array;
    profileId = $(jNode).attr('href').match(/\d{3,}$/);
	if (! profileId) profileId = location.pathname.match(/\d{3,}$/);
	$(jNode).find('span[title]').last().not(':has(a)').append(
		`<a class="icon icon-chat re-icon ml- mr--" title="Messages" href="/messenger/chat/${profileId}"></a>`
	);

    //fix hunqz readability
    $(jNode).has('svg[label="HUNQZ"]').find('span[lang]').first().attr('style', 'font-weight:550');
}


// ***** Link user names on discover page to messages *****
function handleContactStrip (jNode) {
	var replacePattern = /(.*\/(profile|hunq|group)\/)([-\w]*)(.*)/;
	var profileLink = $(jNode).attr('href');
    $(jNode).attr('href', profileLink.replace(/\/group\//, '/profile/'));
	var profileName = profileLink.replace(replacePattern, '$3');
	var baseUrl = '/messenger/chat/';
	$(jNode).find('div[class^="Name-"]')/*.wrapInner(
		`<a class="re-link-idle" title="${profileName}  |  Messages" href="${baseUrl}${profileName}"></a>`
	).children()*/.click(function() {
		openByName(baseUrl, profileLink, profileName);
		return false;
	}).attr('style', `${profileLink.match(/\/hunq\//) ? 'color:#fc193c' : ''}`);
}


// ***** Mark common groups *****
function handleGroupTiles (jNode) {
    $(jNode).addClass('re-group-tile');
    const profileName = $(jNode).attr('href').match(/[-\w]+$/);
    const nameIndex = (item) => item.name == profileName;
    if (commonGroupsList.findIndex(nameIndex) > -1) {
        $(jNode).find('span.icon-group-members').parent('div[class^="Container"]').addClass('re-common-group');
        $(jNode).addClass('re-common-group');
    }

    //official group
    const imgSrc = $(jNode).find('.js-is-official img').attr('src');
    if (imgSrc) $(jNode).find('.js-members-count > div').prepend(
        `<img src="${imgSrc}" class="re-icon-official" title="Offizielle Gruppe"</img>`
    );
}


// ***** Add message icons to discover, visitor list, search results, and group member list, link contact icons *****
function handleTiles (jNode) {
    var jNodeTiles = $(jNode).hasClass('tile__image') ? $(jNode).parent('a') : $(jNode);
	var replacePattern = /(.*\/(profile|hunq|group)\/)([-\w]*)(.*)/;
	var profileLink = jNodeTiles.attr('href');
	var profileName = profileLink.replace(replacePattern, '$3');

    //add + to distance if travel
    if (travelMode && location.pathname.match(/^\/(radar|groups|explore)\//)) {
        if (jNodeTiles.find('div.typo-small.txt-truncate').text().match(/(\d[\d\.,]*\s?(km|m|mi|ft))/)) {
            var distance = jNodeTiles.find('div.typo-small.txt-truncate').html().replace(/^\s+/, '+');
            jNodeTiles.find('div.typo-small.txt-truncate').html(distance);
        }
    }

    //add visitor icon
    var visitTime, visitedTime = '';
    const nameIndex = (item) => item.name == profileName;
    if (location.pathname == '/visitors/me') {
        if (visitorsList.findIndex(nameIndex) > -1) {
            var index1 = visitorsList.findIndex(nameIndex);
            visitTime = new Date(visitorsList[index1].date_visited);
            jNodeTiles.find('div.tile__visit').append(  // 'div.info, div.Name--3cum4 .info__username'
                `<a class="icon icon-visitor re-icon re-idle ml--" style="top:-1px" title="Besucher ${dateTime(visitTime)}" href="/visitors"></a>`
            );
        }
    }
    if (location.pathname == '/visitors') {
        if (visitsList.findIndex(nameIndex) > -1) {
            var index2 = visitsList.findIndex(nameIndex);
            visitedTime = new Date(visitsList[index2].date_visited);
            jNodeTiles.find('div.tile__visit').prepend(  // 'div.info, div.Name--3cum4 .info__username'
                `<a class="icon icon-visitor re-icon re-idle mr--" style="top:-1px" title="Besucht ${dateTime(visitedTime)}" href="/visitors/me"></a>`
            );
        }
    }


	//add message icon
	var baseUrl = '/messenger/chat/';
	jNodeTiles.find('div.info, div.Name--3cum4 .info__username').append(
		`<a class="icon icon-chat re-icon re-idle ml-" title="Messages" href="${baseUrl}${profileName}"></a>`
	).children().last().click(function() {
		openByName(baseUrl, profileLink, profileName);
		return false;
	});

    //link contact icon
	jNodeTiles.find('span.icon-save-contact').replaceWith(
		`<a class="tile__badge icon icon-save-contact re-idle" title="Kontakt bearbeiten" href="/messenger/contacts/all/${profileName}"></a>`
	);
	jNodeTiles.find('a.icon-save-contact').click(function() {
		openByName('/messenger/contacts/all/', profileLink, profileName);
		return false;
	});
	jNodeTiles.find('span.icon-block-contact').replaceWith(
		`<a class="tile__badge icon icon-block-contact" title="Kontakt bearbeiten" href="/messenger/contacts/blocked/${profileName}"></a>`
	);
	jNodeTiles.find('a.icon-block-contact').click(function() {
		openByName('/messenger/contacts/blocked/', profileLink, profileName);
		return false;
	});
}


// ***** Add message icons and preview links to radar entries, link contact icons *****
function handleRadar (jNode) {
	var replacePattern = /(.*\/(profile|hunq|group)\/)([-\w]*)(.*)/;
	var profileLink = $(jNode).attr('href');
	var profileName = profileLink.replace(replacePattern, '$3');

    // TEST
    if ($('#profiles div.search-results__item').length > 200) {
        //$('#profiles div.search-results__item').eq(0).remove();
    }

    //add visitor icon
    const nameIndex = (element) => element.name == profileName;
    if (visitorsList.findIndex(nameIndex) > -1) {
        var index = visitorsList.findIndex(nameIndex);
        var visitTime = new Date(visitorsList[index].date);
        $(jNode).find('div.info, span.info__body').append(
            `<a class="icon icon-visitor re-icon re-idle ml-" title="Besucher ${dateTime(visitTime)}" href="/visitors"></a>`
        );
    }

	//add message icon
	var baseUrl = '/messenger/chat/';
	$(jNode).find('div.info, span.info__body').append(
		`<a class="icon icon-chat re-icon re-idle ml-" title="Messages" href="${baseUrl}${profileName}"></a>`
	).children().last().click(function() {
		openByName(baseUrl, profileLink, profileName);
		return false;
	});

    //add + to distance if travel
    if (travelMode || location.pathname.match(/^\/explore\//)) {
        if (location.pathname.match(/^\/(radar|groups|explore|guycandy)\//)) {
            if ($(jNode).find('div.typo-small.txt-truncate').text().match(/(\d[\d\.,]*\s?(km|m|mi|ft))/)) {
                var distance = $(jNode).find('div.typo-small.txt-truncate').html().replace(/^\s+/, '+');
                $(jNode).find('div.typo-small.txt-truncate').html(distance);
            }
        }
    }

    //link username to preview
	$(jNode).find('div.info__username, span.listresult__info').wrapInner(
		`<a class="re-link-idle" title="${profileName}  |  Vorschau" href="${profileLink.replace(replacePattern, '$1$3/preview')}"></a>`
	);

	//link contact icon
	$(jNode).find('span.icon-save-contact').replaceWith(
		`<a class="tile__badge icon icon-save-contact re-idle" title="Kontakt bearbeiten" href="/messenger/contacts/all/${profileName}"></a>`
	);
	$(jNode).find('a.icon-save-contact').click(function() {
		openByName('/messenger/contacts/all/', profileLink, profileName);
		return false;
	});
	$(jNode).find('span.icon-block-contact').replaceWith(
		`<a class="tile__badge icon icon-block-contact" title="Kontakt bearbeiten" href="/messenger/contacts/blocked/${profileName}"></a>`
	);
	$(jNode).find('a.icon-block-contact').click(function() {
		openByName('/messenger/contacts/blocked/', profileLink, profileName);
		return false;
	});

	//show count of profiles, Plus, travelling, and GPS in title tag of selected tab
	var loadTime = new Date().toLocaleTimeString() + ' aktualisiert';
	var profiles = $('#profiles div.grid-tile, #profiles div.listresult__tile').length;
	var profilesPlus = '';
	var percentPlus = '';
	if ($('#profiles .search-results--small-tiles').length == 0) {
		profilesPlus = $('#profiles div.js-romeo-badge span img, #profiles div[class*="badge--plus-"]').length;
		percentPlus = (profiles > 0 ? ' (' + (Math.round(profilesPlus/profiles*1000)/10).toLocaleString() + ' %)' : '');
		profilesPlus =  ' • ' + profilesPlus + ' Plus' + percentPlus;
	}
	var profilesTravel = '';
	var percentTravel = '';
	profilesTravel = $('#profiles .js-search-results span.icon-airplane').length;
	percentTravel = (profiles > 0 ? ' (' + (Math.round(profilesTravel/profiles*1000)/10).toLocaleString() + ' %)' : '');
	profilesTravel =  `${profilesTravel} ${(profilesTravel == 1 ? 'Reisender' : 'Reisende')}${percentTravel}`;
	var profilesGPS = '';
	var percentGPS = '';
	profilesGPS = $('#profiles span.icon-gps-needle').length;
	percentGPS = (profiles > 0 ? ' (' + (Math.round(profilesGPS/profiles*1000)/10).toLocaleString() + ' %)' : '');
	profilesGPS =  ' • ' + profilesGPS + ' GPS' + percentGPS;
    profiles += ` ${(profiles == 1 ? 'Profil' : 'Profile')} geladen`;
	$('ul.Tabbed-nav--2c5l9 li.is-selected, div.js-nav-item').attr(
		'title', `${loadTime}\r${profiles}${profilesPlus}\r${profilesTravel}${profilesGPS}`
	);
}


// ***** Add message icons to non-message Activity Stream entries; handle group related entries; add icon to settings *****
function handleActivity (jNode) {
	var bodyLink = $(jNode).attr('href');
	if (bodyLink != undefined && ! bodyLink.match('/messenger/chat/')) {
		var replacePattern = /(.*\/(profile|hunq|groups)\/)([A-Za-z0-9\-_]*)(.*)/;
		var profileLink = '' + $(jNode).parent().find('a').attr('href');
		var profileName = profileLink.replace(replacePattern, '$3');
		var baseUrl = '/messenger/chat/';

		//add message icon
        if (profileName) {
            $(jNode).find('div.layout.layout--consume span, .Text-sc-1whxy9k-0').last().not(':has(a,img)').append(
                `<a class="icon icon-chat re-icon ml- mr--" title="Messages" href="${baseUrl}${profileName}"></a>`
            ).children().last().click(function() {
                openByName(baseUrl, profileLink, profileName);
                return false;
            });
        }

		//italic if system text
		$(jNode).find('span.listitem__text, span.ui-status-description').attr('style', 'font-style:italic');

		//add icon, move text to title in desktop view if group picture
        var jNodeGroupPicture = $(jNode).has('img.thumbnail').not(':has(span.icon-heart, span.icon-camera-icon)');
        jNodeGroupPicture.find('span.listitem__timestamp').after(
            `<span class="clr-ui-text listitem__highlight--expanded"><span class="icon icon-group-members"></span></span>`
        );
        if (! location.pathname.match(/^\/stream/)) {
            /*jNodeGroupPicture.find('span.listitem__text').first().hide();
            jNodeGroupPicture.attr('title', jNodeGroupPicture.find('span.listitem__text').first().text().trim());
            $(jNodeGroupPicture).parent().addClass('re-group-item');*/
            $(jNodeGroupPicture).parent().addClass('re-group-item').hide();
        }
	}

    //add enlarge and settings
    $('div.stream__content div.js-list').not(':has(div.re-add)').prepend(`
<div class="re-add mt-- mb- mh" style="display:flex; justify-content:space-between; align-items:center; height:.875rem">
<div class="layout">${(!location.pathname.match(/^\/stream$/)) ? `<a href="/stream" class="icon icon-back re-icon re-link p0 re-stream-group-items" title="Erweitern"></a>` : ``}</div>
<a href="/me/notifications" class="icon icon-settings re-icon re-link p0"><span class="ml--">Anpassen</span></a>
</div>`
    );
    var groupItems = $('section.js-stream .re-group-item').length;
    if (groupItems) {
        $('.re-stream-group-items').html(`<span class="ml-">${groupItems}<span class="icon icon-group-members" style="margin-left:.15rem"></span></span>`).attr('title', `Erweitern • Neue Bilder in ${groupItems} Gruppe${(groupItems == 1) ? '' : 'n'}`);
    }

    //fix hunqz readability
    $(jNode).filter('div.stream__content a.listitem__body').has('svg[label="HUNQZ"]').find('span[lang]').first().attr('style', 'font-weight:550');
}


// ***** Profiles: show profile id, visits since; link URLs *****
function handleProfile (jNode) {
    var profileName = $('h2.profile__name').text().trim().match(/[-\w]+$/);
    var profileType = ($('div.is-profile-loaded').hasClass('profile--hunqz')) ? '/hunqz/profiles' : '/profiles';
    var profilePath = ($('div.is-profile-loaded').hasClass('profile--hunqz')) ? 'hunq' : 'profile';
	var profileId = '', profileIdInfo = '', visits = '', since = '', known = '', known1st = '', known2nd = '', verified = '';
	var albums = 0, pictures = 0, profilePictures = 0, quickShare = 0;
    var name = '', country = '', distance = '', sensor = '', headline = '';
    var sinceMonthYear = $('section.profile__stats section > p').last().contents().filter(function(){ return this.TEXT_NODE; }).first().text();
    $.ajax({headers: ajaxHead(), url: `/api/v4${profileType}/${profileName}/full?lang=de&lookup_type=NAME&expand=albumsV2.items.*.pictures`})

	.done(function (data) {
		if (data.id) {
			profileId = data.id;
            profileIdInfo = `Profil-ID: ${data.id}`;
		}
		if (data.visits_count) { //  not 0 or undefined
			visits = `<br>Besucher: ${data.visits_count.toLocaleString()}`;
		}
		if (data.creation_date) {
			since = new Date(data.creation_date.slice(0,-5)+'.000Z').toLocaleDateString();
			since = 'Mitglied seit: ' + since;
		} else {
			since = sinceMonthYear;
		}

        //known by
        if (data.known_by && data.known_by.first_degree > 0) {
            known1st = data.known_by.first_degree;
            known2nd = data.known_by.second_degree;
            known = `Bekannt bei ${known1st.toLocaleString()} ${known1st == 1 ? 'Nutzer (dieser' : 'Nutzern (diese'} bekannt bei ${known2nd.toLocaleString()})`;
        } else {
            known = `Noch nicht bei anderen bekannt`;
        }

        //authenticity
        if (known1st) {
            verified = (known1st > 9 && known2nd > 99) ? 'white' : '';
            $('.profile .js-authenticity svg path.tick').attr('transform', 'translate(0 -5) scale(.925)');
            $('.profile .js-authenticity button').append(`<span class="${verified}">${known1st <= 30 ? `${known1st.toLocaleString()}` : '30+'}</span>`);
        } else {
            $('.profile .js-authenticity button').append(`<span>...</span>`);
        }

        //show pictures count
		if (data.albumsV2.items_total) {
            for (var item of data.albumsV2.items) {
                if (item.id == 'PROFILE') {
                    if (item.pictures) {
                        profilePictures += item.pictures.items_total;
                    }
                } else if (item.access_policy == 'SHARED') {
                    quickShare += item.items_total;
                } else {
                    pictures += item.items_total;
                    albums += (item.items_total) ? 1 : 0;
                }
            }
            if (profilePictures > 1) {
                $('section.profile__image-strip').not(':has(.re-add)').append(
                    `<div class="re-add re-img-count"><div><p>${profilePictures}</p></div></div>`
                ).children().last().click(function(){
                    changeUrl(`/${profilePath}/${profileName}/gallery`);
                }).attr('style', 'cursor:pointer').attr('title', 'Alle Alben anzeigen');
            }
            if (quickShare || pictures) {
                $('section.profile__stats section > div[class^="InfoText-"] div').first().not(':has(.re-add)').append(
                    `<span class="re-add" style="color:rgba(255,255,255,.6)"> • ${quickShare + pictures} Bilder</span>`
                );
            }
			$('section.js-profile-stats a div div').first().has('svg').not(':has(.re-add)').append(
				`<div class="re-add re-img-count"><div><p>${quickShare}</p></div></div>`
			);
		}

        //link location name to maps
        if (data.location.name) {
			name = `<a target="_blank" href="https://google.com/maps/place/${data.location.name}" rel="noreferrer noopener" class="re-link-idle" title="Ort in Google Maps anzeigen">${data.location.name.trim()}</a>`;
		}
        if (data.location.country && (data.location.distance > 50000 || data.location.distance == null)) {
            country = `, ${data.location.country}`;
        }
        if (data.location.distance != null) {
			if (data.location.distance < 1000) {
				distance = ' • ' + data.location.distance + 'm';
			} else {
				distance = ' • ' + (Math.round(data.location.distance/100)/10).toLocaleString() + ' km';
			}
		}
		if (data.location.sensor) {
			sensor = '<span class="icon icon-small icon-gps-needle icon-badge ml--"></span>';
		}

        $('div.is-profile-loaded p[class^="Location-"]').html(name + country + distance + sensor);
    })

	.fail(function (data) {
		profileId = $('#spotlight-container div.layer.layer--spotlight').attr('id').match(/\d{3,}/);
		since = sinceMonthYear;
	})

	.always(function (data) {

		//since, visits, known by, id
		$('section.profile__stats section > p').last().addClass('re-profile-stats').html(`${since}<br>${known}${visits}<br>${profileIdInfo}`);

        //authenticity
        var title = $('.profile__info .js-authenticity button').attr('title');
        $('.profile__info .js-authenticity button').not('.re-add').addClass('re-add').attr('title', `${title}\n${sinceMonthYear}`);

		//hide visit
		$('div.profile--romeo h2.profile__name').attr('title', 'Profilbesuch verstecken').click(function(){
			hideVisit(profileId);
		});

        //link to albums
        $('section.profile__stats section').first().find('div[class^="InfoText-"] div').click(function(){
            changeUrl(`/${profilePath}/${profileName}/gallery`);
        }).attr('style', 'cursor:pointer').attr('title', 'Alle Alben anzeigen');

        //complete headline
        if (data.headline) {
            $('.js-age-name-location div > p[class^="BodyText"]').text(data.headline);
        }

        //URLs in headline and profile text
        $('.js-age-name-location div > p[class^="BodyText"], section.profile__stats section > div > p[class^="BaseText-sc-"]').each(function() {
            var replacedText = linkify($(this).html());
            $(this).html(replacedText);
        });
    });


    //move Looking For to top, keeping Albums and B&B at top
    $('section.profile__stats section').not(':has(.re-add)').has('h4:contains("Ich suche"), h4:contains("Looking For"), h4:contains("Recherche")').each(function() {
        $(this).addClass('re-add').prependTo('section.profile__stats > div > div.reactView > div');
    });
    $('section.profile__stats section').not('.profile-stats__group').not(':has(.re-add)').has('img').addClass('re-add').prependTo('section.profile__stats > div > div.reactView > div');
    $('section.profile__stats section').not('.profile-stats__group').not(':has(.re-add)').has('div[class^="InfoText-"]').addClass('re-add').prependTo('section.profile__stats > div > div.reactView > div');
}


// ***** Link profile travel locations to maps *****
function linkTravelHeadline (jNode) {
    $(jNode).wrapInner(
         `<a target="_blank" href="https://google.com/maps/place/${$(jNode).text().trim()}" rel="noreferrer noopener" class="re-link-idle" title="Ort in Google Maps anzeigen"></a>`
     );
}


// ***** Handle error page *****
function linksError (jNode) {
    //...
	$(jNode).append(
		`<div style="font-size:0.9em"><br/>...</div>`
	);
}


// ***** Sort groups list by active posts *****

//init
var groupsList = [];
var counter = 0;
var refresh = false;
var groupsListloadTime = 0;
var lastGroupUrl = '';

function recentPosts (jNode) {

	//insert menu
	var viewMode = localStorage.getItem('REgroupsListView');
	var linkTextActive = 'Aktive Beiträge', linkTextDefault = 'Standard';
	var linkText = (viewMode == 'active') ? linkTextActive : linkTextDefault;
	$('div.Container--3h4tt div.js-groups').not(':has(span.re-list-head)').prepend(
		`
<div class="mt- mb- pv-" style="font-size:.85rem; border-bottom:1px solid rgba(255,255,255,.125)">
<span class="re-list-head">Sortierung</span>
<span class="re-list-view ml-" title="Umschalten">${linkText}</span>
<span class="re-list-load icon icon-stathistory pl- pr-" title="Aktualisieren">
<span class="re-list-head ml--"></span>
</span>
</div>
`
	);
    if (mobile.matches) {
		$('div.Container--3h4tt div.js-header').removeClass('l-hidden-sm');
		$('div.Container--xbtQn').hide();
	}
	if (viewMode !== 'active') {
		$('span.re-list-load').hide();
	}

	//register toggle menu click
	$('span.re-list-view').click(function() {
		var oldViewMode = localStorage.getItem('REgroupsListView');
		if (oldViewMode == 'active') {
			linkText = linkTextDefault;
			viewMode = 'default';
			$('span.re-list-load').hide();
            lastGroupUrl = '';
		} else {
			linkText = linkTextActive;
			viewMode = 'active';
			$('span.re-list-load').show();
		}
		localStorage.setItem('REgroupsListView', viewMode);
		$('span.re-list-view').text(linkText);
		handlePostsList(viewMode);
	});

	//register refresh list click
	$('span.re-list-load').click(function() {
		groupsList.length = 0;
		counter = 0;
        refresh = true;
        groupsListloadTime = new Date().toLocaleTimeString();
		$('div.Container--3h4tt div.js-groups div.re-add').remove();
		$('div.Container--3h4tt div.js-groups > div.pt-').hide();
		handlePostsList(viewMode);
	});
	handlePostsList(viewMode);
}


// ***** Handle posts list *****
function handlePostsList (viewMode) {

	if (viewMode !== 'active') {
		$('div.Container--3h4tt div.js-groups div.re-add').remove();
		$('div.Container--3h4tt div.js-groups > div.pt-').show();
        var highlighted = 'div.Container--3h4tt div.js-groups button';
        if ($(highlighted).length) {
            if (typeof $(highlighted)[0].scrollIntoViewIfNeeded === 'function') {
                $(highlighted)[0].scrollIntoViewIfNeeded(true);
            } else {
                $(highlighted)[0].scrollIntoView({block: 'center'});
            }
        }
    } else {
		$('div.Container--3h4tt div.js-groups > div.pt-').hide();
		if (groupsList.length > 0) {
			insertPostsList(groupsList);
		} else {
            refresh = true;
            groupsListloadTime = new Date().toLocaleTimeString('de-DE');
			$('div.Container--3h4tt div.js-groups').append(
				'<div class="spinner-container re-add"><div class="spinner"></div></div>'
			);

            $.ajax({headers: ajaxHead(), url: '/api/v4/profiles/me/groups?expand=items.*.(membership,activity)&lang=de&length=1000&pick=items.*.(id,name,display_name,membership.is_admin,is_forum_enabled,activity.posts.*,activity.photos.*,preview_pic.url_token),items_total'})

			.done(function (data) {
				groupsList = [];
				counter = 0;
				var groupsCount = data.items_total;
				var ajaxUrl = '', name = '', displayName = '', isAdmin = false, picToken = '', actPosts = 0, countPosts = 0, actPhotos = 0, countPhotos = 0;

				for (var item of data.items) {

                    // loop "posts" for all groups
                    if (item) {
                        name = item.name;
                        displayName = item.display_name;
                        isAdmin = item.membership.is_admin;
                        picToken = (item.preview_pic) ? item.preview_pic.url_token : '';
                        if (item.activity) {
                            actPosts = (item.activity.posts) ? item.activity.posts.last_accessed : 0;
                            countPosts = (item.activity.posts) ? item.activity.posts.count : 0;
                            actPhotos = (item.activity.photos) ? item.activity.photos.last_accessed : 0;
                            countPhotos = (item.activity.photos) ? item.activity.photos.count : 0;
                        } else {
                            actPosts = 0;
                            countPosts = 0;
                            actPhotos = 0;
                            countPhotos = 0;
                        }
                        if (item.is_forum_enabled) {
                            ajaxUrl = `/api/v4/groups/${item.id}/posts?pick=items.*.(date_created,comments.items.*.(date_created))&expand=items.*.(comments)&lang=de&length=5&sort_criteria=COMMENTED_AT_DESC`;
                        } else {
                            ajaxUrl = `/api/v4/groups/${item.id}/posts?pick=items.*.(date_created)&lang=de&length=5&sort_criteria=COMMENTED_AT_DESC`;
                        }

                        $.ajax({headers: ajaxHead(),
                                url: ajaxUrl,
                                custom: {name: name, displayName: displayName, isAdmin: isAdmin, picToken: picToken, actPosts: actPosts, countPosts: countPosts, actPhotos: actPhotos, countPhotos: countPhotos} })

                        .done(function (data) {

                            //save name, timestamp, etc. to array (most recent post or comment)
                            var timeList = [], name = '', displayName = '', time = 0, isComment = false, picToken = '', actPosts = 0, countPosts = 0, actPhotos = 0, countPhotos = 0;
                            for (var item of data.items) {
                                if (item.comments && item.comments.items[0]) {
                                    time = item.comments.items[0].date_created;
                                    isComment = true;
                                } else {
                                    time = item.date_created;
                                    isComment = false;
                                }
                                if (time != 0) time = new Date(time.slice(0,-2) + ':00');
                                timeList.push({time: time, isComment: isComment});
                            }

                            //sort by most recent post or comment
                            timeList.sort(function (a,b) {
                                return b.time - a.time;
                            });

                            if (timeList[0]) time = timeList[0].time;
                            if (timeList[0]) isComment = timeList[0].isComment;
                            name = this.custom.name;
                            displayName = this.custom.displayName;
                            isAdmin = this.custom.isAdmin;
                            picToken = this.custom.picToken;
                            actPosts = this.custom.actPosts;
                            countPosts = this.custom.countPosts;
                            actPhotos = this.custom.actPhotos;
                            countPhotos = this.custom.countPhotos;
                            if (actPosts != 0) actPosts = new Date(actPosts);
                            if (actPhotos != 0) actPhotos = new Date(actPhotos);
                            //console.log(displayName, timeList);

                            //add to array
                            groupsList.push({time: time, name: name, displayName: displayName, isAdmin: isAdmin, picToken: picToken, isComment: isComment, actPosts: actPosts, countPosts: countPosts, actPhotos: actPhotos, countPhotos: countPhotos});
                        })

                        .always(function (data) {
                            counter += 1;
                            if (counter >= groupsCount) {
                                insertPostsList(groupsList);
                                return;
                            }
                        });

                    } else {
                        counter += 1;
                        if (counter >= groupsCount) {
                            insertPostsList(groupsList);
                            return;
                        }
                    }
                }
            });
        }
        $('span.re-list-load span').text(groupsListloadTime.slice(0,-3));
        $('ul.Container--1I9Gx button').click();
	}
}


// ***** Insert posts list *****
function insertPostsList (groupsList) {

	//sort by most recent
	groupsList.sort(function (a,b) {
		return b.time - a.time;
	});
	//console.log(groupsList);

	//insert list elements on top of MY GROUPS
	$('div.Container--3h4tt div.js-groups div.re-add').remove();
	$('div.Container--3h4tt div.js-groups > div.pt-').hide();
    $('div.Container--3h4tt div.js-groups').append('<div class="mb re-add"></div>');
	var thumbnail = '';
	for (var item of groupsList) {
		thumbnail = (item.picToken == '') ? '/assets/f3b077168d98a575e8960e70c59f5d78.svg' : `/img/usr/squarish/212x212/${item.picToken}.jpg`;
		$('div.Container--3h4tt div.js-groups').append(`
<div class="reactView re-add">
<a href="/groups/member/${item.name}" class="re-groups-listitem">
<div class="re-groups-tile" style="background-image:url(${thumbnail})"></div>
<div class="re-groups-entry">
<span class="re-groups-text">
<span>
<span lang="" title="${item.displayName}" class="re-groups-name">${item.displayName}<br>
<span class="re-groups-time" title="${(item.isComment) ? 'Letzter Kommentar' : 'Letzter Beitrag'} vom ${item.time.toLocaleString('de-DE').slice(0,-3)}">${dateTime(item.time, !mobile.matches)}</span>
</span>
</span>
</span>
</div>
</a>
</div>`
        );
        if (item.isAdmin) {
            $('div.Container--3h4tt div.js-groups div.re-add a').last().append(`
<div class="re-groups-admin" title="Du verwaltest diese Gruppe">
<span>ADMIN</span>
</div>`
            );
        }
        if (item.isComment) {
            $('div.Container--3h4tt div.js-groups div.re-add a').last().append(`
<div class="re-groups-new ml-" style="margin-right:.1em" title="Aktueller Kommentar vom ${item.time.toLocaleString('de-DE').slice(0,-3)}">
<svg label="Aktueller Kommentar" role="img" aria-hidden="false" viewBox="0 0 1024 1024">
<path d="M943.3 408.7c-49.9-49.9-118.9-80.7-195-80.7H222.7l.1-183.5L0 367.4l222.8 222.8.1-183.5h525.4c54.4 0 103.6 22.1 139.3 57.7 35.6 35.7 57.6 84.9 57.6 139.3 0 54.4-22 103.6-57.7 139.3-35.7 35.7-84.9 57.7-139.3 57.7H616.3c-14.2 0-25.7 11.5-25.7 25.7v27.5c0 14.2 11.5 25.7 25.7 25.7h131.9c76.2 0 145.1-30.9 195-80.7 49.9-49.9 80.7-118.9 80.7-195 .1-76.3-30.8-145.3-80.6-195.2z"></path>
</svg>
</div>`
             );
        }
        if (item.actPosts) {
            $('div.Container--3h4tt div.js-groups div.re-add a').last().append(`
<div class="re-groups-new ml-" title="${item.countPosts} ${(item.countPosts == 1) ? 'neuer Beitrag' : 'neue Beiträge'} seit ${item.actPosts.toLocaleString('de-DE').slice(0,-3)}">
<span style="margin-right:.25em">${item.countPosts}</span>
<svg label="Neue Beiträge" style="font-size:.675em" role="img" aria-hidden="false" viewBox="0 0 100 100">
<path d="M50 0a50 50 0 100 100A50 50 0 1050 0z"></path>
</svg>
</div>`
            );
        }
        if (item.actPhotos) {
            $('div.Container--3h4tt div.js-groups div.re-add a').last().append(`
<div class="re-groups-new ml-" title="${item.countPhotos} ${(item.countPhotos == 1) ? 'neues Bild' : 'neue Bilder'} seit ${item.actPhotos.toLocaleString('de-DE').slice(0,-3)}">
<span style="margin-right:.25em">${item.countPhotos}</span>
<svg label="Neue Bilder" role="img" aria-hidden="false" viewBox="0 0 1024 1024">
<path d="M656 579c0 80-64 145-144 145s-144-65-144-145 64-145 144-145 144 65 144 145zM512 808c-63 0-120-26-161-68s-67-98-67-162c0-63 26-120 67-162s98-67 161-67 120 25 161 67 67 99 67 162c0 64-26 120-67 162s-98 68-161 68zm449-589H762L644 107c-7-7-16-11-27-11H407c-11 0-20 4-27 11L262 219H63c-35 0-63 28-63 63v583c0 35 28 63 63 63h898c35 0 63-28 63-63V282c0-35-28-63-63-63z"></path>
</svg>
</div>`
            );
        }
	}

    //highlight selected item
    $('div.Container--3h4tt div.js-groups div.re-add a').each(function() {
        if (location.href.match(this.href) || (mobile.matches && lastGroupUrl.match(this.href))) {
            if (!refresh) {
                if (typeof $(this)[0].scrollIntoViewIfNeeded === 'function') {
                    $(this)[0].scrollIntoViewIfNeeded(true);
                } else {
                    $(this)[0].scrollIntoView({block: 'center'});
                }
            }
            $(this).find('span.re-groups-name').attr('style', 'color:rgba(255,255,255,.87)');
            $(this).attr('style', `background-color:${color9}`);
            $(this).find('div.re-groups-new').remove();
        }
    });

    //refresh content on re-click, remove indicators on first click
    $('div.Container--3h4tt div.js-groups div.re-add a').click(function() {
        lastGroupUrl = this.href;
        if (location.href.match(this.href)) {
            $('ul.Container--1I9Gx button').click();
            return false;
        } else {
            var index = $('div.Container--3h4tt div.js-groups div.re-add a').index(this);
            groupsList[index].last += '-hide';
            groupsList[index].actPosts = 0;
            groupsList[index].actPhotos = 0;
            return true;
        }
    });
    refresh = false;
}


// ***** Toggle group manage mode *****
function groupManageMode (jNode) {
    if (resigned) $(jNode).prepend('<span class="re-add">!</span>');
    $(jNode).off().on('dblclick', function() {
        $(this).find('.re-add').remove();
        resigned = !resigned;
        if (resigned) $(this).prepend('<span class="re-add">!</span>');
    });
}


// ***** Compact view for group posts *****
function groupPostsViewMode (jNode) {
	var viewMode = localStorage.getItem('REgroupPostsView');
	var linkTextCompact = 'Kompakt', linkTextDefault = 'Mit Kommentaren';
	var linkText = (viewMode == 'compact') ? linkTextCompact : linkTextDefault;
	$('div.Container--1cJVr').append(
		'<span class="re-posts-view" title="Umschalten">' + linkText + '</span>' +
		'<span class="layout-item icon icon-dropdown dropdown__arrow"></span>'
	);
	$('span.re-posts-view').click(function() {
		var oldViewMode = localStorage.getItem('REgroupPostsView');
		var linkText = linkTextCompact, viewMode = 'compact';
		if (oldViewMode == 'compact') {
			linkText = linkTextDefault;
			viewMode = 'default';
		}
		localStorage.setItem('REgroupPostsView', viewMode);
		$('span.re-posts-view').text(linkText);
		$('span.CommentCount--3uCNR').each(function() {
			handleGroupComment(this);
		});
	});
}


// ***** Show/hide group comments *****
function refreshGroupComments (jNode) {
	var thisNode = $(jNode).find('span.CommentCount--3uCNR');  // span.CommentCount--1Eef2
	handleGroupComment(thisNode);
}


// ***** Handle a single group post *****
function handleGroupComment (thisNode) {
	var viewMode = localStorage.getItem('REgroupPostsView');
	var timestamp = $(thisNode).parent().parent().nextAll().find('span.PostDate--2LVzF').last().text();
	if (viewMode == 'compact') {
		$(thisNode).parent().parent().nextAll().hide();
		if (timestamp == '') {
			$(thisNode).text('Kommentar schreiben');
		} else {
			$(thisNode).after(
				'<span class="ml--"> • ' + timestamp + '</span>'
			);
		}
		$(thisNode).not(':has(a)').wrapInner('<a></a>').off('click').click(function() {
			$(thisNode).parent().parent().nextAll().toggle();
		});
	} else {
		$('div.CommentsArea--3iSoQ, div.js-add-comment').show();
		$(thisNode).find('a').contents().unwrap('a');
		$(thisNode).off('click');
		$(thisNode).next('span').remove();
		if (timestamp == '') {
			$(thisNode).text('0 Kommentare');
		}
	}
}


// ***** Group posts *****
function handleGroupPosts (jNode) {
    //...
}


// ***** Sort group members by distance from travel location *****

//init
var travelName = '';
sessionStorage.setItem('PR_SETTINGS:groups:members:sorting', localStorage.getItem('PR_SETTINGS:groups:members:sorting'));

function groupTravelLocation (jNode) {
	var viewMode = localStorage.getItem('REgroupTravelLocation');
    var toggleTravel = 'span.re-member-travel';
    var refreshClick = 'ul.Container--1I9Gx button';
    $('div.Container--e53RO div.Container--13Nkp .re-add').remove();
	$('div.Container--e53RO div.Container--13Nkp').has('div:contains("Entf"), div:contains("Dist")').append(
        `<span class="re-add re-member-travel icon icon-airplane ml- pl" style="cursor:pointer" title="Travel"><span class="pl-"></span></span>`
	);
    handleTravelLocation(viewMode, toggleTravel, refreshClick);
    $('span.re-member-travel').click(function() {
		var viewMode = localStorage.getItem('REgroupTravelLocation');
        var toggleTravel = 'span.re-member-travel';
        var refreshClick = 'ul.Container--1I9Gx button';
		viewMode = (viewMode == 'travel') ? 'default' : 'travel';
		localStorage.setItem('REgroupTravelLocation', viewMode);
		handleTravelLocation(viewMode, toggleTravel, refreshClick);
	});

    //save sorting permanently
    localStorage.setItem('PR_SETTINGS:groups:members:sorting', sessionStorage.getItem('PR_SETTINGS:groups:members:sorting'));
}


function handleTravelLocation (viewMode, toggleTravel, refreshClick) {
    if (viewMode == 'travel') {
        $(toggleTravel).addClass('re-selected');
        if (xhrTravelLat) {
            $.ajax({headers: ajaxHead(), url: `/api/geocoder/private/name?lat=${xhrTravelLat}&lon=${xhrTravelLong}&lang=de`})

            .done(function (data) {
                if (data[0].name) {
                    travelName = data[0].name;
                }
                var travelEdit = '<a href="/explore/edit" class="re-edit-travel icon icon-pen pl-" title="Reiseziel in TRAVEL ändern"></a>';
                $(toggleTravel).find('span').html(travelName).attr('title', travelName);
                $(toggleTravel).next('a.re-edit-travel').remove();
                $(toggleTravel).after(travelEdit);
                travelMode = true;
                $(refreshClick).get(0).click();
            });

        } else {
            $.ajax({headers: ajaxHead(), url: `/api/v4/locations/travel`})

            .done(function (data) {
                var travelEdit = '';
                if (data.length) {
                    var last = data.length -1;
                    xhrTravelLat = data[last].lat;
                    xhrTravelLong = data[last].long;
                    travelName = data[last].name;
                    travelMode = true;
                    travelEdit = '<a href="/explore/edit" class="re-edit-travel icon icon-pen pl-" title="Reiseziel in TRAVEL ändern"></a>';
                } else {
                    travelMode = false;
                    travelEdit = '<a href="/explore/new" class="re-edit-travel">Füge in TRAVEL dein Reiseziel hinzu!</a>';
                }
                $(toggleTravel).find('span').html(travelName).attr('title', travelName);
                $(toggleTravel).next('a.re-edit-travel').remove();
                $(toggleTravel).after(travelEdit);
                $(refreshClick).get(0).click();
            });

        }

    } else {
        $(toggleTravel).removeClass('re-selected');
        $(toggleTravel).find('span').text('').removeAttr('title');
        $(toggleTravel).next('a.re-edit-travel').remove();
        travelMode = false;
        $(refreshClick).get(0).click();
   }
}


// ***** Show picture info in slide show *****
function imgInfo (jNode) {
	var eq = ($('#photos div[class*=swipe__element]').length == 1) ? 0 : 1;
	var imgName = $('#photos div[class*=swipe__element]').eq(eq).find('div.fit img').attr('src');
	if (imgName && imgName.match(/^\/img\//)) {
		//var imgNameTxt = `${imgName.substr(imgName.lastIndexOf('/') + 1, 5)}...`;
        var imgNameTxt = uploadDate(`${imgName.substr(imgName.lastIndexOf('/') + 1, 8)}`);
        var info = `<a class="mr+" style="align-self:flex-end; color:rgba(255,255,255,.5); cursor:default" title="Upload-Datum" href="${imgName}">${imgNameTxt}</a>`;
        var date = `<span class="re-mobi ml+" style="color:rgba(255,255,255,.5)">${$('div.js-sidebar div.txt-quiet').text().trim()}</span>`;
        var name = `<a class="re-mobi re-link ml+" style="z-index:1000" href="${$('#photos div.reactView a').attr('href')}">${$('#photos div.reactView a > [title]').attr('title').trim()}</a>`;

        //desktop
        $('#photos div[class*="js-counter"] div[class*="Container"]').not(':has(a)').prepend(`<span class="re-desk">${info}</span>`);

        //mobile
        $('#photos div.js-actions').not(':has(.re-mobi)').prepend(`<div class="re-mobi layout mb pb-">${info}</div>`);
        $('#photos div[class*="js-counter"] div[class*="Container"]').not(':has(.re-mobi)').append(date + name);
	}

	//URLs in picture caption
	$('#photos div[class^="Description"]').each(function() {
		var replacedText = linkify($(this).text());
		$(this).html(replacedText);
	});

    //fix for arrow and esc keys
    $('#photos button').first().focus();

    //remove false blurred layers
    $('#photos.layer.layer--centered').slice(1).remove();
}


// ***** Show picture info in picture rating *****
function ratingInfo (jNode) {
    $('#picture-rating .re-add').remove();
    $('#picture-rating button').blur();
	var imgName = $('#picture-rating img').attr('src');
    if (imgName) {
        var imgNameTxt = `${imgName.substr(imgName.lastIndexOf('/') + 1, 5)}...`;
        //var imgDate = uploadDate(`${imgName.substr(imgName.lastIndexOf('/') + 1, 8)}`);
        var imgNameMax = sessionStorage.getItem('REratingMax');
        imgNameMax = (imgNameMax ? imgNameMax : imgNameTxt);
        if (imgNameTxt >= imgNameMax) {
            sessionStorage.setItem('REratingMax', imgNameTxt);
        }
        var color = (parseInt(imgNameTxt,16) + 1 < parseInt(imgNameMax,16)) ? 'rgba(255,0,0,0.8)' : 'rgba(255,255,255,0.375)';
        $('#picture-rating div > span > span').append(
            `<a style="color:${color}; font-size:0.85em; cursor:default" class="ml mr- re-add" href="${imgName}">${imgNameTxt}</a>`
        );
    }

    //set focus on reload or skip button
    $('#picture-rating p + button, #picture-rating button[class^="TertiaryButton__Element-"]').focus();
}


// ***** Remove getting location spinner in Gear browser *****

//init
var cleanDone = false;

function removeFeedbackLayer (jNode) {
    if (cleanDone == false && $(jNode).has('div.spinner.spinner--centered').length) {
        $(jNode).has('div.spinner.spinner--centered').fadeOut(1000, function() { $(jNode).remove(); });
        cleanDone = true;
    }
}


// ***** Relogin after timeout *****
function reLogin (jNode) {
    if ($(jNode).siblings('div.ui-dimmer__buttons').find('span.ui-button--primary').filter(':contains("Erneut einloggen"), :contains("Log in again"), :contains("Reconnexion")').length) {
        $(jNode).hide();
        $(jNode).after('<div class="spinner-container re-add"><div class="spinner"></div></div>');
        $(jNode).siblings('div.ui-dimmer__buttons').hide();
        $(jNode).siblings('div.ui-dimmer__text').text('Erneut einloggen ...');
        location.reload();
    }
}


// ***** XHR *****

//init
var xhrTravelLat = '', xhrTravelLong = '';
var travelMode = false;
var resigned = false;

(function() {
    let oldXHROpen = window.XMLHttpRequest.prototype.open;
    window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {

        if (url.match(/v4\/messages\//)) {
            //...
        }

        if (url.match(/v4\/messages\/conversations\?/)) {
            //url = url.replace('&length=15', '&length=120');
        }

        if (url.match(/v4\/contacts\?/)) {
            if ($('#contacts-custom-tags a.ui-tag--selected span.ui-tag__label').text().trim() == '[ A-Z ]') {
                url += '&sort_criteria=NAME_ASC';
                url = url.replace(/&filter%5Btags%5D%5B%5D\=\d+/, ``);
            }
            if ($('#contacts-custom-tags a.ui-tag--selected span.ui-tag__label').text().trim() == '[ Login ]') {
                url += '&sort_criteria=LAST_LOGIN_DESC';
                url = url.replace(/&filter%5Btags%5D%5B%5D\=\d+/, ``);
            }
            if ($('#contacts-custom-tags a.ui-tag--selected span.ui-tag__label').text().trim() == '[ Online ]') {
                url += '&filter[online]=true';
                url = url.replace(/&filter%5Btags%5D%5B%5D\=\d+/, ``);
            }
            //url += '&sort_criteria=LAST_LOGIN_DESC';
            //url += '&sort_criteria=NAME_ASC';
            //url += '&filter[online]=true';
            url = url.replace('/contacts?length=100&pick=items.*.profile&lang=de', '/contacts?length=999&pick=items.*.profile&lang=de');
        }

        if (location.pathname.match(/^\/messenger\/contacts\/name/)) {
            if (url.match(/filter%5Busername%5D\=/)) {
                url += '&sort_criteria=NAME_ASC';
                url = url.replace(/filter%5Busername%5D\=\*/, '');
            }
        }

        if (location.pathname.match(/^\/radar\//)) {
            if (travelMode) {
                url = url.replace(/filter%5Blocation%5D%5Blat%5D\=[-0-9\.]+/, `filter[location][lat]=${xhrTravelLat}`);
                url = url.replace(/filter%5Blocation%5D%5Blong%5D\=[-0-9\.]+/, `filter[location][long]=${xhrTravelLong}`);
            }
            //url = url.replace(/filter%5Btravellers_filter%5D\=EXCLUDED/, '');
            //url = url.replace(/filter%5Btravellers_filter%5D\=INCLUDED/, 'filter%5Btravellers_filter%5D=EXCLUDED');
            //url = url.replace(/sort_criteria\=NEARBY_ASC/, 'sort_criteria=NEARBY_DESC');
        }

        if (location.pathname.match(/^\/(radar|hunqz)\//) && url.match(/filter%5Blocation%5D/)) {
            var radius = $('.js-distance-radius .noUi-handle').attr('aria-valuenow');
            if (radius >= 115500 && radius < 116500) {  //116
                url = url.replace(/filter%5Blocation%5D%5Bradius%5D\=[0-9\.]+/, `filter[location][radius]=${1000000}`);
            }
            if (radius >= 116500 && radius < 117500) {  //117
                url = url.replace(/filter%5Blocation%5D%5Bradius%5D\=[0-9\.]+/, `filter[location][radius]=${2000000}`);
            }
            if (radius >= 117500 && radius < 118500) {  //118
                url = url.replace(/filter%5Blocation%5D%5Bradius%5D\=[0-9\.]+/, `filter[location][radius]=${3000000}`);
            }
            if (radius >= 118500 && radius < 119500) {  //119
                url = url.replace(/filter%5Blocation%5D%5Bradius%5D\=[0-9\.]+/, `filter[location][radius]=${4000000}`);
            }
        }

        if (url.match(/v4\/groups\//)) {
            if (travelMode) {
                url = url.replace(/filter%5Blocation%5D%5Blat%5D\=[-0-9\.]+/, `filter[location][lat]=${xhrTravelLat}`);
                url = url.replace(/filter%5Blocation%5D%5Blong%5D\=[-0-9\.]+/, `filter[location][long]=${xhrTravelLong}`);
            }
            if (resigned) {
                url = url.replace('statuses[]=REJECTED', 'statuses[]=NONE');
            }
        }

        if (url.match(/v4\/profiles\/popular/)) {
            if (travelMode) {
                url = url.replace('sort_criteria=LAST_LOGIN_DESC', 'sort_criteria=NEARBY_ASC');
                url = url.replace(/filter%5Blocation%5D%5Blat%5D\=[-0-9\.]+/, `filter[location][lat]=${xhrTravelLat}`);
                url = url.replace(/filter%5Blocation%5D%5Blong%5D\=[-0-9\.]+/, `filter[location][long]=${xhrTravelLong}`);
            }
            //url = url.replace('sort_criteria=LAST_LOGIN_DESC', 'sort_criteria=SIGNUP_DESC');
        }

        if (location.pathname.match(/^\/explore\//) && url.match(/v4\/profiles\?lang/)) {
            var loc = location.pathname.match(/[-0-9\.]+/g);
            xhrTravelLat = loc[0];
            xhrTravelLong = loc[1];

            //var radius = $('.js-distance-radius .noUi-handle').attr('aria-valuenow');
            //url = url.replace('sort_criteria=NEARBY_ASC', `sort_criteria=LAST_LOGIN_DESC&filter[location][radius]=${radius}`);
            //url = url.replace('sort_criteria=NEARBY_ASC', `sort_criteria=SIGNUP_DESC&filter[location][radius]=${radius}`);
        }

        return oldXHROpen.apply(this, arguments);
    }
})();


// ***** Run at login *****

//init
var commonGroupsList = [], visitorsList = [], visitsList = [];

function runAtLogin (jNode) {

    //init common groups
    commonGroupsList = [];
    $.ajax({headers: ajaxHead(), url: '/api/v4/profiles/me/groups?lang=de&length=10000&pick=items.*.(id,name,display_name)'})

    .done(function (data) {
        for (var item of data.items) {
            commonGroupsList.push(item);
        }
        //console.log(commonGroupsList);
        waitForKeyElements ('li[class*="list__item--group-tile-"] a, .profile .js-profile-stats section > div > a, .profile .js-profile-groups ul > a, .js-list li[class*="Tile--"] a, #search div[class^="GroupThird-"] a', handleGroupTiles);
    });

    //visitors, visits
    $.ajax({headers: ajaxHead(), url: '/api/v4/visitors?lang=de&length=10000&pick=items.*.(name,date_visited)'})
    .done(function (data) {
        for (var item of data.items) {
            //visitorsList.push(item);
        }
        //console.log(visitorsList);
    });
    $.ajax({headers: ajaxHead(), url: '/api/v4/visits?lang=de&length=10000&pick=items.*.(name,date_visited)'})
    .done(function (data) {
        for (var item of data.items) {
            //visitsList.push(item);
        }
        //console.log(visitsList);
    });
}



waitForKeyElements ('div#marionette.is-logged-in', runAtLogin);
waitForKeyElements ('#search input', searchInput);
waitForKeyElements ('header li', menuLinks);
waitForKeyElements ('div[class*="Central--"] ul.Tabbed-nav--2c5l9 li.is-selected', navLinks);
waitForKeyElements ('#offcanvas-nav div[class^="Version"], div.js-filter-button', handleVersionBookmark);
waitForKeyElements ('#messenger[class!="layer layer--nav-primary is-hidden"] span.idbldl-0', previewMessage);
waitForKeyElements ('#messenger div:is(.js-correspondence, .js-header) div.reactView > div', showLoginLocation);
waitForKeyElements ('#messenger div.js-correspondence div.js-header-region div[class*="ContextMenu__"] ul', threadOptionsMenu);
waitForKeyElements ('#messenger div.js-chat .reactView a[class^="Box-sc-"]', contactsMessage);
waitForKeyElements ('#messenger div.js-contacts .reactView a[class^="Box-sc-"]', messageContacts);
waitForKeyElements ('div.js-wrapper a.tile__link > div.tile__image, :is(#visits, #search, .js-profiles) :is(a.tile__link, a.listresult)', handleTiles);
waitForKeyElements (':is(div.js-wrapper, div.js-admins, #group-preview) a.js-contact', handleContactStrip);
waitForKeyElements ('#profiles a.tile__link, #profiles a.listresult', handleRadar);
waitForKeyElements ('div.stream__content a.listitem__body, div.stream__content div.js-list', handleActivity);
waitForKeyElements ('div.is-profile-loaded', handleProfile);
waitForKeyElements ('span[class^="profile__travel-headline--location--"]', linkTravelHeadline);
//waitForKeyElements ('div.profile__container--error', linksError);
waitForKeyElements ('div.js-groups', recentPosts);
waitForKeyElements ('#manage div[class^="FilterBar__Container"] > div > div', groupManageMode);
//waitForKeyElements ('div.Sorting--3E8ZW', groupPostsViewMode);
//waitForKeyElements ('div.Main--W3X4g div.js-post-list p.js-content div.reactView button', handleGroupPosts);
waitForKeyElements ('div.Container--e53RO div.Container--13Nkp button', groupTravelLocation);
waitForKeyElements ('div.js-post-list div.Container--3__0Z', refreshGroupComments);
waitForKeyElements ('#photos div[class*=swipe__element]', imgInfo);
waitForKeyElements ('#picture-rating img, #picture-rating p[class^="Text-sc-"]', ratingInfo);
waitForKeyElements (':is(.js-chat .js-scrollable, .Xjs-main .js-sidebar, .profile-section--gallery .scrollable, [id^="single-album-"]) div[class="js-paging-spinner spinner-container l-fancy"]', fixScroll);
waitForKeyElements ('#spotlight-container > div.layer-container-clickable', removeFeedbackLayer);
waitForKeyElements ('div.layer--error div.icon-warning-triangle', reLogin);