How to generate third field in _ga and _gid? - cookies

I'm investigate too much on _gid and _ga. And as i know, the definition of them:
_ga: used to identify unique users and it expires after 2 years.
_gid: used to identify unique users and it expires after 24 hours.
Example:
_ga: GA1.3.292651669.1502954402
_gid: GA1.3.974792242.1509957189
From what are the values in _ga cookie?, I know the meaning of each filed in _ga. And it's the same for _gid.
But I don't know how to generate third field, random generated user ID(for _ga:292651669 and for _gid: 974792242).
I tried to delete both _ga & _gid and I get the new couple _ga: GA1.3.2097663971.1509959880 and _gid: GA1.3.1180999143.1509959880. The third fields of both are changed. So how can they generate and how google identify user by them. Assumption I open browser today with a couple of _gid and _ga, and tomorrow, I cleared all cookies, ga will create of new couplw (_gid,_ga).; It means I'm in today that different tomorrow's me.
Please help me.
Thanks & Best Regards,
Jame

Here is the code from analytics.js release 2017-09-21 that generates the random id.
It's a random value based on current time, userAgent, cookie, referrer and history.length from the window object.
var O = window;
// var M = document;
// Stack Overflow doesn't allow cookie access in sandbox, so lets fake it:
var M = [];
M.cookie = "cookieName=someValue";
var hd = function() {
return Math.round(2147483647 * Math.random())
}
function La(a) {
var b = 1, c;
if (a)
for (b = 0,
c = a.length - 1; 0 <= c; c--) {
var d = a.charCodeAt(c);
b = (b << 6 & 268435455) + d + (d << 14);
d = b & 266338304;
b = 0 != d ? b ^ d >> 21 : b
}
return b
}
var ra = function() {
for (var a = O.navigator.userAgent + (M.cookie ? M.cookie : "") + (M.referrer ? M.referrer : ""), b = a.length, c = O.history.length; 0 < c; )
a += c-- ^ b++;
return [hd() ^ La(a) & 2147483647, Math.round((new Date).getTime() / 1E3)].join(".")
}
document.getElementById('output').innerText = ra();
<h3>Output:</h3>
<pre id="output"></pre>

Related

Fuzzy matching in Google Sheets

Trying to compare two columns in GoogleSheets with this formula in Column C:
=if(A1=B1,"","Mismatch")
Works fine, but I'm getting a lot of false positives:
A.
B
C
MARY JO
Mary Jo
JAY, TIM
TIM JAY
Mismatch
Sam Ron
Sam Ron
Mismatch
Jack *Ma
Jack MA
Mismatch
Any ideas how to work this?
This uses a score based approach to determine a match. You can determine what is/isn't a match based on that score:
Score Formula = getMatchScore(A1,B1)
Match Formula = if(C1<.7,"mismatch",)
function getMatchScore(strA, strB, ignoreCase=true) {
strA = String(strA);
strB = String(strB)
const toLowerCase = ignoreCase ? str => str.toLowerCase() : str => str;
const splitWords = str => str.split(/\b/);
let [maxLenStr, minLenStr] = strA.length > strB.length ? [strA, strB] : [strB, strA];
maxLenStr = toLowerCase(maxLenStr);
minLenStr = toLowerCase(minLenStr);
const maxLength = maxLenStr.length;
const minLength = minLenStr.length;
const lenScore = minLength / maxLength;
const orderScore = Array.from(maxLenStr).reduce(
(oldItem, nItem, index) => nItem === minLenStr[index] ? oldItem + 1 : oldItem, 0
) / maxLength;
const maxKeyWords = splitWords(maxLenStr);
const minKeyWords = splitWords(minLenStr);
const keywordScore = minKeyWords.reduce(({ score, searchWord }, nItem) => {
const newSearchWord = searchWord?.replace(new RegExp(nItem, ignoreCase ? 'i' : ''), '');
score += searchWord.length != newSearchWord.length ? 1: 0;
return { score, searchWord: newSearchWord };
}, { score: 0, searchWord: maxLenStr }).score / minKeyWords.length;
const sortedMaxLenStr = Array.from(maxKeyWords.sort().join(''));
const sortedMinLenStr = Array.from(minKeyWords.sort().join(''));
const charScore = sortedMaxLenStr.reduce((oldItem, nItem, index) => {
const surroundingChars = [sortedMinLenStr[index-1], sortedMinLenStr[index], sortedMinLenStr[index+1]]
.filter(char => char != undefined);
return surroundingChars.includes(nItem)? oldItem + 1 : oldItem
}, 0) / maxLength;
const score = (lenScore * .15) + (orderScore * .25) + (charScore * .25) + (keywordScore * .35);
return score;
}
try:
=ARRAYFORMULA(IFERROR(IF(LEN(
REGEXREPLACE(REGEXREPLACE(LOWER(A1:A), "[^a-z ]", ),
LOWER("["&B1:B&"]"), ))>0, "mismatch", )))
Implementing fuzzy matching via Google Sheets formula would be difficult. I would recommend using a custom formula for this one or a full blown script (both via Google Apps Script) if you want to populate all rows at once.
Custom Formula:
function fuzzyMatch(string1, string2) {
string1 = string1.toLowerCase()
string2 = string2.toLowerCase();
var n = -1;
for(i = 0; char = string2[i]; i++)
if (!~(n = string1.indexOf(char, n + 1)))
return 'Mismatch';
};
What this does is compare if the 2nd string's characters order is found in the same order as the first string. See sample data below for the case where it will return mismatch.
Output:
Note:
Last row is a mismatch as 2nd string have r in it that isn't found at the first string thus correct order is not met.
If this didn't meet your test cases, add a more definitive list that will show the expected output of the formula/function so this can be adjusted, or see player0's answer which solely uses Google Sheets formula and is less stricter with the conditions.
Reference:
https://stackoverflow.com/a/15252131/17842569
The main limitation of traditional fuzzy matching is that it doesn’t take into consideration similarities outside of the strings. Topic clustering requires semantic understanding. Goodlookup is a smart function for spreadsheet users that gets very close to semantic understanding. It’s a pre-trained model that has the intuition of GPT-3 and the join capabilities of fuzzy matching. Use it like vlookup or index match to speed up your topic clustering work in google sheets.
https://www.goodlookup.com/

Get last row ignoring formula in google script

I used a google script that move row from one sheet to another from column A to column D. On column E i have a formula. How can i put data on last row from Column A to D from example, ignoring formula from column E. Can someone help me with this?
function onEdit(e){
let r = e.range;
if (r.columnStart != 4 || r.rowStart == 1 || e.value == null) return;
const sh = SpreadsheetApp.getActive();
const valArray = ["Waiting","In progress","Complete"];
const destArray = ["Order","Open order","Complete order"];
let dest = sh.getSheetByName(destArray[valArray.indexOf(e.value)]);
let src = sh.getActiveSheet();
if (dest.getName() == src.getName()) return;
src.getRange(r.rowStart,1,1,4).moveTo(dest.getRange(dest.getLastRow()+1,1,1,4));
src.deleteRow(r.rowStart);
}
Here an example of my problem, maybe this will explain better:https://docs.google.com/spreadsheets/d/1qowADCPYiyej25ezXtjVLO5fvg9Gr9rolX3bh2-ZAG4/edit#gid=0
Replace dest.getLastRow() by dest.getLastDataRow('A') and add this function:
Object.prototype.getLastDataRow = function(col){
var lastRow = this.getLastRow();
var range = this.getRange(col + lastRow);
if (range.getValue() !== "") {
return lastRow;
} else {
return range.getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
}
};
I still sugest you to erase all formulas in column E and put in E1
={"price * 2";ARRAYFORMULA(if(C2:C>0;C2:C*2;""))}
so that the formula will populate / will be active the new row

Dropdown query has no error, but returns no results

I'm hoping to allow others to sort through the data using some dropdowns, but they shouldn't have to use all of them if they don't need to.
My query function:
=QUERY(CATALOG!A2:I259,"SELECT * WHERE 1=1 "&IF(A2="Any",""," AND B = '"&A2&"' ")&IF(B2="ANY",""," AND C = '"&B2&"' ")&IF(C2="Any",""," AND D = '"&C2&"' ")&IF(D2="Any",""," AND E = '"&D2&"' ")&IF(E2="Any",""," AND F = '"&E2&"' ")&IF(F2="Any",""," AND G = '"&F2&"' ")&IF(G2="Any",""," AND H = '"&G2&"' "),1)
Whenever I ran this, there wasn't an error but the query didn't give any items.
I initially only tested one of the dropdowns but received nothing. I plugged in a known product into the inputs and still received nothing.
Link to copy of the spreadsheet with dataset and function
https://docs.google.com/spreadsheets/d/1s3tOm_6g8n66HT9md3EAXY7XwbkpmPggYhxdF-zv5ok/edit?usp=sharing
Some of the search parameters seem to be numbers. In that case do not use the single quotes (as that will turn them into strings). See if this works
=QUERY(CATALOG!A2:I259,"SELECT * WHERE 1=1 "&IF(A2="Any",""," AND B = "&A2&" ")&IF(B2="ANY",""," AND C = '"&B2&"' ")&IF(C2="Any",""," AND D = '"&C2&"' ")&IF(D2="Any",""," AND E = '"&D2&"' ")&IF(E2="Any",""," AND F = "&E2&" ")&IF(F2="Any",""," AND G = "&F2&" ")&IF(G2="Any",""," AND H = '"&G2&"' "),1)
try shorter:
=QUERY(CATALOG!A2:I259,
"where 1=1 "&
IF(A2="Any",," and B = "&A2)&
IF(B2="Any",," and C = '"&B2&"'")&
IF(C2="Any",," and D = '"&C2&"'")&
IF(D2="Any",," and E = '"&D2&"'")&
IF(E2="Any",," and F = "&E2)&
IF(F2="Any",," and G = "&F2)&
IF(G2="Any",," and H = '"&G2&"'"), 1)

Copy cell if certain condition met

I know there are already many topics like mine, but I am completely new to programming scripts and therefore I ask you to help me with following problem:
In cell B2 is the user name and in cell C2 the submitter type - if the submitter type is "Requester" then the user name of cell B2 should be copied to cell AE2 - the problem is, that I also want to keep the previous user names if the submitter type change and gets updated...
That means, first the submitter type is "Requester" then the system should copy the user name to cell AE2 - if the submitter type of my line change, then the already copied user name should not change - understood what I want? This should work for all lines of the spreadsheet...
I tried the code but got following error:
Maybe you can improve the code for me?
I changed those 2:
Before:
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
After:
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
The error now is:
new error
Or was the change wrong? Maybe you mean that:
var userNameColumn = 2; //Column where the user name is written
var subTypeColumn = 5; //Column where the submitter type is written ex. "Requester"
var sUserNameColumn = 3; //Column where the user name is saved
But then only one object (username) is known instead of 2 before - subTypeCell and sUserNameCell again undefined - that says the debugger - the code looks now like that (again with my changes, because then 2 objects instead only 1 is known):
You can do something like this:
var userNameColumn = 2; //Column where the user name is written
var subTypeColumn = 3; //Column where the submitter type is written ex. "Requester"
var sUserNameColumn = 5; //Column where the user name is saved
function saveUserName() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
for (var i = 1; i <= numRows; i++) {
var userNameCell = rows.getCell(i, userNameColumn);
var subTypeCell = rows.getCell(i, subTypeColumn);
var sUserNameCell = rows.getCell(i, sUserNameColumn);
if(sUserNameCell.isBlank() && subTypeCell.getValue() === 'Requester') {
sUserNameCell.setValue(userNameCell)
};
}
}
Firstly this defines the columns that you are working with, which are the "Username"(in the scriptuserNameColumn), the column with the "Submitter type"(in the scriptsubTypeColumn) and the column where the username is saved (in the scriptsUserNameColumn). Each have been assigned a number corresponding to a columns in spreadsheet, wher 2 is B, 3 is C, and so on. You can change them to your needs.
Then we create a function called saveUserName() inside this function we get the current spreadsheet, we define what range in the spreadsheet we will work with, here it is everything, then we get the number of rows that has data in them.
After that we go through the data we defined, and setup some variables we can use for each cell. Then we create our if statement, which states, if the "Saved-User-Name-Cell" is empty and the "Submitter-Type-Cell" = the word 'Requester' then we grab the "Saved-User-Name-Cell" and set it's value equal to what is within the "User-Name-Cell".
That's it!

split List<User> in multiple List<User> in c#

I want to split List of user generic List into its small list with each 5 records.
Ex
I have List: u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15.
so must be split into
List1:u1,u2,u3,u4,u5
List2:u6,u7,u8,u9,u10
List3:u11,u12,u13,u14,u15
Any direct method available or need programing logic in c# ?
You can group on the index:
List<List<User>> lists =
list
.Select((u, i) => new { List = i / 5, User = u })
.GroupBy(g => g.List, g => g.User)
.Select(g => g.ToList())
.ToList();
You can also use Range to make a loop and get a part of the list for each iteration:
List<List<User>> lists =
Enumerable.Range(0, (list.Count + 4) / 5)
.Select(n => list.Skip(n * 5).Take(5).ToList())
.ToList();
You can Use Skip(count) and Take(count) methods.
// These are your objects, put here your init code
var list = Enumerable.Range(1, 20).ToList();
var lists = new List<int>[(list.Count + 4) / 5]; // The array of lists you wanted
for (int i = 0; i < lists.Length; i++)
{
lists[i] = list.Skip(i * 5).Take(5).ToList();
}
The (list.Count + 4) / 5 is a method to round UP the division (if I have 6 elements in list, I want two sublists)
If you really need a List of List...
var lists = new List<List<int>>((list.Count + 4) / 5);
for (int i = 0; i < lists.Capacity; i++)
{
lists.Add(list.Skip(i * 5).Take(5).ToList());
}
I think this might be more efficient since you're not doing groupings, orderings and such. This is just a single iteration over the dataset.
var splitList= new List<IEnumerable<User>>();
List<User> currentList = null;
int count = 0;
foreach(var user in users)
{
if (0 == count% 5)
{
currentList = new List<User>(5);
returnValue.Add(currentList);
}
currentList.Add(key);
count++;
}
return returnValue;