' + svg + "";
}
// Wait for the form's data (it comes late in Google's page), with the page covered
// meanwhile so that Google's own editor is never seen
function ugfFormsFullEditor(kind) {
const veil = document.createElement("div");
veil.id = "ugf-fe-wait";
veil.style.cssText = "position:fixed;inset:0;z-index:2147483001;background:#fff;display:flex;align-items:flex-start;justify-content:center;font:13px arial,sans-serif;color:#666;padding-top:120px;";
veil.textContent = "Loading...";
(document.body || document.documentElement).appendChild(veil);
const t0 = Date.now();
let loadedAt = 0;
const tick = function() {
const model = ugfFeParse();
if (document.readyState !== "loading" && !loadedAt) {
loadedAt = Date.now();
}
if (model) {
veil.remove();
ugfFormsFullEditorBuild(kind, model);
return;
}
if ((loadedAt && Date.now() - loadedAt > 3000) || Date.now() - t0 > 20000) {
// not a form Gplex can read: Google's editor, dressed, as before
veil.remove();
ugfFormsEditor(ugfFormsEditorEra());
return;
}
setTimeout(tick, 100);
};
tick();
}
function ugfFormsFullEditorBuild(kind, model) {
const A = ugfDocsArt();
const esc = ugfDocsEsc;
const l = String(layout || "");
const old = kind === "o08" || kind === "o10" || kind === "o11";
const cardsUi = kind === "fk" || kind === "fm" || kind === "fg";
const gm2 = kind === "fg";
const T = ugfFeTypes();
const types = ugfFeTypesFor(kind);
const who = ugfDocsWho();
const signedIn = !!(who.email || who.name);
const html = document.documentElement;
html.setAttribute("gplex-fe", kind);
console.log("[Gplex] Forms: layout " + layout + " (" + kind + ", Gplex's editor, " + model.items.length + " items)");
// the form's colour (a colour you picked stays; the 2025 default is the purple of 2016-2024)
const accent = (function() {
let c = "";
document.querySelectorAll("head style").forEach(function(st) {
const m = (st.textContent || "").match(/\.kaAt2\.KKjvXb \.KKHx9e \{background-color: ([^;}]+)/);
if (m && !c) {
c = m[1].trim();
}
});
if (!c || /87, 70, 227|103, 58, 183/.test(c)) {
return { main: "#673ab7", light: "#ede7f6" };
}
const rgb = (c.match(/\d+/g) || []).map(Number);
const light = rgb.length === 3 ? "rgb(" + rgb.map(function(v) {
return Math.round(v + (255 - v) * 0.88);
}).join(", ") + ")" : "#ede7f6";
return { main: c, light: light };
})();
const style = document.createElement("style");
style.id = "ugf-fe-styles";
style.textContent = ugfFeCss(kind, accent);
(document.head || document.documentElement).appendChild(style);
document.title = (old || kind === "o13" ? "Edit form - " : "") + model.title + (old ? " - Google Docs" : " - Google Forms");
const shell = document.createElement("div");
shell.id = "ugf-fe";
shell.setAttribute("kind", kind);
document.body.appendChild(shell);
const st = { sel: null, view: "edit", status: "saved", resp: null, respErr: null, published: null, helpShown: {}, n: 0, settingsTab: "general" };
model.items.forEach(function(it) {
it.gid = it.id;
it.key = "k" + (st.n++);
if (it.help) {
st.helpShown[it.key] = true;
}
});
// ---- saving, through Google's editor
let lastKey = 0;
shell.addEventListener("keydown", function() {
lastKey = Date.now();
}, true);
const typing = function() {
const a = document.activeElement;
return !!(a && shell.contains(a) && /^(INPUT|TEXTAREA)$/.test(a.tagName) && Date.now() - lastKey < 1500);
};
const drv = ugfFeDriver(function(s, what) {
st.status = s;
paintStatus();
if (s === "error") {
note(old ? "Sorry, your changes could not be saved. Reload the form " :
kind === "o13" ? "Some changes could not be saved. Reload " : "Couldn't save your last change. Reload ", true);
}
}, typing);
const go = function(name, args, cb) {
drv.go(name, args, cb);
};
// ---- small helpers
const itemByKey = function(k) {
return model.items.filter(function(it) {
return it.key === k;
})[0] || null;
};
const idx = function(it) {
return model.items.indexOf(it);
};
const tname = function(t) {
return T[t] ? (old || kind === "o13" ? T[t].old : T[t].g) : (t === "header" ? (old || kind === "o13" ? "Section header" : "Title and description") : t === "page" ? (old || kind === "o13" ? "Page break" : "Section") : t);
};
const isQuestion = function(it) {
return !!T[it.type];
};
let noteTimer = 0;
const note = function(h, stay) {
let n = shell.querySelector(".fenote");
if (!n) {
n = document.createElement("div");
n.className = "fenote";
shell.appendChild(n);
}
n.innerHTML = trusted_policy.createHTML(h || "");
n.style.display = h ? "" : "none";
clearTimeout(noteTimer);
if (h && !stay) {
noteTimer = setTimeout(function() {
n.style.display = "none";
}, 6000);
}
};
const statusText = function() {
if (old && st.status === "saved") {
return "";
}
if (st.status === "saving") {
return old ? "Saving..." : "Saving…";
}
if (st.status === "error") {
return old ? "Not saved" : "Couldn't save";
}
return old ? "Saved" : kind === "o13" ? "All changes saved in Drive" : "All changes saved in Drive";
};
const paintStatus = function() {
shell.querySelectorAll(".festat").forEach(function(s) {
s.textContent = statusText();
s.classList.toggle("err", st.status === "error");
});
const sv = shell.querySelector(".osave");
if (sv) {
sv.disabled = st.status !== "saving";
sv.textContent = st.status === "saving" ? "Saving..." : "Saved";
}
};
const published = function() {
const b = ugfFePublishButton();
return b ? /Published/i.test(b.textContent || "") : true;
};
// ---- the bar at the very top, as each period had it
const gbar = function() {
const mail = who.email || who.name || "";
// the Google bar of the layout's own pages (2007 on), as over the Docs editors
if (l === "2007") {
return ugfNtGbar("classic", ugfDocsLabel(), "2007");
}
if (l === "2009" || l === "2009L") {
return ugfNtGbar("classic", ugfDocsLabel(), "2009");
}
if (l === "2010N") {
return ugfNtGbar("classic", ugfDocsLabel(), "2010");
}
if (kind === "o08") {
const apps = [["Gmail", "https://mail.google.com/"], ["Calendar", "https://calendar.google.com/"], ["Documents", ""], ["Photos", "https://photos.google.com/"],
["Reader", "https://www.google.com/reader/"], ["Web", "https://www.google.com/"]];
return '' + apps.map(function(a) {
return a[1] ? '
' + a[0] + " " : "
" + a[0] + " ";
}).join("") + '
more ▼ ";
}
if (kind === "o10") {
const links = [["Web", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Videos", "https://www.google.com/videohp"], ["Maps", "https://maps.google.com/"],
["News", "https://news.google.com/"], ["Shopping", "https://www.google.com/shopping"], ["Gmail", "https://mail.google.com/"]];
return '";
}
if (kind === "o11" || kind === "o13") {
return ugfNtGbar("dark", ugfDocsHere(), "2011");
}
return "";
};
const avatar = function() {
return signedIn ? '' + ugfGmailAvatar() + " " :
'Sign in ';
};
const formsHome = "https://docs.google.com/forms/u/0/";
// ---- a question as it shows on the form (not being edited)
const preview = function(it) {
const radio = it.type === "mc" ? "radio" : "checkbox";
if (ugfFeChoice(it.type)) {
if (it.type === "list") {
return cardsUi ? '' + it.options.map(function(o, i) {
return '
' + (i + 1) + ". " + esc(o) + "
";
}).join("") + "
" : '' + esc(it.options[0] || "") + " ";
}
return '' + it.options.map(function(o) {
return ' ' + esc(o) + " ";
}).join("") + (it.other ? ' Other: ' : "") + "
";
}
if (it.type === "scale") {
let h = '";
}
if (it.type === "grid" || it.type === "cbgrid") {
let h = '";
}
if (it.type === "paragraph") {
return cardsUi ? 'Long answer text
' : '';
}
if (it.type === "text") {
return cardsUi ? 'Short answer text
' : ' ';
}
if (it.type === "date") {
return cardsUi ? 'Month, day, year ' + ugfFeIcon("event", 20) + "
" : ' ';
}
if (it.type === "time") {
return cardsUi ? 'Time ' + ugfFeIcon("schedule", 20) + "
" : ' ';
}
if (it.type === "file") {
return '' + ugfFeIcon("cloud_upload", 20) + " Add file
";
}
return "";
};
// ---- the editing panel of the old editors (2008-2013)
const oldPanel = function(it) {
const k = it.key;
const lab = kind === "o13" ? ["Question title", "Help text", "Question type"] : ["Question Title", "Help Text", "Question Type"];
if (!isQuestion(it)) {
return '" +
'';
}
let h = '";
h += '';
if (ugfFeChoice(it.type)) {
h += '
' + it.options.map(function(o, i) {
return '
";
}).join("") +
(it.other ? '
' : "") +
'
";
} else if (it.type === "scale") {
const opt = function(from, to, cur) {
let s = "";
for (let v = from; v <= to; v++) {
s += '
" + v + " ";
}
return s;
};
h += '
Scale
' + opt(0, 1, it.lo) + ' to
' + opt(2, 10, it.hi) + " " +
'
' + it.lo + ': label (optional)
' +
'
' + it.hi + ': label (optional)
';
} else if (it.type === "grid" || it.type === "cbgrid") {
const list = function(word, arr, f) {
return '
' + word + " " + arr.map(function(v, i) {
return '
";
}).join("") + '
' + (arr.length + 1) + '.
';
};
h += '
' + list("Rows", it.rows, "row") + list("Columns", it.cols, "col") + "
";
} else {
h += '
' + (it.type === "paragraph" ? '' : ' ') + "
";
}
h += "
";
h += '";
return h;
};
const oldItem = function(it, n) {
const on = st.sel === it.key;
const qn = isQuestion(it);
let h = '';
if (it.type === "page") {
h += '
Page break
';
}
if (on) {
h += '
' + (qn ? esc(tname(it.type)) : esc(tname(it.type))) + "
" + oldPanel(it);
} else {
h += '
' +
'
' + (esc(it.title) || (qn ? "Untitled question " : "")) + (it.required ? ' * ' : "") + "
" +
(it.help ? '
' + esc(it.help) + "
" : "") + (qn ? preview(it) : "");
}
return h + "
";
};
// ---- the add-item menu (every period's list of types)
const addMenuItems = function() {
const out = types.map(function(t) {
return { t: t, label: tname(t) };
});
out.push({ sep: true });
out.push({ t: "header", label: tname("header") });
if (kind !== "o08") {
out.push({ t: "page", label: tname("page") });
}
return out;
};
// ---- a question card (2014 on)
const optIcon = function(it, i) {
if (it.type === "list") {
return '' + (i + 1) + ". ";
}
return ugfFeIcon(it.type === "mc" ? "radio_button_unchecked" : "check_box_outline_blank", 24);
};
const cardItem = function(it) {
const on = st.sel === it.key;
const k = it.key;
const qn = isQuestion(it);
if (it.type === "page") {
const pageNo = model.items.slice(0, idx(it) + 1).filter(function(x) {
return x.type === "page";
}).length + 1;
return 'Section ' + pageNo + " of " + (model.items.filter(function(x) {
return x.type === "page";
}).length + 1) + "
" +
' ' +
'" +
(on ? '" : "") + "
";
}
if (!on) {
return '' + (esc(it.title) || (qn ? "Question" : "Untitled Title")) + (it.required ? ' * ' : "") + "
" +
(it.help ? '
' + esc(it.help) + "
" : "") + (qn ? preview(it) : "") + "
";
}
let h = '' + ugfFeIcon("drag_indicator", 20) + "
";
if (!qn) {
h += '
' +
'
" +
'
";
return h;
}
h += '";
if (st.helpShown[k]) {
h += '";
}
if (ugfFeChoice(it.type)) {
h += '' + it.options.map(function(o, i) {
return '
";
}).join("") +
(it.other ? '
" : "") +
'
' + optIcon(it, it.options.length) + '
' +
(it.type !== "list" && !it.other ? '
or add "Other" ' : "") + "
";
} else if (it.type === "scale") {
const opt = function(from, to, cur) {
let s = "";
for (let v = from; v <= to; v++) {
s += '" + v + " ";
}
return s;
};
h += '' + opt(0, 1, it.lo) + ' to ' + opt(2, 10, it.hi) + "
" +
'' + it.lo + '
' +
'' + it.hi + '
';
} else if (it.type === "grid" || it.type === "cbgrid") {
const list = function(word, arr, f) {
return '' + word + "
" + arr.map(function(v, i) {
return '
";
}).join("") + '
' + (arr.length + 1) + '.
';
};
h += '' + list("Rows", it.rows, "row") + list("Columns", it.cols, "col") + "
";
} else {
h += preview(it);
}
h += '";
return h;
};
// ---- the summary of responses
const summary = function() {
if (st.respErr) {
return '' + (old ? "Sorry, the responses could not be loaded." : "Couldn't load responses.") + "
";
}
if (!st.resp) {
return '' + (old ? "Loading..." : "Loading…") + "
";
}
const R = st.resp;
const n = R.rows.length;
let h = '' + n + " response" + (n === 1 ? "" : "s") + "
";
if (!published()) {
h += '
";
}
if (!n) {
return h + '
' + (cardsUi ? "Waiting for responses" : "No responses yet.") + "
";
}
model.items.filter(isQuestion).forEach(function(it) {
const cols = [];
R.head.forEach(function(hd, i) {
if (hd === it.title || hd.indexOf(it.title + " [") === 0) {
cols.push(i);
}
});
if (!cols.length) {
return;
}
h += '' + esc(it.title) + '
';
const vals = [];
R.rows.forEach(function(r) {
cols.forEach(function(c) {
if (r[c]) {
vals.push(r[c]);
}
});
});
h += vals.length + " response" + (vals.length === 1 ? "" : "s") + "
";
if (ugfFeChoice(it.type) || it.type === "scale" || it.type === "grid" || it.type === "cbgrid") {
const count = {};
let keys = [];
if (ugfFeChoice(it.type)) {
keys = it.options.slice();
} else if (it.type === "scale") {
for (let v = it.lo; v <= it.hi; v++) {
keys.push(String(v));
}
} else {
keys = it.cols.slice();
}
vals.forEach(function(v) {
(it.type === "checkbox" || it.type === "cbgrid" ? v.split(/;\s*/) : [v]).forEach(function(x) {
if (keys.indexOf(x) < 0) {
keys.push(x);
}
count[x] = (count[x] || 0) + 1;
});
});
const max = Math.max.apply(null, keys.map(function(x) {
return count[x] || 0;
}).concat([1]));
h += '
' + keys.map(function(x) {
const c = count[x] || 0;
return '' + esc(x) + ' ' + c +
(old || kind === "o13" ? " (" + Math.round(c / Math.max(1, n) * 100) + "%)" : "") + " ";
}).join("") + "
";
} else {
h += '
' + vals.slice(-40).reverse().map(function(v) {
return '
' + esc(v) + "
";
}).join("") + "
";
}
h += "
";
});
return h + "";
};
const loadResponses = function() {
st.resp = null;
st.respErr = null;
ugfFeResponses(function(err, r) {
st.respErr = err;
st.resp = r || null;
if (st.view === "responses") {
draw();
}
});
};
// ---- the settings, as each period had them
const S = function(label) {
return ugfFeSettingOn(label);
};
const settingsRows = function(list) {
return list.map(function(r) {
return ' " + esc(r[0]) + " ";
}).join("");
};
const confText = function() {
const ta = Array.prototype.slice.call(document.querySelectorAll("textarea[aria-label='Confirmation message']")).filter(function(x) {
return !x.closest("#ugf-fe");
})[0];
return ta ? ta.value || ta.getAttribute("data-initial-value") || "" : "";
};
// ---- the whole page
const titleBlock = function() {
if (old) {
return '";
}
return "";
};
const draw = function() {
const scrollEl = shell.querySelector(".fescroll");
const top = scrollEl ? scrollEl.scrollTop : 0;
let h = gbar();
if (old) {
const logo = kind === "o08" ? ' ' :
kind === "o10" ? 'docs ' : ' ';
h += '' +
'Add item ▾ Email this form ' +
'See responses ▾ More actions ▾ ' +
'Saved
';
h += '";
} else if (kind === "o13") {
h += '' + esc(model.docTitle) +
' ☆ ' + ugfFeIcon("folder", 16) + '
Send form ' + avatar() + "
" +
'' + ugfFeIcon("edit", 16) + ' Edit questions View responses View live form ';
h += '";
} else {
// the card editors
const hdrTitle = '' + esc(model.docTitle) + " ";
const icons = '' + ugfFeIcon("visibility", 24) + " " +
(l === "2022" ? "" : '' + ugfFeIcon("settings", 24) + " ");
const send = '' + (kind === "fm" ? "SEND" : kind === "fk" ? "Send form" : "Send") + " ";
if (kind === "fm") {
h += '";
} else {
h += '";
}
const tabs = [["edit", gm2 ? "Questions" : kind === "fm" ? "QUESTIONS" : "Questions"], ["responses", gm2 ? "Responses" : kind === "fm" ? "RESPONSES" : "Responses"]];
if (l === "2022") {
tabs.push(["settings", "Settings"]);
}
const tabRow = '' + tabs.map(function(t) {
return '
' + t[1] + " ";
}).join("") + "
";
h += (kind === "fm" ? "" : tabRow) + '";
}
shell.innerHTML = trusted_policy.createHTML(h);
ugfNtMenus(shell, ugfMenusRounded());
paintStatus();
placeFab();
const sc = shell.querySelector(".fescroll");
if (sc) {
sc.scrollTop = top;
sc.addEventListener("scroll", placeFab);
}
shell.querySelectorAll("textarea").forEach(grow);
};
// the card toolbar follows the card being edited (2014 on)
const placeFab = function() {
const fab = shell.querySelector(".cfab");
if (!fab) {
return;
}
const on = shell.querySelector(".ccard.on") || shell.querySelector(".ccard.ctc");
const body = shell.querySelector(".cbody");
if (!on || !body) {
return;
}
const r = on.getBoundingClientRect();
const b = body.getBoundingClientRect();
const sc = shell.querySelector(".fescroll").getBoundingClientRect();
let y = r.top - b.top;
y = Math.max(y, sc.top - b.top + 8);
fab.style.top = y + "px";
};
const grow = function(ta) {
if (!ta.classList.contains("cqt") && !ta.classList.contains("chelp") && !ta.classList.contains("cfd")) {
return;
}
ta.style.height = "auto";
ta.style.height = ta.scrollHeight + "px";
};
// ---- menus of Gplex's own
let menu = null;
const closeMenu = function() {
if (menu) {
menu.remove();
menu = null;
}
};
const openMenu = function(anchor, items, onPick) {
closeMenu();
menu = document.createElement("div");
menu.className = "femenu";
menu.innerHTML = trusted_policy.createHTML(items.map(function(it, i) {
if (it.sep) {
return '
';
}
return '' + (it.icon ? ugfFeIcon(it.icon, 24) : "") + "" + esc(it.label) + " ";
}).join(""));
shell.appendChild(menu);
const r = anchor.getBoundingClientRect();
menu.style.left = Math.min(r.left, window.innerWidth - menu.offsetWidth - 8) + "px";
menu.style.top = Math.min(r.bottom + 2, window.innerHeight - menu.offsetHeight - 8) + "px";
menu.addEventListener("click", function(ev) {
const a = ev.target.closest("a[data-i]");
ev.preventDefault();
if (!a || a.classList.contains("dis")) {
return;
}
closeMenu();
onPick(items[+a.getAttribute("data-i")]);
});
};
document.addEventListener("mousedown", function(ev) {
if (menu && !menu.contains(ev.target) && !ev.target.closest("[data-menu], .ctype, .cmore")) {
closeMenu();
}
}, true);
// ---- dialogs of Gplex's own
const dialog = function(title, body, buttons, onButton) {
const f = document.createElement("div");
f.className = "fedlgf";
f.innerHTML = trusted_policy.createHTML('' + body + "
" +
'
' + buttons.map(function(b, i) {
return '' + esc(b) + " ";
}).join("") + "
");
shell.appendChild(f);
const close = function() {
f.remove();
};
f.addEventListener("click", function(ev) {
if (ev.target.closest(".x")) {
ev.preventDefault();
close();
return;
}
const b = ev.target.closest("button[data-i]");
if (b) {
if (onButton(+b.getAttribute("data-i"), f) !== false) {
close();
}
}
});
const first = f.querySelector("input, textarea");
if (first) {
first.focus();
}
return f;
};
// the form's link, and email through your own mail
const sendForm = function() {
const link = model.viewUrl;
const pub = function() {
if (!published()) {
go("publish", []);
}
};
if (old) {
dialog("Email this form", 'To:
' +
'Subject:
' +
'", ["Send", "Cancel"], function(i, f) {
if (i === 0) {
pub();
window.open("mailto:" + encodeURIComponent(f.querySelector(".to").value) + "?subject=" + encodeURIComponent(f.querySelector(".sub").value) +
"&body=" + encodeURIComponent("I've invited you to fill out the form " + model.title + ". To fill it out, visit:\n" + link), "_blank");
}
});
return;
}
dialog("Send form", '' +
'' + (published() ? "" : 'The form will be published so that it accepts responses.
'),
[cardsUi ? (kind === "fm" ? "SEND" : "Send") : "Send", kind === "o13" ? "Done" : cardsUi && kind === "fm" ? "COPY LINK" : "Copy link"], function(i, f) {
pub();
if (i === 0) {
window.open("mailto:" + encodeURIComponent(f.querySelector(".to").value) + "?subject=" + encodeURIComponent(f.querySelector(".sub").value) +
"&body=" + encodeURIComponent(f.querySelector(".msg").value + "\n" + link), "_blank");
} else if (navigator.clipboard) {
navigator.clipboard.writeText(link).catch(function() {});
note(old ? "Link copied." : "Link copied to clipboard");
}
});
const ln = shell.querySelector(".fedlg .lnk");
if (ln) {
ln.addEventListener("focus", function() {
ln.select();
});
}
};
const settingsDialog = function() {
const body = '" +
'" + settingsRows([["Collect email addresses", "Collect email addresses"], ["Limit to 1 response", "Limit to 1 response"],
["Respondents can edit after submit", "Allow response editing"], ["Respondents can see summary charts and text responses", "View results summary"]]) + "
" +
'" + settingsRows([["Show progress bar", "Show progress bar"], ["Shuffle question order", "Shuffle question order"],
["Show link to submit another response", "Show link to submit another response"]]) +
'
Confirmation message:
";
const f = dialog("Settings", body, [kind === "fm" ? "SAVE" : "Save", kind === "fm" ? "CANCEL" : "Cancel"], function(i, fence) {
if (i === 0) {
fence.querySelectorAll("input[data-set]").forEach(function(cb) {
const lab = cb.getAttribute("data-set");
if (S(lab) !== cb.checked) {
go(lab === "Collect email addresses" ? "emails" : "setting", lab === "Collect email addresses" ? [cb.checked ? "Responder input" : "Do not collect"] : [lab, cb.checked]);
}
});
const c = fence.querySelector(".conf");
if (c && c.value !== confText()) {
go("confirmation", [c.value]);
}
}
});
f.addEventListener("click", function(ev) {
const t = ev.target.closest("[data-t]");
if (t) {
ev.preventDefault();
st.settingsTab = t.getAttribute("data-t");
f.querySelectorAll("[data-t]").forEach(function(x) {
x.classList.toggle("on", x === t);
});
f.querySelectorAll(".dpane").forEach(function(p) {
p.style.display = p.getAttribute("data-p") === st.settingsTab ? "" : "none";
});
}
});
};
// ---- changing things
const select = function(k) {
if (st.sel === k) {
return;
}
st.sel = k;
draw();
const box = shell.querySelector(".oi.on input[data-f='title'], .ccard.on .cqt, .ccard.on .cst");
if (box && !old) {
box.focus();
} else if (box && old) {
box.focus();
}
};
const addItem = function(what, t) {
const cur = itemByKey(st.sel);
const at = cur ? idx(cur) + 1 : model.items.length;
const it = { id: "", gid: "", key: "k" + (st.n++), title: "", help: "", type: what === "question" ? t || "mc" : what, required: false,
options: ["Option 1"], other: false, lo: 1, hi: 5, loLabel: "", hiLabel: "", rows: ["Row 1"], cols: ["Column 1"] };
if (what === "question" && !ugfFeChoice(it.type)) {
it.options = [];
}
model.items.splice(at, 0, it);
const after = cur ? cur : (at > 0 ? model.items[at - 1] : null);
go("add", [after, what], function(err, gid) {
if (!err && gid) {
it.gid = gid;
}
});
if (what === "question" && it.type !== "mc") {
go("type", [it, it.type]);
}
st.sel = it.key;
draw();
const box = shell.querySelector(".oi.on input[data-f='title'], .ccard.on .cqt, .ccard.on .cst");
if (box) {
box.focus();
}
};
const commit = function(el) {
const f = el.getAttribute("data-f");
const it = itemByKey(el.getAttribute("data-k"));
const v = el.type === "checkbox" ? el.checked : el.value;
if (f === "ftitle") {
model.title = v;
go("formText", ["title", function() {
return model.title;
}]);
return;
}
if (f === "fdesc") {
model.desc = v;
go("formText", ["desc", function() {
return model.desc;
}]);
return;
}
if (f === "conf") {
go("confirmation", [v]);
return;
}
if (!it) {
return;
}
if (f === "title") {
it.title = v;
go("title", [it, function() {
return it.title;
}]);
} else if (f === "help") {
it.help = v;
go("help", [it, function() {
return it.help;
}]);
} else if (f === "opt") {
it.options[+el.getAttribute("data-i")] = v;
goOptions(it);
} else if (f === "row" || f === "col") {
(f === "row" ? it.rows : it.cols)[+el.getAttribute("data-i")] = v;
goGrid(it);
} else if (f === "lo" || f === "hi") {
it[f] = +v;
go("scale", [it, it.lo, it.hi, it.loLabel, it.hiLabel]);
draw();
} else if (f === "loLabel" || f === "hiLabel") {
it[f] = v;
go("scale", [it, it.lo, it.hi, it.loLabel, it.hiLabel]);
} else if (f === "req") {
it.required = !!v;
go("required", [it, !!v]);
} else if (f === "type") {
setType(it, v);
}
};
const goOptions = function(it) {
go("options", [it, function() {
return it.options.slice();
}]);
};
const goGrid = function(it) {
go("grid", [it, function() {
return it.rows.slice();
}, function() {
return it.cols.slice();
}]);
};
const setType = function(it, t) {
if (it.type === t) {
return;
}
const wasChoice = ugfFeChoice(it.type);
it.type = t;
if (ugfFeChoice(t) && !wasChoice && !it.options.length) {
it.options = ["Option 1"];
}
if (t === "list") {
it.other = false;
}
go("type", [it, t]);
draw();
};
shell.addEventListener("input", function(ev) {
const el = ev.target;
const f = el.getAttribute("data-f");
grow(el);
if (!f) {
return;
}
const it = itemByKey(el.getAttribute("data-k"));
if (f === "title" && it) {
it.title = el.value;
} else if (f === "help" && it) {
it.help = el.value;
} else if (f === "opt" && it) {
it.options[+el.getAttribute("data-i")] = el.value;
} else if ((f === "row" || f === "col") && it) {
(f === "row" ? it.rows : it.cols)[+el.getAttribute("data-i")] = el.value;
} else if (f === "ftitle") {
model.title = el.value;
} else if (f === "fdesc") {
model.desc = el.value;
}
});
shell.addEventListener("change", function(ev) {
const el = ev.target;
if (el.hasAttribute("data-set")) {
// the settings on the page itself (2013, and the Settings tab of 2022)
if (!el.closest(".fedlg")) {
const lab = el.getAttribute("data-set");
go(lab === "Collect email addresses" ? "emails" : "setting", lab === "Collect email addresses" ? [el.checked ? "Responder input" : "Do not collect"] : [lab, el.checked]);
}
return;
}
if (el.hasAttribute("data-f")) {
commit(el);
}
});
// a new option: typing in "Click to add option" / "Add option"
const addOption = function(el) {
const it = itemByKey(el.getAttribute("data-k"));
if (!it) {
return;
}
const g = el.getAttribute("data-g");
if (g) {
(g === "row" ? it.rows : it.cols).push(el.value || (g === "row" ? "Row " : "Column ") + ((g === "row" ? it.rows : it.cols).length + 1));
goGrid(it);
} else {
it.options.push(el.value || "Option " + (it.options.length + 1));
goOptions(it);
}
draw();
const list = shell.querySelectorAll((g ? "[data-f='" + g + "']" : "[data-f='opt']") + "[data-k='" + it.key + "']");
const last = list[list.length - 1];
if (last) {
last.focus();
last.select();
}
};
shell.addEventListener("focusin", function(ev) {
const el = ev.target;
if (el.matches(".oadd, .cadd, .oaddg, .caddg") && !drv.restoring) {
addOption(el);
}
});
shell.addEventListener("keydown", function(ev) {
const el = ev.target;
if (ev.key === "Enter" && el.matches("input[data-f='opt']")) {
// Enter in an option starts the next one, as Google's did
ev.preventDefault();
el.blur();
const it = itemByKey(el.getAttribute("data-k"));
if (it && +el.getAttribute("data-i") === it.options.length - 1) {
const add = shell.querySelector(".oadd[data-k='" + it.key + "'], .cadd[data-k='" + it.key + "']");
if (add) {
add.focus();
}
}
} else if (ev.key === "Enter" && el.matches("input[data-f='title'], input[data-f='ftitle'], input[data-f='help']")) {
ev.preventDefault();
el.blur();
}
});
shell.addEventListener("click", function(ev) {
const t = ev.target;
const a = t.closest("a, button, [data-menu], [data-view], [data-act], .oi, .ccard");
if (!a || !shell.contains(a)) {
return;
}
if (a.matches("a[href='#'], button, [data-menu], [data-view], [data-act], .ctype, .cmore, [data-add]")) {
// handled below
}
if (a.classList.contains("reload")) {
ev.preventDefault();
window.location.reload();
return;
}
if (a.classList.contains("me")) {
return;
}
const view = a.getAttribute("data-view");
if (view) {
ev.preventDefault();
st.view = view;
st.sel = null;
if (view === "responses") {
loadResponses();
}
draw();
return;
}
if (a.classList.contains("toedit")) {
ev.preventDefault();
st.view = "edit";
draw();
return;
}
if (a.classList.contains("dlcsv")) {
ev.preventDefault();
window.open("https://docs.google.com/forms/d/" + ugfFeFileId() + "/downloadresponses?tz_offset=" + (-new Date().getTimezoneOffset() * 60000), "_blank");
return;
}
if (a.classList.contains("dopub")) {
ev.preventDefault();
go("publish", [], function() {
draw();
});
return;
}
const act = a.getAttribute("data-act");
if (act === "send" || act === "email") {
ev.preventDefault();
sendForm();
return;
}
if (act === "preview") {
ev.preventDefault();
if (model.viewUrl) {
window.open(model.viewUrl, "_blank");
}
return;
}
if (act === "settings") {
ev.preventDefault();
settingsDialog();
return;
}
if (act === "rename") {
ev.preventDefault();
dialog("Rename form", ' ', ["OK", "Cancel"], function(i, f) {
if (i === 0) {
model.docTitle = f.querySelector(".nm").value;
go("docTitle", [model.docTitle]);
draw();
}
});
return;
}
const m = a.getAttribute("data-menu");
if (m) {
ev.preventDefault();
let items = [];
let pick = null;
if (m === "add" || m === "insert") {
items = addMenuItems();
pick = function(x) {
if (x.t === "header" || x.t === "page") {
addItem(x.t);
} else {
addItem("question", x.t);
}
};
} else if (m === "resp") {
items = [{ label: old ? "Summary" : "Summary of responses", act: "sum" }, { label: "Download responses (.csv)", act: "csv" }, { sep: true },
{ label: published() ? "Accepting responses" : "Start accepting responses", act: "pub", on: published() }];
pick = function(x) {
if (x.act === "sum") {
st.view = "responses";
loadResponses();
draw();
} else if (x.act === "csv") {
window.open("https://docs.google.com/forms/d/" + ugfFeFileId() + "/downloadresponses?tz_offset=" + (-new Date().getTimezoneOffset() * 60000), "_blank");
} else if (x.act === "pub" && !published()) {
go("publish", []);
}
};
} else if (m === "more") {
items = [{ label: "Edit confirmation", act: "conf" }, { label: "View published form", act: "live" }, { sep: true },
{ label: published() ? "Accepting responses" : "Start accepting responses", act: "pub", on: published() }];
pick = function(x) {
if (x.act === "conf") {
dialog("Edit confirmation", 'Confirmation message
" +
settingsRows([["Show link to submit another response", "Show link to submit another response"], ["Publish response summary", "View results summary"]]), ["Save", "Cancel"], function(i, f) {
if (i === 0) {
const c = f.querySelector(".conf").value;
if (c !== confText()) {
go("confirmation", [c]);
}
f.querySelectorAll("input[data-set]").forEach(function(cb) {
if (S(cb.getAttribute("data-set")) !== cb.checked) {
go("setting", [cb.getAttribute("data-set"), cb.checked]);
}
});
}
});
} else if (x.act === "live") {
window.open(model.viewUrl, "_blank");
} else if (x.act === "pub" && !published()) {
go("publish", []);
}
};
} else if (m === "file") {
items = [{ label: "Send form", act: "send" }, { label: "Rename...", act: "rename" }, { sep: true }, { label: "Forms home", act: "home" }];
pick = function(x) {
if (x.act === "send") {
sendForm();
} else if (x.act === "rename") {
shell.querySelector("[data-act='rename']").click();
} else {
window.location.href = formsHome;
}
};
} else if (m === "view") {
items = [{ label: "Live form", act: "live" }, { label: "Summary of responses", act: "sum" }];
pick = function(x) {
if (x.act === "live") {
window.open(model.viewUrl, "_blank");
} else {
st.view = "responses";
loadResponses();
draw();
}
};
} else if (m === "help") {
items = [{ label: "Forms Help", act: "help" }];
pick = function() {
window.open("https://support.google.com/docs/topic/9055404", "_blank");
};
} else if (m === "hmore") {
items = [{ label: "Forms home", act: "home" }, { label: "Download responses (.csv)", act: "csv" }, { sep: true }, { label: published() ? "Accepting responses" : "Publish form", act: "pub", on: published() }];
pick = function(x) {
if (x.act === "home") {
window.location.href = formsHome;
} else if (x.act === "csv") {
window.open("https://docs.google.com/forms/d/" + ugfFeFileId() + "/downloadresponses?tz_offset=" + (-new Date().getTimezoneOffset() * 60000), "_blank");
} else if (!published()) {
go("publish", []);
}
};
}
openMenu(a, items, pick);
return;
}
const addWhat = a.getAttribute("data-add");
if (addWhat) {
ev.preventDefault();
addItem(addWhat);
return;
}
// the card's type menu (2014 on)
if (a.classList.contains("ctype")) {
ev.preventDefault();
const it = itemByKey(a.getAttribute("data-k"));
const groups = [["text", "paragraph"], ["mc", "checkbox", "list"], ["file"], ["scale", "grid", "cbgrid"], ["date", "time"]];
const items = [];
groups.forEach(function(g) {
const got = g.filter(function(x) {
return types.indexOf(x) > -1;
});
if (got.length) {
if (items.length) {
items.push({ sep: true });
}
got.forEach(function(x) {
items.push({ t: x, label: tname(x), icon: T[x].mi, on: it && it.type === x });
});
}
});
openMenu(a, items, function(x) {
setType(it, x.t);
});
return;
}
if (a.classList.contains("cmore")) {
ev.preventDefault();
const it = itemByKey(a.getAttribute("data-k"));
openMenu(a, [{ label: "Description", act: "desc", on: !!st.helpShown[it.key] }], function() {
st.helpShown[it.key] = !st.helpShown[it.key];
if (!st.helpShown[it.key] && it.help) {
it.help = "";
go("help", [it, ""]);
}
draw();
const hb = shell.querySelector(".ccard.on .chelp");
if (hb) {
hb.focus();
}
});
return;
}
// an item's own buttons
const box = a.closest(".oi, .ccard");
const it = box ? itemByKey(box.getAttribute("data-k")) : null;
if (a.matches(".oed")) {
ev.preventDefault();
select(it.key);
return;
}
if (a.matches(".odone")) {
ev.preventDefault();
st.sel = null;
draw();
return;
}
if (a.matches(".odup, .cdup") && it) {
ev.preventDefault();
const copy = JSON.parse(JSON.stringify(it));
copy.key = "k" + (st.n++);
copy.gid = "";
model.items.splice(idx(it) + 1, 0, copy);
go("duplicate", [it], function(err, gid) {
if (!err && gid) {
copy.gid = gid;
}
});
st.sel = copy.key;
draw();
return;
}
if (a.matches(".odel, .cdel") && it) {
ev.preventDefault();
model.items.splice(idx(it), 1);
go("remove", [it]);
st.sel = null;
draw();
return;
}
if (a.matches(".orm, .crm") && it) {
ev.preventDefault();
if (a.classList.contains("oth")) {
it.other = false;
go("other", [it, false]);
} else if (a.getAttribute("data-g")) {
const arr = a.getAttribute("data-g") === "row" ? it.rows : it.cols;
arr.splice(+a.getAttribute("data-i"), 1);
goGrid(it);
} else {
it.options.splice(+a.getAttribute("data-i"), 1);
goOptions(it);
}
draw();
return;
}
if (a.matches(".oaddother, .caddother") && it) {
ev.preventDefault();
it.other = true;
go("other", [it, true]);
draw();
return;
}
// a click on an item opens it (a click on the old editors' items too)
if (box && it && st.sel !== it.key && !t.closest("input:not([disabled]), textarea:not([disabled]), select:not([disabled]), button")) {
select(it.key);
} else if (box && box.classList.contains("ctc") && st.sel !== "title") {
st.sel = "title";
shell.querySelectorAll(".ccard.on").forEach(function(c) {
c.classList.remove("on");
});
box.classList.add("on");
placeFab();
}
});
// a click outside the item being edited closes it (the card editors)
shell.addEventListener("mousedown", function(ev) {
if (!cardsUi || !st.sel || st.sel === "title") {
return;
}
if (!ev.target.closest(".ccard, .cfab, .femenu, .fedlgf, .ctabs, .chead, .mbar")) {
st.sel = null;
draw();
}
});
// the account menu from the photo, square until 2019
const onAcct = function(ev) {
const me = ev.target && ev.target.closest ? ev.target.closest("#ugf-fe .me") : null;
if (me) {
ev.preventDefault();
ev.stopPropagation();
if (ev.type === "click") {
ugfGmailAccountMenu(me, ugfMenusRounded() ? "m2018" : "m2013");
}
return;
}
if (ev.target && ev.target.closest && ev.target.closest("#ugf-gmail-accfence")) {
ev.preventDefault();
ev.stopPropagation();
if (ev.type === "click") {
ugfGmailCloseMenus();
}
}
};
window.addEventListener("mousedown", onAcct, true);
window.addEventListener("click", onAcct, true);
window.addEventListener("resize", placeFab);
// leaving with changes not yet made in Google's editor
window.addEventListener("beforeunload", function(ev) {
if (!drv.idle()) {
ev.preventDefault();
ev.returnValue = "";
}
});
draw();
}
// ---- how the Forms editor of each period looked -----------------------------------
function ugfFeCss(kind, accent) {
const A = ugfDocsArt();
const F = "#ugf-fe";
const spr = 'url("' + A.feSprite + '")';
const old = kind === "o08" || kind === "o10" || kind === "o11";
const kennedy = kind === "o11" || kind === "o13";
const cardsUi = kind === "fk" || kind === "fm" || kind === "fg";
const round = kind === "fg";
// the Google bar and the photo corner, from the shared styles (without their
// rule that hides the page underneath: Google's editor must stay usable)
const shared = ugfNtBaseCss("ugf-fe").filter(function(r) {
return r.indexOf("html[gplex-nt]") !== 0 && r.indexOf(F + " {") !== 0;
});
const css = shared.concat([
"html[gplex-fe], html[gplex-fe] body { overflow: hidden !important; }",
"#ugf-gmail-accfence { position: fixed; inset: 0; z-index: 2147483600 !important; }",
"#ugf-gmail-accmenu, #ugf-gmail-appsmenu { z-index: 2147483601 !important; text-align: left; }",
"#ugf-gmail-accmenu a, #ugf-gmail-appsmenu a { text-decoration: none; }",
ugfMapsMenuCss(),
F + " { position: fixed; inset: 0; z-index: 2147483000; display: flex; flex-direction: column; background: #fff; color: #000; font: 13px arial, sans-serif; text-align: left; }",
F + " * { box-sizing: border-box; }",
F + " .mi { display: inline-flex; font-style: normal; } " + F + " .mi svg { display: block; fill: currentColor; }",
F + " .sp { flex: 1; }",
F + " .fescroll { flex: 1; overflow: auto; min-height: 0; position: relative; }",
F + " input, " + F + " textarea, " + F + " select, " + F + " button { font: inherit; color: inherit; }",
F + " .w { width: 100%; }",
F + " .femenu { position: fixed; z-index: 60; background: #fff; min-width: 180px; padding: 4px 0; }",
F + " .femenu a { display: flex; align-items: center; gap: 12px; padding: 5px 24px 5px 16px; color: #222; text-decoration: none; white-space: nowrap; cursor: pointer; }",
F + " .femenu a.dis { color: #aaa; cursor: default; } " + F + " .femenu .sep { border-top: 1px solid #ddd; margin: 4px 0; }",
F + " .fedlgf { position: fixed; inset: 0; z-index: 70; display: flex; align-items: center; justify-content: center; }",
F + " .fedlg { background: #fff; width: 480px; max-width: calc(100vw - 32px); }",
F + " .fedlgh { display: flex; justify-content: space-between; align-items: center; } " + F + " .fedlgh .x { text-decoration: none; font-size: 20px; color: #777; }",
F + " .fedlg .dr { margin: 0 0 12px 0; } " + F + " .fedlg .dr .w { margin: 4px 0; } " + F + " .fedlg .small { font-size: 12px; color: #666; }",
F + " .fedlg .dl { font-weight: bold; margin: 8px 0 4px 0; } " + F + " .fedlg .srow { display: block; margin: 6px 0; }",
F + " .fedlgf2 { display: flex; gap: 8px; }",
F + " .fenote { position: absolute; left: 50%; transform: translateX(-50%); top: 6px; z-index: 65; }",
F + " .festat { color: #666; font-size: 12px; margin: 0 10px; white-space: nowrap; } " + F + " .festat.err { color: #c00; }",
// previews of the questions
F + " .pv { margin: 6px 0 0 0; } " + F + " .pvo { display: block; margin: 4px 0; } " + F + " .pvother { width: 160px; }",
F + " .pvscale td { text-align: center; padding: 2px 8px; } " + F + " .pvscale .lb { color: #666; } " + F + " .pvgrid td { text-align: center; padding: 2px 10px; } " + F + " .pvgrid .rl { text-align: left; }",
F + " .pvin { width: 260px; } " + F + " .pvin.short { width: 120px; } " + F + " .pvta { width: 400px; height: 60px; }",
// the summary of responses
F + " .rsum { padding: 4px 0; } " + F + " .rcount { font-size: 20px; margin: 4px 0 12px 0; } " + F + " .rpub { margin: 0 0 12px 0; } " + F + " .rmsg { color: #666; margin: 12px 0; }",
F + " .ritem { margin: 18px 0; } " + F + " .rq { font-weight: bold; } " + F + " .rn { color: #666; font-size: 12px; margin: 2px 0 8px 0; }",
F + " .rbars { border-collapse: collapse; } " + F + " .rbars td { padding: 3px 8px 3px 0; } " + F + " .rbars .rl { max-width: 240px; } " + F + " .rbars .rb { width: 320px; } " + F + " .rbars .rb span { display: block; height: 14px; background: #3366cc; min-width: 1px; }",
F + " .rtexts .rt { padding: 4px 0; border-bottom: 1px solid #eee; white-space: pre-wrap; }"
]);
if (old || kind === "o13") {
css.push(
// the Google links of 2008-2010
F + " .fetop { display: flex; justify-content: space-between; padding: 3px 8px; font-size: 13px; flex: 0 0 auto; }",
F + " .fetop a { color: #00c; margin-right: 7px; } " + F + " .fetop b { margin-right: 7px; } " + F + " .fetop .right a { margin: 0; } " + F + " .fetop small { font-size: 9px; }",
F + " .fetop.g10 { border-bottom: 1px solid #c9d7f1; padding: 3px 8px 4px 8px; }",
// an item: its tools on hover (the editor's own pencil, copy and bin)
F + " .oi { position: relative; margin: 6px 0; padding: 8px 10px; border: 1px solid transparent; cursor: pointer; }",
F + " .oi .oitools { position: absolute; right: 8px; top: 6px; display: none; gap: 8px; } " + F + " .oi:hover .oitools { display: flex; }",
F + " .oitools a { display: block; background-image: " + spr + "; background-repeat: no-repeat; }",
F + " .oitools .oed { width: 13px; height: 13px; background-position: -55px -61px; } " + F + " .oitools .odup { width: 15px; height: 15px; background-position: -71px -59px; }",
F + " .oitools .odel { width: 13px; height: 13px; background-position: -87px -60px; }",
F + " .oq { font-weight: bold; } " + F + " .ostar { color: #c00; } " + F + " .oh { color: #666; font-size: 12px; margin: 2px 0; }",
F + " .oi.on { cursor: default; } " + F + " .oihead { font-size: 11px; color: #666; margin: 0 0 6px 0; }",
F + " .oedtab { border-collapse: collapse; } " + F + " .oedtab th { text-align: right; padding: 4px 8px 4px 0; white-space: nowrap; width: 112px; vertical-align: top; }",
F + " .oedtab td { padding: 3px 0; } " + F + " .oedtab input.w, " + F + " .oedtab textarea.w { width: 380px; }",
F + " .oedbody { margin: 6px 0 0 120px; } " + F + " .oopt { display: flex; align-items: center; gap: 6px; margin: 3px 0; } " + F + " .oopt input[type=text] { width: 300px; }",
F + " .oopt .on { width: 22px; text-align: right; color: #666; } " + F + " .oopt.add .oadd, " + F + " .oopt.add .oaddg { color: #999; font-style: italic; }",
F + " .orm { display: inline-block; width: 13px; height: 13px; background: " + spr + " -45px -42px no-repeat; }",
F + " .oother input { width: 200px; } " + F + " .or { color: #666; } " + F + " .oscale select { margin: 0 4px; } " + F + " .olab { margin: 6px 0; } " + F + " .olab input { width: 200px; }",
F + " .ogrid { display: flex; gap: 30px; } " + F + " .ogl b { display: block; margin: 0 0 4px 0; } " + F + " .ogl .oopt input[type=text] { width: 180px; }",
F + " .otheir input, " + F + " .otheir textarea { width: 260px; background: #fff; }",
F + " .oedfoot { display: flex; align-items: center; gap: 14px; margin: 10px 0 2px 120px; }",
F + " .opb { font-size: 11px; color: #666; border-top: 2px dashed #aaa; padding-top: 4px; margin-bottom: 6px; }",
F + " .oaddrow { margin: 10px 0; } " + F + " .olink { margin: 20px 0; }"
);
}
if (old) {
const btn = kind === "o11" ? [
F + " .ob { display: inline-flex; align-items: center; height: 29px; padding: 0 10px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px arial, sans-serif; cursor: default; margin-right: 8px; }",
F + " .ob:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); color: #222; } " + F + " .ob[disabled] { opacity: .5; }",
F + " .odone { height: 29px; padding: 0 14px; border: 1px solid #3079ed; border-radius: 2px; background: linear-gradient(#4d90fe, #4787ed); color: #fff; font: bold 11px arial, sans-serif; }"
] : [
F + " .ob { height: 22px; padding: 0 8px; margin-right: 6px; border: 1px solid #aaa; border-radius: 2px; background: " + spr + " 0 -76px repeat-x #e3e3e3; font: 13px arial, sans-serif; color: #000; cursor: pointer; }",
F + " .ob:hover { border-color: #888; } " + F + " .ob[disabled] { color: #888; }",
F + " .odone { height: 22px; padding: 0 12px; border: 1px solid #aaa; border-radius: 2px; background: " + spr + " 0 -76px repeat-x #e3e3e3; font: bold 13px arial, sans-serif; cursor: pointer; }"
];
css.push.apply(css, btn);
css.push(
F + " .ohead { display: flex; align-items: center; gap: 12px; padding: 8px 10px 6px 10px; flex: 0 0 auto; }",
F + " .ologo { display: flex; align-items: flex-end; text-decoration: none; } " + F + " .ologo img { display: block; } " + F + " .ologo .g10 { height: 35px; }",
F + " .ologo .dw { color: #1c51a8; font: 26px arial, sans-serif; margin: 0 0 1px 3px; letter-spacing: -1px; }",
F + " .spr.logo { display: block; width: 105px; height: 23px; background: " + spr + " 0 0 no-repeat; }",
F + " .oname b { font-size: 16px; display: block; } " + F + " .oname .osub { color: #666; font-size: 12px; } " + F + " .olive { color: #00c; }",
F + " .otool { display: flex; align-items: center; padding: 4px 8px; flex: 0 0 auto; " + (kind === "o11" ? "border-bottom: 1px solid #ebebeb; background: #fff; padding: 8px 10px;" :
"background: " + spr + " 0 -96px repeat-x #e5eaf4; border-top: 1px solid #c3d9ff; border-bottom: 1px solid #c3d9ff;") + " }",
F + " .ocanvas { padding: 12px 16px 60px 16px; max-width: 820px; }",
F + " .oform { margin: 0 0 10px 0; } " + F + " .oft { width: 100%; font: bold 22px arial, sans-serif; border: 1px solid #ccc; padding: 3px 5px; margin: 0 0 6px 0; }",
F + " .ofd { width: 100%; font: 13px arial, sans-serif; border: 1px solid #ccc; padding: 3px 5px; resize: vertical; }",
F + " .oreq { color: #c00; font-size: 12px; margin: 8px 0 0 0; }",
F + " .oi:hover { background: " + (kind === "o11" ? "#f5f5f5" : "#fff9dd") + "; border-color: " + (kind === "o11" ? "#e5e5e5" : "#e8d98b") + "; }",
F + " .oi.on, " + F + " .oi.on:hover { background: " + (kind === "o11" ? "#f1f1f1" : "#e8eef7") + "; border-color: " + (kind === "o11" ? "#d8d8d8" : "#c3d9ff") + "; }",
F + " .ohead2 { margin: 0 0 10px 0; } " + F + " .ohead2 a { color: #00c; }",
F + " .femenu { border: 1px solid " + (kind === "o11" ? "rgba(0,0,0,.2)" : "#999") + "; box-shadow: " + (kind === "o11" ? "0 2px 4px rgba(0,0,0,.2)" : "2px 2px 3px rgba(0,0,0,.25)") + "; }",
F + " .femenu a:hover { background: " + (kind === "o11" ? "#eee" : "#e0ecff") + "; }",
F + " .fedlgf { background: rgba(255,255,255,.5); }",
kind === "o11" ? F + " .fedlg { border: 1px solid rgba(0,0,0,.333); box-shadow: 0 4px 16px rgba(0,0,0,.2); padding: 26px 36px; } " + F + " .fedlgh { font-size: 16px; margin: 0 0 16px 0; } " + F + " .fedlgf2 { margin-top: 14px; } " +
F + " .fedlgf2 button { height: 29px; padding: 0 12px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); font: bold 11px arial, sans-serif; color: #444; } " +
F + " .fedlgf2 .pri { border-color: #3079ed; background: linear-gradient(#4d90fe, #4787ed); color: #fff; }"
: F + " .fedlg { border: 1px solid #6b90da; border-radius: 4px; box-shadow: 2px 2px 6px rgba(0,0,0,.3); } " + F + " .fedlgh { background: #e0ecff; padding: 6px 10px; font-weight: bold; border-radius: 4px 4px 0 0; } " +
F + " .fedlgb { padding: 12px 14px 4px 14px; } " + F + " .fedlgf2 { padding: 4px 14px 12px 14px; } " + F + " .fedlgf2 button { padding: 1px 12px; } " + F + " .fedlgf2 .pri { font-weight: bold; }",
F + " .fenote { background: #fad163; padding: 3px 12px; font-weight: bold; border-radius: 3px; top: 34px; } " + F + " .fenote a { color: #00c; }"
);
}
if (kind === "o13") {
css.push(
F + " { background: #f1f1f1; }",
F + " .khead { display: flex; align-items: center; gap: 10px; padding: 8px 16px 0 16px; background: #fff; flex: 0 0 auto; }",
F + " .kicon img { width: 30px; height: 30px; display: block; } " + F + " .ktitle { display: flex; flex-direction: column; }",
F + " .kname { display: flex; align-items: center; gap: 8px; font-size: 18px; color: #222; } " + F + " .kn { cursor: pointer; padding: 1px 3px; border: 1px solid transparent; } " + F + " .kn:hover { border-color: #ccc; }",
F + " .kstar { color: #999; font-size: 16px; } " + F + " .kfold { color: #999; }",
F + " .kmenus { display: flex; align-items: center; margin: 2px 0 4px -6px; } " + F + " .km { padding: 3px 7px; cursor: pointer; color: #222; border: 1px solid transparent; } " + F + " .km:hover { background: #eee; border-color: #ccc; }",
F + " .kb { display: inline-flex; align-items: center; gap: 4px; height: 29px; padding: 0 10px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444 !important; font: bold 11px arial, sans-serif; text-decoration: none; cursor: default; margin-right: 8px; }",
F + " .kb:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); } " + F + " .kb.on { background: #eee; box-shadow: inset 0 1px 2px rgba(0,0,0,.1); border-color: #ccc; color: #222 !important; }",
F + " .kb.blue, " + F + " .odone { border: 1px solid #3079ed; background: linear-gradient(#4d90fe, #4787ed); color: #fff !important; height: 29px; padding: 0 14px; border-radius: 2px; font: bold 11px arial, sans-serif; }",
F + " .ktabs { display: flex; padding: 8px 16px; background: #fff; border-bottom: 1px solid #e5e5e5; flex: 0 0 auto; }",
F + " .kpage { max-width: 880px; margin: 16px auto 60px auto; }",
F + " .kbox, " + F + " .kform { background: #fff; border: 1px solid #e5e5e5; padding: 14px 20px; margin: 0 0 14px 0; }",
F + " .kboxh { font-weight: bold; font-size: 14px; margin: 0 0 8px 0; display: flex; justify-content: space-between; } " + F + " .kboxh a { color: #15c; font-weight: normal; font-size: 13px; }",
F + " .srow { display: block; margin: 6px 0; } " + F + " .kft { margin: 0 0 10px 0; } " + F + " .klab { font-weight: bold; margin: 0 0 4px 0; }",
F + " .kform input.w, " + F + " .kbox textarea.w, " + F + " .kform textarea.w { border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 4px 6px; font: 13px arial, sans-serif; }",
F + " .kform input[data-f=ftitle] { font-size: 18px; }",
F + " .oi:hover { background: #fafafa; border-color: #e5e5e5; } " + F + " .oi.on, " + F + " .oi.on:hover { background: #f7f7f7; border-color: #d8d8d8; }",
F + " .oedtab input.w, " + F + " .oopt input[type=text] { border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 3px 5px; }",
F + " .ksendrow { margin: 0 0 20px 0; }",
F + " .femenu { border: 1px solid rgba(0,0,0,.2); box-shadow: 0 2px 4px rgba(0,0,0,.2); } " + F + " .femenu a:hover { background: #eee; }",
F + " .fedlgf { background: rgba(255,255,255,.75); } " + F + " .fedlg { border: 1px solid rgba(0,0,0,.333); box-shadow: 0 4px 16px rgba(0,0,0,.2); padding: 26px 36px; }",
F + " .fedlgh { font-size: 16px; margin: 0 0 16px 0; } " + F + " .fedlgf2 { margin-top: 14px; }",
F + " .fedlgf2 button { height: 29px; padding: 0 12px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); font: bold 11px arial, sans-serif; color: #444; }",
F + " .fedlgf2 .pri { border-color: #3079ed; background: linear-gradient(#4d90fe, #4787ed); color: #fff; }",
F + " .fenote { background: #f9edbe; border: 1px solid #f0c36d; padding: 4px 14px; font-weight: bold; top: 70px; } " + F + " .fenote a { color: #15c; }",
F + " .me { margin-left: 8px; } " + F + " .me img, " + F + " .me .pfp { width: 32px; height: 32px; }"
);
}
if (cardsUi) {
const sq = round ? "8px" : "0";
const blue = round ? "#1a73e8" : "#4285f4";
css.push(
F + " { background: " + accent.light + "; font: 14px Roboto, arial, sans-serif; color: #202124; }",
F + " a { color: inherit; text-decoration: none; }",
F + " .ib { display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: 50%; color: #5f6368; cursor: pointer; }",
F + " .ib:hover { background: rgba(95,99,104,.08); }",
F + " .chead { display: flex; align-items: center; height: 64px; padding: 0 8px 0 16px; background: #fff; flex: 0 0 auto; }",
F + " .cicon img { width: 40px; height: 40px; display: block; } " + F + " .ctitle { font-size: 18px; margin: 0 8px 0 12px; color: #202124; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40vw; }",
F + " .hfold, " + F + " .hstar { width: 32px; height: 32px; }",
F + " .csend { height: 36px; padding: 0 24px; margin: 0 8px; border: 0; cursor: pointer; font: 500 14px Roboto, arial, sans-serif; }",
F + " .me { display: inline-flex; margin: 0 8px; } " + F + " .me img, " + F + " .me .pfp { width: 32px; height: 32px; border-radius: 50%; display: block; object-fit: cover; }",
F + " .ctabs { display: flex; justify-content: center; background: #fff; height: 42px; flex: 0 0 auto; border-bottom: 1px solid #dadce0; }",
F + " .ctabs a { display: flex; align-items: center; padding: 0 8px; margin: 0 10px; font-weight: 500; color: #202124; border-bottom: 3px solid transparent; }",
F + " .ctabs a.on { color: " + accent.main + "; border-bottom-color: " + accent.main + "; }",
F + " .cbody { position: relative; width: 770px; max-width: calc(100% - 90px); margin: 0 auto; padding: 12px 0 90px 0; }",
F + " .ccol { position: relative; }",
F + " .ccard { position: relative; background: #fff; border: 1px solid #dadce0; border-radius: " + sq + "; margin: 12px 0 0 0; padding: 22px 24px 24px 24px; }",
F + " .ccard.ctc { border-top: 10px solid " + accent.main + "; }",
F + " .ccard.on { border-left: 6px solid " + blue + "; padding-left: 19px; box-shadow: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12); }",
F + " .ccard.ctc.on { border-left: 6px solid " + blue + "; }",
F + " .cft { width: 100%; font: 32px Roboto, arial, sans-serif; border: 0; border-bottom: 1px solid transparent; padding: 0 0 6px 0; outline: none; color: #202124; background: transparent; }",
F + " .cfd { width: 100%; font: 14px Roboto, arial, sans-serif; border: 0; border-bottom: 1px solid transparent; padding: 8px 0 4px 0; outline: none; resize: none; overflow: hidden; background: transparent; color: #202124; }",
F + " .ccard.on .cft, " + F + " .ccard.on .cfd { border-bottom-color: #dadce0; } " + F + " .cft:focus, " + F + " .cfd:focus { border-bottom: 2px solid " + accent.main + " !important; }",
F + " .cdrag { position: absolute; left: 50%; top: 2px; transform: translateX(-50%) rotate(90deg); color: #dadce0; }",
F + " .crow1 { display: flex; gap: 16px; align-items: flex-start; } " + F + " .cqtw { flex: 1; }",
F + " .cqt { width: 100%; min-height: 56px; background: #f8f9fa; border: 0; border-bottom: 1px solid #80868b; padding: 16px; font: 16px Roboto, arial, sans-serif; resize: none; overflow: hidden; outline: none; color: #202124; }",
F + " .cqt:focus { border-bottom: 2px solid " + accent.main + "; } " + F + " input.cqt.big { min-height: 0; font-size: 20px; padding: 12px 16px; }",
F + " .ccard.pg .cst { width: 100%; font: 24px Roboto, arial, sans-serif; border: 0; border-bottom: 1px solid #dadce0; outline: none; padding: 4px 0 6px 0; }",
F + " .chelp { display: block; width: 100%; margin: 10px 0 0 0; border: 0; border-bottom: 1px solid #dadce0; padding: 6px 0; font: 14px Roboto, arial, sans-serif; resize: none; overflow: hidden; outline: none; background: transparent; }",
F + " .chelp:focus { border-bottom: 2px solid " + accent.main + "; }",
F + " .ctype { display: flex; align-items: center; gap: 10px; width: 240px; height: 48px; padding: 0 4px 0 12px; border: 1px solid #dadce0; border-radius: " + (round ? "4px" : "0") + "; color: #202124; }",
F + " .ctype span { flex: 1; } " + F + " .ctype .mi { color: #5f6368; }",
F + " .copts { margin: 12px 0 0 0; } " + F + " .copt { display: flex; align-items: center; gap: 12px; min-height: 44px; color: #bdc1c6; }",
F + " .copt input { flex: 1; border: 0; border-bottom: 1px solid transparent; padding: 6px 0; outline: none; color: #202124; background: transparent; }",
F + " .copt input:hover { border-bottom-color: #dadce0; } " + F + " .copt input:focus { border-bottom: 2px solid " + accent.main + "; }",
F + " .copt.add input { flex: 0 1 auto; width: 100px; color: #70757a; } " + F + " .copt .onum { color: #202124; width: 24px; text-align: right; }",
F + " .cor { color: #202124; } " + F + " .caddother { color: " + blue + " !important; font-weight: 500; } " + F + " .cother { flex: 1; color: #70757a; border-bottom: 1px dotted #dadce0; padding: 6px 0; }",
F + " .crm { width: 40px; height: 40px; color: #5f6368; }",
F + " .cscale { display: flex; align-items: center; gap: 16px; margin: 16px 0; } " + F + " .cscale select { height: 36px; padding: 0 8px; border: 0; border-bottom: 1px solid #dadce0; background: transparent; }",
F + " .clab { display: flex; align-items: center; gap: 16px; margin: 8px 0; } " + F + " .clab span { width: 20px; } " + F + " .clab input { width: 260px; border: 0; border-bottom: 1px solid #dadce0; padding: 6px 0; outline: none; }",
F + " .cgrid { display: flex; gap: 24px; margin: 12px 0 0 0; } " + F + " .cgl { flex: 1; } " + F + " .cglh { font-weight: 500; margin: 0 0 4px 0; }",
F + " .pvtext { display: inline-flex; align-items: center; gap: 12px; color: #70757a; border-bottom: 1px dotted #bdc1c6; padding: 8px 0; min-width: 50%; margin: 14px 0 0 0; } " + F + " .pvtext.long { min-width: 80%; }",
F + " .pvo { display: flex; align-items: center; gap: 12px; margin: 10px 0; color: #202124; } " + F + " .pvl { margin: 8px 0; }",
F + " .cqv { font-size: 16px; white-space: pre-wrap; } " + F + " .cstar { color: #d93025; } " + F + " .chv { font-size: 14px; color: #202124; margin: 6px 0 0 0; white-space: pre-wrap; }",
F + " .cfoot { display: flex; align-items: center; border-top: 1px solid #dadce0; margin: 20px 0 -8px 0; padding: 8px 0 0 0; }",
F + " .csep { width: 1px; height: 32px; background: #dadce0; margin: 0 12px 0 8px; }",
F + " .creq { display: flex; align-items: center; gap: 12px; cursor: pointer; } " + F + " .creq input { display: none; }",
F + " .csw { position: relative; width: 36px; height: 14px; border-radius: 7px; background: #bdc1c6; }",
F + " .csw:after { content: ''; position: absolute; left: -2px; top: -3px; width: 20px; height: 20px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.4); transition: left .15s; }",
F + " .creq input:checked + .csw { background: " + accent.light + "; filter: saturate(3) brightness(.9); } " + F + " .creq input:checked + .csw:after { left: 18px; background: " + accent.main + "; }",
F + " .csec { margin: 24px 0 0 0; } " + F + " .csectag { display: inline-block; background: " + accent.main + "; color: #fff; font-size: 14px; padding: 8px 16px; border-radius: " + (round ? "8px 8px 0 0" : "0") + "; }",
F + " .csec + .ccard { margin-top: 0; border-top: 10px solid " + accent.main + "; }",
F + " .cfab { position: absolute; right: -64px; top: 12px; width: 50px; display: flex; flex-direction: column; background: #fff; border: 1px solid #dadce0; border-radius: " + sq + "; box-shadow: 0 1px 2px rgba(0,0,0,.2); transition: top .15s; }",
F + " .cfab .ib { border-radius: " + (round ? "50%" : "0") + "; }",
F + " .rpub a { color: " + blue + " !important; font-weight: 500; } " + F + " .rcard .rcount { font-size: 28px; } " + F + " .rbars .rb span { background: " + accent.main + "; }",
F + " .scard .sh { font-size: 24px; margin: 0 0 12px 0; } " + F + " .ssec { border-top: 1px solid #dadce0; padding: 12px 0; } " + F + " .ssh { font-size: 18px; margin: 0 0 8px 0; }",
F + " .srow { display: flex; align-items: center; gap: 10px; margin: 10px 0; } " + F + " .srow input { accent-color: " + accent.main + "; width: 18px; height: 18px; }",
F + " .sconf textarea { width: 100%; border: 0; border-bottom: 1px solid #dadce0; padding: 6px 0; outline: none; } " + F + " .ssl { font-weight: 500; margin: 12px 0 4px 0; }",
F + " .femenu { box-shadow: 0 2px 4px rgba(0,0,0,.2), 0 8px 16px rgba(0,0,0,.14); border-radius: " + (round ? "4px" : "0") + "; padding: 8px 0; }",
F + " .femenu a { padding: 0 24px 0 16px; height: 48px; color: #202124; } " + F + " .femenu a:hover { background: #f1f3f4; } " + F + " .femenu a.chk { background: #e8f0fe; } " + F + " .femenu .mi { color: #5f6368; }",
F + " .fedlgf { background: rgba(0,0,0,.4); } " + F + " .fedlg { border-radius: " + (round ? "8px" : "2px") + "; padding: 24px 24px 8px 24px; box-shadow: 0 24px 38px 3px rgba(0,0,0,.14), 0 9px 46px 8px rgba(0,0,0,.12), 0 11px 15px -7px rgba(0,0,0,.2); }",
F + " .fedlgh { font: " + (round ? "400 22px \"Google Sans\"" : "500 20px") + " Roboto, arial, sans-serif; margin: 0 0 16px 0; }",
F + " .fedlg input.w, " + F + " .fedlg textarea.w { border: 0; border-bottom: 1px solid #dadce0; padding: 8px 0; outline: none; } " + F + " .fedlg .dl { font-weight: 500; }",
F + " .dtabs { display: flex; border-bottom: 1px solid #dadce0; margin: 0 0 12px 0; } " + F + " .dtabs a { padding: 10px 16px; font-weight: 500; color: #5f6368; border-bottom: 2px solid transparent; } " + F + " .dtabs a.on { color: " + accent.main + "; border-bottom-color: " + accent.main + "; }",
F + " .fedlgf2 { justify-content: flex-end; margin: 16px -16px 0 0; } " + F + " .fedlgf2 button { height: 36px; padding: 0 12px; border: 0; background: none; color: " + accent.main + "; font: 500 14px Roboto, arial, sans-serif; text-transform: " + (round ? "none" : "uppercase") + "; cursor: pointer; border-radius: " + (round ? "4px" : "2px") + "; }",
F + " .fedlgf2 button:hover { background: rgba(0,0,0,.06); }",
F + " .fenote { top: auto; bottom: 24px; left: 24px; transform: none; background: #323232; color: #fff; padding: 14px 24px; border-radius: " + (round ? "4px" : "2px") + "; } " + F + " .fenote a { color: #8ab4f8; margin-left: 16px; }"
);
if (kind === "fk") {
css.push(
F + " .csend { border: 1px solid #3079ed; background: linear-gradient(#4d90fe, #4787ed); color: #fff; height: 29px; padding: 0 20px; border-radius: 2px; font: bold 11px arial, sans-serif; }",
F + " .ctabs a { font-weight: 400; }",
// the dialogs of 2014-2016 were still Kennedy's: blue and grey buttons,
// boxed fields, the page whitened behind
F + " .fedlgf { background: rgba(255,255,255,.75); } " + F + " .fedlg { border-radius: 0; padding: 30px 42px; border: 1px solid #acacac; box-shadow: 0 4px 16px rgba(0,0,0,.2); }",
F + " .fedlgh { font: 16px arial, sans-serif; color: #222; margin: 0 0 16px 0; }",
F + " .fedlg input.w, " + F + " .fedlg textarea.w { border: 1px solid #d9d9d9; border-top-color: #c0c0c0; border-radius: 1px; padding: 5px 8px; font: 13px arial, sans-serif; } " +
F + " .fedlg input.w:focus, " + F + " .fedlg textarea.w:focus { border-color: #4d90fe; box-shadow: inset 0 1px 2px rgba(0,0,0,.3); }",
F + " .fedlgf2 { justify-content: flex-start; margin: 22px 0 0 0; gap: 8px; } " + F + " .fedlgf2 button { height: 29px; min-width: 72px; padding: 0 12px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; " +
"background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px arial, sans-serif; text-transform: none; cursor: default; }",
F + " .fedlgf2 button:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); background: linear-gradient(#f8f8f8, #f1f1f1); color: #222; }",
F + " .fedlgf2 button.pri { background: linear-gradient(#4d90fe, #4787ed); border-color: #3079ed; color: #fff; } " + F + " .fedlgf2 button.pri:hover { background: linear-gradient(#4d90fe, #357ae8); border-color: #2f5bb7; color: #fff; }",
F + " .dtabs a.on { color: #222; border-bottom-color: #dd4b39; }"
);
} else if (kind === "fm") {
css.push(
F + " .mbar { background: " + accent.main + "; color: #fff; flex: 0 0 auto; }",
F + " .mtop { display: flex; align-items: center; height: 64px; padding: 0 8px; } " + F + " .mtop .ib, " + F + " .mtop .ctitle { color: #fff; } " + F + " .mtop .ctitle { font-size: 20px; font-weight: 500; }",
F + " .mtop .ib:hover { background: rgba(255,255,255,.12); }",
F + " .csend { background: #f1f1f1; color: " + accent.main + "; border-radius: 2px; min-width: 88px; padding: 0 16px; letter-spacing: .5px; box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2); }",
F + " .csend:hover { background: #e6e6e6; }",
F + " .mband { position: absolute; left: -100vw; right: -100vw; top: 0; height: 48px; background: " + accent.main + "; }",
F + " .cbody { padding-top: 0; } " + F + " .mtabs { position: relative; background: #fff; margin: 0; }",
F + " .mtabs .ctabs { border-bottom: 1px solid #e0e0e0; height: 48px; } " + F + " .mtabs + .ccard { margin-top: 0; border-top-width: 1px; border-top-color: #dadce0; }",
F + " .mtabs + .ccard.ctc { border-top: 1px solid #e0e0e0; margin-top: 0; }",
F + " .ctabs a { font-size: 14px; letter-spacing: .25px; }"
);
} else {
css.push(
F + " .csend { background: " + accent.main + "; color: #fff; border-radius: 4px; font-family: \"Google Sans\", Roboto, arial, sans-serif; letter-spacing: .25px; }",
F + " .ctitle { font-family: \"Google Sans\", Roboto, arial, sans-serif; } " + F + " .ccard.ctc { border-top-left-radius: 8px; border-top-right-radius: 8px; }",
F + " .ctabs a { font-family: \"Google Sans\", Roboto, arial, sans-serif; }"
);
}
}
return css.join("\n");
}
// ---- Gplex for Google Drive (5.5) -------------------------------------------------
// Gplex's own Drive: the Google Docs list before Drive (2007 to early 2012), then the
// Drive of each period. It is drawn over Google's own Drive page, which keeps running
// underneath: what is listed is read from Google's page, and everything done (opening,
// starring, renaming, uploading, sharing...) is done by pressing Google's own controls.
function ugfDvWanted() {
if (window.location.host !== "drive.google.com" || !ugfNtTopFrame() || !ugfNtOn("UGF_DRIVE_ON")) {
return false;
}
return ugfDvView().view !== "";
}
// which Drive a layout gets
// dl07 2004-2008: the Docs list with the blue bar
// dl09 late 2008-2010: the Docs list of 2009
// dl10 2010-early 2011: collections, the Google bar of 2010
// dl11 late 2011-early 2012: the grey Docs list under the black bar
// dv12 late 2012-2013: the first Drive (April 2012), red CREATE
// dv14 2014-2016: the new Drive of June 2014, blue NEW
// dv17 2017-2018: Drive in Material, white bar
// dv19 2019 on: Google Material 2
function ugfDvEra() {
const l = String(layout || "2015");
if (l === "2019" || l === "2022") {
return "dv19";
}
if (l === "2017" || l === "2018" || l === "2018M") {
return "dv17";
}
if (["2014", "2015", "2015L", "2016", "2016C", "2016L"].indexOf(l) > -1) {
return "dv14";
}
if (l === "2013" || l === "2013L") {
return "dv12";
}
if (l === "2012" || l === "2011") {
return "dl11";
}
if (l === "2010" || l === "2010N") {
return "dl10";
}
if (l === "2009" || l === "2009L") {
return "dl09";
}
return "dl07";
}
function ugfDvAuthUser() {
return ((window.location.pathname || "").match(/\/u\/(\d+)(\/|$)/) || ["", "0"])[1];
}
function ugfDvBase() {
return "https://drive.google.com/drive/u/" + ugfDvAuthUser();
}
// where in Drive we are
function ugfDvView() {
const p = (window.location.pathname || "/").replace(/^\/drive\/u\/\d+/, "/drive");
if (p === "/" || /^\/drive\/?$/.test(p)) {
return { view: "root" };
}
let m = p.match(/^\/drive\/folders\/([\w-]+)\/?$/);
if (m) {
return { view: "folder", id: m[1] };
}
m = p.match(/^\/drive\/(my-drive|home|shared-with-me|recent|starred|trash|search|computers|shared-drives|spam|quota)\/?$/);
if (m) {
return { view: m[1], q: m[1] === "search" ? (new URLSearchParams(window.location.search).get("q") || "") : "" };
}
return { view: "" };
}
// ---- a file's kind, from the type Google names it by -------------------------------
function ugfDvKindOf(type) {
const t = String(type || "").trim();
const g = { "Google Docs": "document", "Google Sheets": "spreadsheet", "Google Slides": "presentation", "Google Forms": "form", "Google Drawings": "drawing",
"Google Sites": "sites", "Google My Maps": "map", "Google Apps Script": "script", "Google Jamboard": "generic", "Google Vids": "video",
"Folder": "folder", "Shared folder": "sharedfolder", "Shortcut": "generic", "PDF": "pdf", "Image": "image", "Video": "video", "Audio": "audio", "Text": "text",
"Compressed archive": "archive", "Archive": "archive", "Microsoft Word": "word", "Microsoft Excel": "excel", "Microsoft PowerPoint": "powerpoint", "Word": "word",
"Excel": "excel", "PowerPoint": "powerpoint", "Unknown file": "generic", "Binary file": "generic" }[t];
if (g) {
return g;
}
if (/folder/i.test(t)) {
return /shared/i.test(t) ? "sharedfolder" : "folder";
}
if (/word/i.test(t)) {
return "word";
}
if (/excel/i.test(t)) {
return "excel";
}
if (/powerpoint/i.test(t)) {
return "powerpoint";
}
return "generic";
}
// every type label Drive writes after a name, longest first (the name is what is left)
function ugfDvTypeLabels() {
return ["Google Apps Script", "Compressed archive", "Microsoft PowerPoint", "Microsoft Excel", "Microsoft Word", "Google Drawings", "Google My Maps", "Google Jamboard",
"Google Slides", "Google Sheets", "Google Forms", "Google Sites", "Google Docs", "Google Vids", "Shared folder", "Unknown file", "Binary file", "PowerPoint",
"Shortcut", "Archive", "Folder", "Image", "Video", "Audio", "Excel", "Word", "Text", "PDF"];
}
function ugfDvIsFolder(it) {
return it.kind === "folder" || it.kind === "sharedfolder";
}
function ugfDvIcon(kind, era) {
const A = ugfDocsArt();
const set = A.dv[era] || A.dv.mt;
return set[kind] || (kind === "sharedfolder" ? set.folder : "") || set.generic || A.dv.mt.generic;
}
// where a file opens: the editors for Google's own kinds, the folder in Drive, and
// Google's viewer for the rest
function ugfDvOpenUrl(it) {
const u = "/u/" + ugfDvAuthUser();
const map = { document: "document", spreadsheet: "spreadsheets", presentation: "presentation", form: "forms", drawing: "drawings" };
if (ugfDvIsFolder(it)) {
return ugfDvBase() + "/folders/" + it.id;
}
if (map[it.kind]) {
return "https://docs.google.com/" + map[it.kind] + u + "/d/" + it.id + "/edit";
}
return "https://drive.google.com/file/d/" + it.id + "/view?authuser=" + ugfDvAuthUser();
}
function ugfDvShareUrl(it) {
const map = { document: "document", spreadsheet: "spreadsheets", presentation: "presentation", form: "forms", drawing: "drawings" };
if (ugfDvIsFolder(it)) {
return "https://drive.google.com/drive/folders/" + it.id + "?usp=sharing";
}
if (map[it.kind]) {
return "https://docs.google.com/" + map[it.kind] + "/d/" + it.id + "/edit?usp=sharing";
}
return "https://drive.google.com/file/d/" + it.id + "/view?usp=sharing";
}
function ugfDvThumb(it, size) {
return "https://drive.google.com/thumbnail?id=" + encodeURIComponent(it.id) + "&sz=" + (size || "w400") + "&authuser=" + ugfDvAuthUser();
}
// ---- reading Google's list -----------------------------------------------------------
// Drive lists files as table rows (the list) or grid cells (the grid, and the
// suggested folders); each carries the file's id. The columns are named in the table's
// head, so each row's cells are read by the head's names.
function ugfDvHarvest() {
const out = [];
const seen = {};
const clean = function(s) {
return String(s || "").replace(/\s+/g, " ").trim();
};
const labels = ugfDvTypeLabels();
document.querySelectorAll("[role=row][data-id], [role=gridcell][data-id]").forEach(function(el) {
if (el.closest("#ugf-drive") || !el.isConnected) {
return;
}
const id = el.getAttribute("data-id");
if (!id || seen[id] || !/^[\w-]{10,}$/.test(id)) {
return;
}
// the name and the type: the name's tooltip is " "
let tip = "";
el.querySelectorAll("[data-tooltip]").forEach(function(t) {
if (!tip && t.getAttribute("data-id") === id) {
tip = clean(t.getAttribute("data-tooltip"));
}
});
const svgT = el.querySelector("[data-column-field='6'] svg title, svg title");
let type = svgT ? clean(svgT.textContent) : "";
let name = clean((el.querySelector("strong") || {}).textContent || "");
if (!type && tip) {
labels.some(function(lb) {
if (tip.length > lb.length && tip.slice(-lb.length - 1) === " " + lb) {
type = lb;
return true;
}
return false;
});
}
if (!name) {
name = type && tip.slice(-type.length - 1) === " " + type ? tip.slice(0, -type.length - 1) : tip;
}
if (!name) {
const al = clean(el.getAttribute("aria-label") || "");
name = al.replace(/ (Located in|More info).*$/, "");
}
if (!name) {
return;
}
// shared and starred, as the name's label says (" Shared Starred")
let flags = "";
el.querySelectorAll("[aria-label]").forEach(function(a) {
const v = clean(a.getAttribute("aria-label"));
if (v.indexOf(name) === 0 && v.length > name.length && v.length < name.length + 60) {
flags += " " + v.slice(name.length);
}
});
const starBtn = el.querySelector("button[aria-label^='Remove from starred'], button[aria-label^='Add to starred']");
const starred = starBtn ? /^Remove/.test(starBtn.getAttribute("aria-label")) : / Starred\b/.test(flags);
const shared = / Shared\b/.test(flags) || /^Shared folder$/.test(type);
const it = { id: id, el: el, name: name, type: type, kind: ugfDvKindOf(type || (/ folder\b/i.test(flags) ? "Folder" : "")), starred: starred, shared: shared,
cols: {}, grid: el.getAttribute("role") === "gridcell" };
// the other columns, by the head's names
const table = el.closest("table");
if (table) {
const heads = {};
table.querySelectorAll("thead th[data-column-field]").forEach(function(th) {
heads[th.getAttribute("data-column-field")] = clean(th.textContent);
});
el.querySelectorAll("td[data-column-field]").forEach(function(td) {
const h = heads[td.getAttribute("data-column-field")];
if (!h || td.getAttribute("data-column-field") === "6") {
return;
}
const lab = td.querySelector("[data-tooltip]");
it.cols[h] = clean(lab ? lab.getAttribute("data-tooltip") : td.textContent);
});
} else {
const sub = el.querySelector(".uSZ2u, [class*='subtitle']");
if (sub) {
it.cols.Location = clean(sub.textContent).replace(/^in /, "");
}
}
const c = it.cols;
it.owner = c.Owner || c["Shared by"] || "";
it.modified = c["Last modified"] || c["Date modified"] || c["Last opened by me"] || c["Opened by me"] || c["Date shared"] || c["Trashed date"] || c["Date trashed"] ||
(c["Reason suggested"] || "").replace(/^You (edited|modified|opened|created|uploaded)\s*•\s*/, "");
it.size = c["File size"] || c.Size || "";
it.location = c.Location || c["Original location"] || "";
seen[id] = true;
out.push(it);
});
return out;
}
// how much of the storage is used, as Google's page says it
function ugfDvQuota() {
const a = document.querySelector("a[data-target=quota][aria-label], [aria-label^='Storage Summary']");
const m = a ? String(a.getAttribute("aria-label") || "").match(/:\s*(.+?) of (.+?) used/) : null;
return m ? { used: m[1], total: m[2] } : null;
}
// the name of the folder being shown (the page's title is " - Google Drive")
function ugfDvTitle() {
return String(document.title || "").replace(/\s*-\s*Google Drive\s*$/, "").trim();
}
// ---- pressing Google's controls -----------------------------------------------------
function ugfDvFire(el, types, extra) {
const r = el.getBoundingClientRect();
const at = Object.assign({ bubbles: true, cancelable: true, button: 0, buttons: 1, clientX: r.left + Math.min(20, r.width / 2), clientY: r.top + Math.min(12, r.height / 2) }, extra || {});
types.forEach(function(t) {
if (/up|click/.test(t)) {
at.buttons = 0;
}
try {
el.dispatchEvent(/^pointer/.test(t) && typeof PointerEvent === "function" ? new PointerEvent(t, Object.assign({ pointerType: "mouse", isPrimary: true }, at)) : new MouseEvent(t, at));
} catch (e) {
try {
el.dispatchEvent(new MouseEvent(t.replace("pointer", "mouse"), { bubbles: true, cancelable: true }));
} catch (e2) {}
}
});
}
function ugfDvPress(el) {
if (!el) {
return false;
}
try {
el.focus({ preventScroll: true });
} catch (e) {}
ugfDvFire(el, ["pointerover", "mouseover", "pointerdown", "mousedown", "pointerup", "mouseup", "click"]);
return true;
}
function ugfDvKey(el, key) {
const codes = { Enter: 13, Escape: 27, Delete: 46, ArrowDown: 40 };
["keydown", "keyup"].forEach(function(t) {
try {
(el || document.activeElement || document.body).dispatchEvent(new KeyboardEvent(t, { bubbles: true, cancelable: true, key: key, code: key, keyCode: codes[key] || 0, which: codes[key] || 0 }));
} catch (e) {}
});
}
function ugfDvShown(el) {
if (!el || !el.isConnected || el.closest("#ugf-drive, #ugf-photos")) {
return false;
}
if (!el.getClientRects().length) {
return false;
}
const cs = getComputedStyle(el);
return cs.visibility !== "hidden" && cs.display !== "none" && el.getAttribute("aria-hidden") !== "true";
}
// wait for something to appear on Google's page (or give up)
function ugfDvWait(fn, ms) {
return new Promise(function(resolve) {
const end = Date.now() + (ms || 4000);
const step = function() {
let v = null;
try {
v = fn();
} catch (e) {}
if (v) {
resolve(v);
} else if (Date.now() > end) {
resolve(null);
} else {
setTimeout(step, 60);
}
};
step();
});
}
function ugfDvSleep(ms) {
return new Promise(function(r) {
setTimeout(r, ms);
});
}
// Google's row (or grid cell) for a file
function ugfDvRow(id) {
let found = null;
document.querySelectorAll("[role=row][data-id], [role=gridcell][data-id]").forEach(function(el) {
if (!found && el.getAttribute("data-id") === id && !el.closest("#ugf-drive, #ugf-photos")) {
found = el;
}
});
return found;
}
function ugfDvText(el) {
return String((el && (el.getAttribute("aria-label") || el.textContent)) || "").replace(/\s+/g, " ").trim();
}
// a menu item on show, by the words it starts with
function ugfDvMenuItem(re) {
let hit = null;
document.querySelectorAll("[role=menuitem], [role=menuitemcheckbox], [role=menuitemradio], [role=option]").forEach(function(el) {
if (hit || !ugfDvShown(el) || el.getAttribute("aria-disabled") === "true") {
return;
}
const t = String(el.textContent || "").replace(/\s+/g, " ").trim();
const a = String(el.getAttribute("aria-label") || "").trim();
if (re.test(t) || re.test(a)) {
hit = el;
}
});
return hit;
}
function ugfDvDialog() {
let hit = null;
document.querySelectorAll("[role=dialog], [role=alertdialog]").forEach(function(el) {
if (!hit && ugfDvShown(el) && el.querySelector("button, input, [role=button]")) {
hit = el;
}
});
return hit;
}
// a button of any of Google's dialogs on show (a page can have several open at once,
// some of them side panels), by its words
function ugfDvDialogButton(re) {
let hit = null;
document.querySelectorAll("[role=dialog], [role=alertdialog]").forEach(function(d) {
if (!hit && ugfDvShown(d)) {
hit = ugfDvButton(d, re);
}
});
return hit;
}
// what Google's dialogs on show offer (for the console, when a step fails)
function ugfDvDialogWords() {
const out = [];
document.querySelectorAll("[role=dialog], [role=alertdialog]").forEach(function(d) {
if (ugfDvShown(d)) {
const bs = [];
d.querySelectorAll("button, [role=button]").forEach(function(b) {
if (ugfDvShown(b)) {
bs.push(ugfDvText(b).slice(0, 30));
}
});
out.push("[" + bs.join(" | ") + "]");
}
});
return out.join(" ");
}
function ugfDvButton(root, re) {
let hit = null;
(root || document).querySelectorAll("button, [role=button]").forEach(function(b) {
if (!hit && ugfDvShown(b) && b.getAttribute("aria-disabled") !== "true" && !b.disabled && re.test(ugfDvText(b))) {
hit = b;
}
});
return hit;
}
function ugfDvCloseMenus() {
ugfDvKey(document.activeElement, "Escape");
}
// put words into one of Google's fields the way typing does
function ugfDvType(input, value) {
try {
input.focus({ preventScroll: true });
input.select && input.select();
} catch (e) {}
let ok = false;
try {
ok = document.execCommand("selectAll", false) && document.execCommand("insertText", false, value);
} catch (e) {}
if (!ok || input.value !== value) {
const d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(input), "value");
if (d && d.set) {
d.set.call(input, value);
} else {
input.value = value;
}
input.dispatchEvent(new Event("input", { bubbles: true }));
}
input.dispatchEvent(new Event("change", { bubbles: true }));
}
// ---- doing things in Drive: one at a time, each by pressing Google's own controls ----
function ugfDvActions(onBusy) {
const queue = [];
let busy = false;
const pump = async function() {
if (busy) {
return;
}
busy = true;
onBusy(true);
while (queue.length) {
const job = queue.shift();
let r = false;
try {
r = await job[0]();
} catch (e) {
console.log("[Gplex] Drive: " + e);
r = false;
}
job[1](r);
}
busy = false;
onBusy(false);
};
const run = function(fn) {
return new Promise(function(resolve) {
queue.push([fn, resolve]);
pump();
});
};
const rowButton = function(id, re) {
const row = ugfDvRow(id);
if (!row) {
return null;
}
ugfDvFire(row, ["pointerover", "mouseover", "mouseenter"]);
let hit = null;
row.querySelectorAll("button[aria-label], [role=button][aria-label]").forEach(function(b) {
if (!hit && re.test(b.getAttribute("aria-label")) && b.getAttribute("aria-disabled") !== "true") {
hit = b;
}
});
return hit;
};
// select the file in Google's list (a plain click on its row)
const select = function(id) {
const row = ugfDvRow(id);
if (!row) {
return false;
}
const cell = row.querySelector("[data-column-field='28'], [data-column-field='8']") || row;
ugfDvFire(cell, ["pointerdown", "mousedown", "pointerup", "mouseup", "click"]);
return true;
};
// the row's menu: its three dots, or a right click on it
const openMore = async function(id) {
ugfDvCloseMenus();
await ugfDvSleep(60);
const row = ugfDvRow(id);
if (!row) {
return false;
}
const b = rowButton(id, /^More actions/);
if (b) {
ugfDvPress(b);
}
let up = await ugfDvWait(function() {
return ugfDvMenuItem(/\S/);
}, 1500);
if (!up) {
select(id);
ugfDvFire(row.querySelector("strong") || row, ["contextmenu"], { button: 2, buttons: 2 });
up = await ugfDvWait(function() {
return ugfDvMenuItem(/\S/);
}, 1500);
}
return !!up;
};
// through a menu and its submenus: each step is the words its item starts with
const menuPath = async function(steps) {
for (let i = 0; i < steps.length; i++) {
const it = await ugfDvWait(function() {
return ugfDvMenuItem(steps[i]);
}, 2500);
if (!it) {
// (what the menu did offer, so a changed wording can be seen in the console)
const offered = [];
document.querySelectorAll("[role=menuitem], [role=menuitemcheckbox], [role=menuitemradio]").forEach(function(el) {
if (ugfDvShown(el)) {
offered.push(String(el.textContent || "").replace(/\s+/g, " ").trim().slice(0, 40));
}
});
console.log("[Gplex] Drive: no menu item matching " + steps[i] + (offered.length ? " (the menu has: " + offered.join(" | ") + ")" : " (no menu open)"));
ugfDvCloseMenus();
return false;
}
if (i < steps.length - 1) {
ugfDvFire(it, ["pointerover", "mouseover", "mouseenter", "pointermove", "mousemove"]);
await ugfDvSleep(200);
if (!ugfDvMenuItem(steps[i + 1])) {
ugfDvPress(it);
await ugfDvSleep(150);
}
if (!ugfDvMenuItem(steps[i + 1])) {
ugfDvKey(it, "ArrowRight");
}
} else {
ugfDvPress(it);
}
}
return true;
};
const viaMenu = async function(id, steps) {
return (await openMore(id)) && (await menuPath(steps));
};
// Google's dialog with a text field: fill it and press its button
const fillDialog = async function(value, okRe) {
const dlg = await ugfDvWait(function() {
const d = ugfDvDialog();
return d && d.querySelector("input[type=text], input:not([type])") ? d : null;
}, 4000);
if (!dlg) {
console.log("[Gplex] Drive: Google's dialog with a name field did not appear");
return false;
}
const input = dlg.querySelector("input[type=text], input:not([type])");
ugfDvType(input, value);
await ugfDvSleep(120);
const ok = ugfDvButton(dlg, okRe);
if (ok) {
ugfDvPress(ok);
} else {
ugfDvKey(input, "Enter");
}
await ugfDvWait(function() {
return !dlg.isConnected || !ugfDvShown(dlg);
}, 4000);
return true;
};
// a confirmation Google may ask for (moving a shared file, deleting forever)
const confirm = async function(re, ms) {
const b = await ugfDvWait(function() {
return ugfDvDialogButton(re);
}, ms || 900);
if (b) {
ugfDvPress(b);
}
return !!b;
};
const newMenu = async function(re) {
ugfDvCloseMenus();
const btn = document.querySelector("[guidedhelpid=new_menu_button]") || ugfDvButton(document, /^New$/);
if (!btn) {
return false;
}
ugfDvPress(btn);
// (and by the keyboard, if the mouse did not open it)
if (!(await ugfDvWait(function() {
return ugfDvMenuItem(/\S/);
}, 1500))) {
try {
btn.focus();
} catch (e) {}
ugfDvKey(btn, "Enter");
if (!(await ugfDvWait(function() {
return ugfDvMenuItem(/\S/);
}, 1200))) {
["keydown", "keyup"].forEach(function(t) {
try {
btn.dispatchEvent(new KeyboardEvent(t, { bubbles: true, cancelable: true, key: " ", code: "Space", keyCode: 32, which: 32 }));
} catch (e) {}
});
}
}
return menuPath([re]);
};
// the parts of Google's page a file can be dropped on
const dropTarget = function() {
return document.querySelector("[role=main][guidedhelpid=main_container]") || document.querySelector("[role=main]");
};
const drag = function(src, dst) {
let dt;
try {
dt = new DataTransfer();
} catch (e) {
return false;
}
const ev = function(el, t) {
const r = el.getBoundingClientRect();
try {
el.dispatchEvent(new DragEvent(t, { bubbles: true, cancelable: true, dataTransfer: dt, clientX: r.left + 30, clientY: r.top + r.height / 2 }));
} catch (e) {}
};
if (src) {
ev(src, "dragstart");
ev(src, "drag");
}
ev(dst, "dragenter");
ev(dst, "dragover");
ev(dst, "drop");
if (src) {
ev(src, "dragend");
}
return dt;
};
return {
run: run,
busy: function() {
return busy;
},
star: function(id) {
return run(async function() {
const b = rowButton(id, /^(Add to|Remove from) starred/);
if (b) {
return ugfDvPress(b);
}
return viaMenu(id, [/^Organi[sz]e/, /^(Add to|Remove from) [Ss]tarred/]);
});
},
rename: function(id, name) {
return run(async function() {
const b = rowButton(id, /^Rename/);
if (b) {
ugfDvPress(b);
} else if (!(await viaMenu(id, [/^Rename/]))) {
return false;
}
return fillDialog(name, /^OK$/i);
});
},
trash: function(id) {
return run(async function() {
const b = rowButton(id, /^(Move to (trash|bin)|Remove)\b/);
if (b) {
ugfDvPress(b);
} else if (!(await viaMenu(id, [/^(Move to (trash|bin)|Remove)\b/]))) {
return false;
}
await confirm(/^(Move to (trash|bin)|Remove|OK)$/i);
return true;
});
},
restore: function(id) {
return run(function() {
const b = rowButton(id, /^Restore/);
return b ? ugfDvPress(b) : viaMenu(id, [/^Restore/]);
});
},
purge: function(id) {
return run(async function() {
const b = rowButton(id, /^Delete forever/);
if (b) {
ugfDvPress(b);
} else if (!(await viaMenu(id, [/^Delete forever/]))) {
return false;
}
await confirm(/^Delete forever$/i, 3000);
return true;
});
},
download: function(id) {
return run(async function() {
const b = rowButton(id, /^Download/);
if (b) {
return ugfDvPress(b);
}
return viaMenu(id, [/^Download/]);
});
},
copy: function(id) {
return run(function() {
return viaMenu(id, [/^Make a copy/]);
});
},
// Google's share dialog, opened (for driving, or to be shown)
share: function(id) {
return run(async function() {
const b = rowButton(id, /^Share/);
if (b) {
ugfDvPress(b);
} else if (!(await viaMenu(id, [/^Share/, /^Share/]))) {
return null;
}
return ugfDvWait(ugfDvShareDialog, 8000);
});
},
moveDialog: function(id) {
return run(async function() {
if (!(await viaMenu(id, [/^Organi[sz]e/, /^Move/]))) {
return null;
}
return ugfDvWait(ugfDvDialog, 4000);
});
},
// moving: dragging the row onto a folder of the list, or onto My Drive
move: function(id, target) {
return run(async function() {
const src = ugfDvRow(id);
let dst = null;
if (target === "root") {
dst = ugfDvTreeItem(/^My Drive$/);
} else {
dst = ugfDvRow(target);
}
if (!src || !dst) {
return false;
}
drag(src, dst);
await confirm(/^Move$/i, 1500);
return !!(await ugfDvWait(function() {
return !ugfDvRow(id);
}, 3000));
});
},
newFolder: function(name) {
return run(async function() {
if (!(await newMenu(/^(New )?folder(?!\s*upload)/i))) {
return false;
}
return fillDialog(name, /^Create$/i);
});
},
folderUpload: function() {
return run(function() {
return newMenu(/^Folder upload/);
});
},
// Google's own File upload / Folder upload, pressed straight away (not queued):
// the browser opens a file picker only for a click the person has just made
googleUpload: function(folder) {
const re = folder ? /^Folder upload/i : /^File upload/i;
const btn = document.querySelector("[guidedhelpid=new_menu_button]") || ugfDvButton(document, /^New$/);
if (!btn) {
console.log("[Gplex] Drive: Google's New button was not found");
return Promise.resolve(false);
}
ugfDvPress(btn);
const now = ugfDvMenuItem(re);
if (now) {
ugfDvPress(now);
return Promise.resolve(true);
}
return ugfDvWait(function() {
return ugfDvMenuItem(re);
}, 2500).then(function(it) {
if (!it) {
return menuPath([re]);
}
ugfDvPress(it);
return true;
});
},
// files chosen or dropped on Gplex's page go to Google's page the way a drop does
upload: function(files) {
return run(async function() {
const t = dropTarget();
if (!t || !files.length) {
return false;
}
let dt;
try {
dt = new DataTransfer();
[].forEach.call(files, function(f) {
dt.items.add(f);
});
} catch (e) {
return false;
}
const r = t.getBoundingClientRect();
// (the page is told a drag came in, then it is dropped once on the list)
[["dragenter", t], ["dragover", t], ["drop", t]].forEach(function(e2) {
try {
e2[1].dispatchEvent(new DragEvent(e2[0], { bubbles: true, cancelable: true, dataTransfer: dt, clientX: r.left + r.width / 2, clientY: r.top + r.height / 2 }));
} catch (e) {}
});
return true;
});
},
// the Undo of Google's own message (after moving to the trash, renaming...)
undo: function() {
return run(async function() {
let b = null;
document.querySelectorAll("[role=alert] button, [role=status] button, [aria-live] button, [role=alert] [role=button], [aria-live] [role=button]").forEach(function(x) {
if (!b && ugfDvShown(x) && /^Undo$/i.test(ugfDvText(x))) {
b = x;
}
});
b = b || ugfDvButton(document, /^Undo$/i);
return b ? ugfDvPress(b) : false;
});
},
select: select
};
}
// one of Google's places on the left (My Drive, Starred...), by its words
function ugfDvTreeItem(re) {
let hit = null;
document.querySelectorAll("[role=treeitem]").forEach(function(ti) {
if (hit || ti.closest("#ugf-drive")) {
return;
}
const ids = String(ti.getAttribute("aria-labelledby") || "").split(/\s+/);
const lab = ids[0] ? document.getElementById(ids[0]) : null;
const inner = ti.querySelector("[aria-label]");
const words = [lab ? lab.textContent : "", inner ? inner.getAttribute("aria-label") : "", ti.getAttribute("aria-label") || "", (ti.textContent || "").slice(0, 60)];
if (words.some(function(w) {
return re.test(String(w || "").replace(/\s+/g, " ").trim());
})) {
hit = lab || ti;
}
});
return hit;
}
// Google's share dialog (on the page, or in a frame of Drive's own)
function ugfDvShareDialog() {
const looks = function(root) {
let hit = null;
root.querySelectorAll("[role=dialog]").forEach(function(d) {
if (!hit && (d.getClientRects().length) && /^Share\b|Sharing settings|Share with/i.test(String(d.getAttribute("aria-label") || d.textContent || "").trim().slice(0, 80))) {
hit = d;
}
});
return hit;
};
let d = looks(document);
if (d) {
return { dialog: d, doc: document, frame: null };
}
let found = null;
document.querySelectorAll("iframe").forEach(function(f) {
if (found || !f.getClientRects().length) {
return;
}
try {
const doc = f.contentDocument;
if (doc && /shar/i.test(f.src + " " + (f.className || "") + " " + (f.name || ""))) {
const dd = looks(doc) || doc.querySelector("[role=dialog]");
if (dd) {
found = { dialog: dd, doc: doc, frame: f };
}
}
} catch (e) {}
});
return found;
}
// Show one of Google's dialogs above Gplex's page: the fallback when Gplex cannot do
// what was asked through its own dialog
function ugfDvReveal(el, onGone) {
if (!el) {
return;
}
let top = el;
while (top.parentElement && top.parentElement !== document.body) {
top = top.parentElement;
}
const whole = top.querySelector && top.querySelector("[role=main]");
const html = document.documentElement;
if (whole || top === el.ownerDocument.documentElement) {
html.setAttribute("gplex-dv-reveal", "");
} else {
top.setAttribute("ugf-dv-up", "");
if (getComputedStyle(top).position === "static") {
top.style.setProperty("position", "relative", "important");
top.setAttribute("ugf-dv-pos", "");
}
}
const watch = setInterval(function() {
if (!el.isConnected || !el.getClientRects().length || getComputedStyle(el).visibility === "hidden") {
clearInterval(watch);
html.removeAttribute("gplex-dv-reveal");
top.removeAttribute("ugf-dv-up");
if (top.hasAttribute("ugf-dv-pos")) {
top.style.removeProperty("position");
top.removeAttribute("ugf-dv-pos");
}
if (onGone) {
onGone();
}
}
}, 300);
}
// Inviting people through Google's share dialog: the addresses into its field, the
// role, the note, and Send. Anything not found leaves the dialog shown as it is.
async function ugfDvShareInvite(sd, emails, role, notify, note) {
const doc = sd.doc;
const d = sd.dialog;
const shown = function(el) {
return el && el.getClientRects().length > 0;
};
const field = await ugfDvWait(function() {
let hit = null;
d.querySelectorAll("input, [contenteditable=true]").forEach(function(i) {
const w = (i.getAttribute("aria-label") || "") + " " + (i.getAttribute("placeholder") || "");
if (!hit && shown(i) && /add people|people|email|groups/i.test(w)) {
hit = i;
}
});
return hit;
}, 4000);
if (!field) {
return false;
}
for (let i = 0; i < emails.length; i++) {
try {
field.focus();
} catch (e) {}
let ok = false;
try {
ok = doc.execCommand("insertText", false, emails[i]);
} catch (e) {}
if (!ok) {
const dsc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(field), "value");
if (dsc && dsc.set) {
dsc.set.call(field, emails[i]);
}
field.dispatchEvent(new Event("input", { bubbles: true }));
}
await ugfDvSleep(500);
ugfDvKey(field, "Enter");
await ugfDvSleep(400);
}
await ugfDvSleep(600);
// the role: "Editor", "Commenter" or "Viewer" on the dialog's role button
const want = { edit: /^Editor$/i, comment: /^Commenter$/i, view: /^Viewer$/i }[role];
if (want && role !== "edit") {
let rb = null;
d.querySelectorAll("button, [role=button], [role=listbox], [aria-haspopup]").forEach(function(b) {
if (!rb && shown(b) && /^(Editor|Viewer|Commenter)\b/i.test(String(b.textContent || "").trim())) {
rb = b;
}
});
if (rb) {
ugfDvPress(rb);
const opt = await ugfDvWait(function() {
let o = null;
doc.querySelectorAll("[role=menuitem], [role=option], [role=menuitemradio]").forEach(function(x) {
if (!o && shown(x) && want.test(String(x.textContent || "").replace(/\s+/g, " ").trim().split(" ")[0])) {
o = x;
}
});
return o;
}, 2000);
if (opt) {
ugfDvPress(opt);
}
}
}
const box = d.querySelector("input[type=checkbox][aria-label*='Notify'], [role=checkbox][aria-label*='Notify']");
if (box) {
const on = box.getAttribute("aria-checked") === "true" || box.checked;
if (on !== !!notify) {
ugfDvPress(box);
}
}
if (note && notify) {
const ta = d.querySelector("textarea");
if (ta && shown(ta)) {
ugfDvType(ta, note);
}
}
await ugfDvSleep(300);
let send = null;
d.querySelectorAll("button, [role=button]").forEach(function(b) {
if (!send && shown(b) && /^(Send|Share)$/i.test(String(b.textContent || "").trim())) {
send = b;
}
});
if (!send) {
return false;
}
ugfDvPress(send);
return true;
}
// ---- Drive: starting, and the page -----------------------------------------------------
function ugfDvStart() {
if (window.location.host !== "drive.google.com" || !ugfNtTopFrame() || !ugfNtOn("UGF_DRIVE_ON")) {
return;
}
// a file's own page: the viewer of the period
if (ugfDvFileId()) {
ugfDvViewer(ugfDvEra());
return;
}
if (!ugfDvWanted()) {
const veil = document.getElementById("ugf-dv-veil");
if (veil) {
veil.remove();
}
}
if (ugfDvWanted()) {
ugfDriveMain();
return;
}
// Drive changes its address without reloading: start when it reaches one of its lists
const t = setInterval(function() {
if (ugfDvWanted()) {
clearInterval(t);
ugfDriveMain();
}
}, 500);
}
function ugfDriveMain() {
const era = ugfDvEra();
const A = ugfDocsArt();
const l = String(layout || "");
const fav = { dl07: A.fav2007, dl09: A.fav2008, dl10: A.fav2010, dl11: A.fav2011, dv12: A.dvFav2012, dv14: A.dvFav2014, dv17: A.dvFav2017, dv19: l === "2022" ? A.dvFav2020 : A.dvFav2017 }[era];
console.log("[Gplex] Drive: layout " + layout + " (" + era + ")" + (UGF_VERSION ? " - Gplex " + UGF_VERSION : ""));
ugfApplyFavicon(fav);
ugfKeepFavicon(function() {
return fav;
});
ugfDriveHome(era);
}
function ugfDriveHome(era) {
const A = ugfDocsArt();
const esc = ugfDocsEsc;
const ic = ugfFeIcon;
const l = String(layout || "");
const who = ugfCalWho();
const signedIn = !!(who.email || who.name);
const docsList = era === "dl07" || era === "dl09" || era === "dl10" || era === "dl11";
const kennedy = era === "dl11" || era === "dv12";
const material = era === "dv14" || era === "dv17" || era === "dv19";
const gm = era === "dv19";
const html = document.documentElement;
html.setAttribute("gplex-dv", era);
const style = document.createElement("style");
style.id = "ugf-drive-styles";
style.textContent = ugfDriveCss(era, A).join("\n");
(document.head || document.documentElement).appendChild(style);
const shell = document.createElement("div");
shell.id = "ugf-drive";
shell.setAttribute("era", era);
shell.setAttribute("tabindex", "-1");
document.body.appendChild(shell);
// Google's page stays usable underneath (its menus and dialogs are pressed from here)
const veil = document.getElementById("ugf-dv-veil");
if (veil) {
veil.remove();
}
const act = ugfDvActions(function(b) {
shell.classList.toggle("busy", b);
});
const state = { items: [], sel: {}, anchor: "", sort: "", dir: 1, grid: false, loaded: false, view: ugfDvView(), moreNav: false, lastKey: "", gTitle: document.title };
try {
state.grid = localStorage.getItem("UGF_DV_GRID") === "1";
} catch (e) {}
const W = docsList ? { item: "item", items: "items", folder: era === "dl10" || era === "dl11" ? "collection" : "folder", Folder: era === "dl10" || era === "dl11" ? "Collection" : "Folder" }
: { item: "item", items: "items", folder: "folder", Folder: "Folder" };
// ---- remembered folders (the top of My Drive), for the folder lists on the left
const cacheKey = "UGF_DV_FOLDERS_" + ugfDvAuthUser();
const cached = function() {
try {
return JSON.parse(localStorage.getItem(cacheKey) || "[]");
} catch (e) {
return [];
}
};
const remember = function() {
if (state.view.view !== "my-drive" || !state.loaded) {
return;
}
const f = state.items.filter(ugfDvIsFolder).slice(0, 40).map(function(it) {
return { id: it.id, name: it.name };
});
try {
localStorage.setItem(cacheKey, JSON.stringify(f));
} catch (e) {}
};
// the way down into folders, for the path above the list
const trailKey = "UGF_DV_TRAIL";
const trail = function() {
try {
return JSON.parse(sessionStorage.getItem(trailKey) || "[]");
} catch (e) {
return [];
}
};
const setTrail = function(t) {
try {
sessionStorage.setItem(trailKey, JSON.stringify(t));
} catch (e) {}
};
// ---- the places on the left, per period
const places = function() {
if (era === "dl07" || era === "dl09") {
return [["All items", "my-drive"], ["Opened by me", "recent"], ["Starred", "starred"], ["Shared with me", "shared-with-me"], ["Trash", "trash"]];
}
if (era === "dl10") {
return [["Home", "home"], ["Starred", "starred"], ["All items", "my-drive"], ["Shared with me", "shared-with-me"], ["Trash", "trash"]];
}
if (era === "dl11") {
return [["Home", "home"], ["Starred", "starred"], ["Owned by me", "my-drive"], ["Shared with me", "shared-with-me"], ["Trash", "trash"]];
}
if (era === "dv12") {
return [["My Drive", "my-drive"], ["Shared with me", "shared-with-me"], ["Starred", "starred"], ["Recent", "recent"], ["Trash", "trash", true]];
}
if (era === "dv14") {
return [["My Drive", "my-drive", "folder"], ["Shared with me", "shared-with-me", "people"], ["Recent", "recent", "access_time"], ["Starred", "starred", "star"], ["Trash", "trash", "delete"]];
}
return [["My Drive", "my-drive", "folder"], ["Computers", "computers", "computer"], ["Shared with me", "shared-with-me", "people"], ["Recent", "recent", "access_time"],
["Starred", "starred", "star"], ["Trash", "trash", "delete"]];
};
const placeName = function(v) {
let n = "";
places().forEach(function(p) {
if (p[1] === v) {
n = p[0];
}
});
return n || { "my-drive": "My Drive", home: "Home", search: "Search results", computers: "Computers", spam: "Spam" }[v] || "My Drive";
};
const here = function() {
const v = state.view.view;
if (v === "folder" || v === "root") {
const t = trail();
return t.length && t[0].from ? t[0].from : "my-drive";
}
return v;
};
// ---- going places: Google's own links on its left, so the page does not reload
const go = function(v) {
const re = { "my-drive": /^My Drive$/, home: /^Home$/, "shared-with-me": /^(Items )?[Ss]hared with me$/, recent: /^Recent( items)?$/, starred: /^Starred( items)?$/,
trash: /^(Trash|Trashed items|Bin|Items in bin)$/, computers: /^Computers$/, spam: /^Spam/ }[v];
setTrail([]);
state.sel = {};
const ti = re ? ugfDvTreeItem(re) : null;
const url = ugfDvBase() + "/" + v;
if (ti) {
ugfDvPress(ti);
setTimeout(function() {
if (ugfDvView().view !== v) {
window.location.href = url;
}
}, 2500);
} else {
window.location.href = url;
}
};
const openFolder = function(it, from) {
const t = trail().filter(function(x) {
return x.id !== it.id;
});
const cur = state.view.view === "folder" ? state.view.id : "";
let nt = [];
if (cur) {
const at = t.map(function(x) {
return x.id;
}).indexOf(cur);
nt = at > -1 ? t.slice(0, at + 1) : [{ id: cur, name: currentTitle() }];
}
nt.push({ id: it.id, name: it.name });
nt[0].from = nt[0].from || from || (state.view.view === "folder" ? here() : state.view.view === "root" ? "my-drive" : state.view.view);
setTrail(nt);
state.sel = {};
const row = ugfDvRow(it.id);
const url = ugfDvBase() + "/folders/" + it.id;
if (row) {
const nm = row.querySelector("strong, .MxB3Nd") || row;
ugfDvFire(nm, ["mousedown", "mouseup", "click"], { detail: 1 });
ugfDvFire(nm, ["mousedown", "mouseup", "click"], { detail: 2 });
ugfDvFire(nm, ["dblclick"], { detail: 2 });
setTimeout(function() {
const v = ugfDvView();
if (!(v.view === "folder" && v.id === it.id)) {
window.location.href = url;
}
}, 1800);
} else {
window.location.href = url;
}
};
const openItem = function(it) {
if (!it) {
return;
}
if (ugfDvIsFolder(it)) {
openFolder(it);
return;
}
if (it.kind === "image") {
preview(it);
return;
}
window.open(ugfDvOpenUrl(it), "_blank");
};
const newDoc = function(kind) {
const path = { document: "document", spreadsheet: "spreadsheets", presentation: "presentation", form: "forms", drawing: "drawings" }[kind];
const f = state.view.view === "folder" ? "&folder=" + encodeURIComponent(state.view.id) : "";
window.open("https://docs.google.com/" + path + "/u/" + ugfDvAuthUser() + "/create?usp=drive_web" + f, "_blank");
};
// ---- what is listed
const visible = function() {
let list = state.items.slice();
if (state.sort === "name") {
list.sort(function(a, b) {
const fa = ugfDvIsFolder(a) ? 0 : 1;
const fb = ugfDvIsFolder(b) ? 0 : 1;
return fa - fb || a.name.localeCompare(b.name, undefined, { numeric: true }) * state.dir;
});
}
return list;
};
const selected = function() {
return visible().filter(function(it) {
return state.sel[it.id];
});
};
const byId = function(id) {
let f = null;
state.items.forEach(function(it) {
if (it.id === id) {
f = it;
}
});
return f;
};
const inTrash = function() {
return state.view.view === "trash";
};
const dateOf = function(it) {
return String(it.modified || "").replace(/^(me|You)\s*[•·]?\s*/, "");
};
const ownerOf = function(it) {
return it.owner || (state.view.view === "shared-with-me" || it.grid ? "" : "me");
};
// ---- the bars at the top
const searchForm = function(cls, ph, btn) {
return '";
};
const topLinks = function() {
const apps = era === "dl07" ? [["Mail", "https://mail.google.com/"], ["Calendar", "https://calendar.google.com/"], ["Documents", ""],
["Photos", "https://photos.google.com/"], ["Groups", "https://groups.google.com/"], ["Web", "https://www.google.com/"]]
: [["Gmail", "https://mail.google.com/"], ["Calendar", "https://calendar.google.com/"], ["Documents", ""], ["Reader", "https://www.google.com/reader/"], ["Web", "https://www.google.com/"]];
return '' +
(signedIn ? "
" + esc(who.email || who.name) + " | " : "") + '
Settings ' + (era === "dl07" ? "" : " ▾") +
' |
Help | ' +
(signedIn ? '
Sign out ' : '
Sign in ') + "
";
};
const quota = function() {
const qd = ugfDvQuota();
if (!qd) {
return "";
}
if (material) {
return '";
}
return '' + (kennedy ? esc(qd.used) + " (" + "of " + esc(qd.total) + ") used" : "You're using " + esc(qd.used) + " of " + esc(qd.total) + ".") +
(kennedy ? '
Get more storage ' : "") + "
";
};
const quotaFill = function() {
const qd = ugfDvQuota();
const bar = shell.querySelector(".qbar i");
if (!qd || !bar) {
return;
}
const n = function(s) {
const m = String(s).match(/([\d.,]+)\s*(bytes|KB|MB|GB|TB)/i);
if (!m) {
return 0;
}
return parseFloat(m[1].replace(/,/g, "")) * Math.pow(1024, ["bytes", "kb", "mb", "gb", "tb"].indexOf(m[2].toLowerCase()));
};
const p = n(qd.total) ? Math.min(100, Math.max(1, 100 * n(qd.used) / n(qd.total))) : 0;
bar.style.width = p + "%";
};
const frame = function() {
let h = "";
const nav = '
';
if (era === "dl07") {
h = topLinks() + '' +
searchForm("srch", "", '
Search Docs Search the Web ') + "
" +
'New ▾ Upload
' +
'';
} else if (era === "dl09") {
h = topLinks() + '" +
'New ▾ Upload...
' + nav + "
" +
'
';
} else if (era === "dl10") {
h = ugfNtGbar("classic", "Documents", "2010") + '" +
'Create new ▾ Upload...
' + nav + "
" +
'
';
} else if (kennedy) {
const drive = era === "dv12";
h = ugfNtGbar("dark", drive ? "Drive" : "Documents", "2011") + '' +
searchForm("ksrch", drive ? "" : "", '
' + ic("search", 18) + " ") + ugfNtHeadCorner() + "
" +
'" +
'CREATE ' + ic("file_download", 18) + "
" + nav + quota() + '
';
} else if (era === "dv14") {
const newLogo = ["2016", "2016C", "2016L"].indexOf(l) > -1;
h = '" +
searchForm("gsrch", "Search Drive", '
' + ic("search", 20) + " ") + ugfNtHeadCorner() + "
" +
'Drive
' +
'
' + ic(state.grid ? "view_list" : "view_module", 24) + " " +
'
' + ic("sort_by_alpha", 24) + ' ' + ic("info_o", 24) + " " +
'
' + ic("settings", 24) + " " +
'';
} else {
const q4 = l === "2022";
h = 'Drive ' +
searchForm("msrch", "Search Drive", '
' + ic("search", 24) + " ") +
'
' + ic("help_outline", 24) + ' ' + ic("settings", 24) + " " +
'
' + ugfNtCorner() + " " +
'' + (gm ? ic("add", 24) + "New " : "NEW") + "
" + nav + quota() + "
" +
'
' +
'
' + ic(state.grid ? "view_list" : "view_module", 24) + " " +
'
' + ic("info_o", 24) + " " + '
';
}
shell.innerHTML = trusted_policy.createHTML(h + '
');
ugfNtMenus(shell, gm);
drawNav();
drawList();
quotaFill();
};
// ---- the places on the left
const drawNav = function() {
const box = shell.querySelector(".nav");
if (!box) {
return;
}
const cur = here();
let h = "";
places().forEach(function(p) {
if (p[2] === true && !state.moreNav) {
return;
}
const on = p[1] === cur;
h += '' + (material && p[2] ? ic(p[2], 24) : "") + "" + esc(p[0]) + "
";
// the folders at the top of My Drive, under it
if ((p[1] === "my-drive" && (era === "dv12" || era === "dv14")) || (p[1] === "my-drive" && era === "dl11" && false)) {
const fs = cached();
if (on && fs.length) {
h += '' + fs.map(function(f) {
const openF = state.view.view === "folder" && trail().some(function(x) {
return x.id === f.id;
});
return '
' +
(material ? ic("folder", 20) : '
') + "
" + esc(f.name) + " ";
}).join("") + "
";
}
}
});
if (era === "dv12") {
h += '' + (state.moreNav ? "Less ▴" : "More ▾") + "
";
}
// the old lists: the folders (or collections) as a group of their own
if (docsList) {
const fs = cached();
const title = era === "dl07" ? "Folders" : era === "dl09" ? "My folders" : "My collections";
h += '' + (fs.length ? "▾ " : "▸ ") + title + "
";
h += fs.length ? fs.map(function(f) {
const openF = state.view.view === "folder" && trail().some(function(x) {
return x.id === f.id;
});
return '' + esc(f.name) + " ";
}).join("") : '' + (era === "dl07" || era === "dl09" ? "No folders" : "No collections") + "
";
}
box.innerHTML = trusted_policy.createHTML(h);
};
// the path above the list (Drive), or the list's name (the Docs list)
const crumbHtml = function() {
const v = state.view.view;
if (v === "search") {
return 'Search results for “' + esc(state.view.q) + "” ";
}
if (v !== "folder") {
return '' + esc(placeName(v)) + (v === "my-drive" && material ? " " + ic("arrow_drop_down", 24) : "") + " ";
}
const t = trail();
const at = t.map(function(x) {
return x.id;
}).indexOf(state.view.id);
const path = at > -1 ? t.slice(0, at + 1) : [{ id: state.view.id, name: currentTitle() }];
const sep = material ? ic("chevron_right", 24) : kennedy ? " > " : " › ";
const root = (t[0] && t[0].from) || "my-drive";
let h = '' + esc(placeName(root)) + " ";
path.forEach(function(x, i) {
const last = i === path.length - 1;
const name = last ? (currentTitle() || x.name) : x.name;
h += '' + sep + ' " +
esc(name) + (last && material ? " " + ic("arrow_drop_down", 24) : "") + " ";
});
return h;
};
const currentTitle = function() {
const t = String(state.gTitle || "").replace(/\s*-\s*Google Drive\s*$/, "").trim();
return /^(Google Drive|My Drive|Home|Recent|Starred|Trash|Bin|Shared with me|Computers|Search results)$/i.test(t) ? "" : t;
};
// ---- the buttons over the list: what can be done with the chosen files
const actionsFor = function(sel) {
const one = sel.length === 1 ? sel[0] : null;
if (inTrash()) {
return [["restore", "Restore", "restore"], ["purge", "Delete forever", "delete_outline"]];
}
const out = [];
if (one) {
out.push(["open", ugfDvIsFolder(one) ? "Open" : "Open", "open_in_new"]);
}
out.push(["share", "Share...", "person_add"]);
if (one) {
out.push(["link", "Get link", "link"]);
}
out.push(["move", docsList ? (era === "dl10" || era === "dl11" ? "Move to collection..." : "Move to folder...") : "Move to...", "drive_file_move"]);
out.push(["star", sel.length && sel.every(function(it) {
return it.starred;
}) ? "Remove star" : (material ? "Add to Starred" : "Add star"), "star_border"]);
if (one) {
out.push(["rename", "Rename...", "drive_file_rename_outline"]);
}
if (one && !ugfDvIsFolder(one)) {
out.push(["copy", "Make a copy", "content_copy"]);
}
out.push(["download", "Download", "file_download"]);
if (one) {
out.push(["details", material ? "View details" : "Details", "info_o"]);
}
out.push(["trash", docsList ? "Delete" : "Remove", "delete"]);
return out;
};
// (only when it changes: an open menu keeps its button)
const put = function(el, h) {
if (el && el.ugfH !== h) {
el.ugfH = h;
el.innerHTML = trusted_policy.createHTML(h);
}
};
const drawTool = function() {
const box = shell.querySelector(".tool");
const sel = selected();
if (box) {
let h = "";
if (era === "dl07") {
h = 'Add to folder ▾ ' + (inTrash() ? "Restore" : "Delete") + " " +
'Rename More actions ▾ ';
} else if (era === "dl09") {
h = inTrash() ? 'Undelete Empty trash '
: 'Share ▾ Folders ▾ Delete ' +
'Rename More actions ▾ ';
} else if (era === "dl10") {
h = inTrash() ? 'Undelete Delete forever '
: 'Share ▾ Organize ▾ Delete ' +
'Rename More actions ▾ ';
} else if (kennedy) {
h = sel.length ? (inTrash() ? 'Restore Delete forever '
: '' + ic("person_add", 18) + ' ' + ic("folder", 18) + " " +
'' + ic("delete", 18) + ' More ▾ ') : "";
} else {
h = sel.length ? actionsFor(sel).filter(function(a) {
return ["share", "link", "open", "trash", "restore", "purge", "download"].indexOf(a[0]) > -1 && !(a[0] === "open");
}).map(function(a) {
return '' + ic(a[2], 24) + " ";
}).join("") + '' + ic("more_vert", 24) + " " : "";
}
put(box, h);
}
put(shell.querySelector(".mhead"), crumbHtml());
put(shell.querySelector(".crumb"), crumbHtml());
const n = visible().length;
put(shell.querySelector(".foot"), 'Select: All ' + n + ' , None ' +
(n ? "Showing items 1-" + n + " of " + n : "") + " ");
};
// ---- the list itself
const empty = function() {
if (!state.loaded) {
return 'Loading...
';
}
const v = state.view.view;
const words = { trash: docsList ? "No items in the trash." : "Trash is empty", starred: "No starred items", "shared-with-me": "Nothing has been shared with you",
search: "No results for “" + (state.view.q || "") + "”", recent: "No recent files" }[v];
return '' + esc(words || (docsList ? "No items." : "No files in this folder. Drag files here or use the " + (era === "dv12" ? "CREATE" : "NEW") + " button.")) + "
";
};
const iconImg = function(it) {
return ' ';
};
const tags = function(it) {
let t = "";
if (it.shared && !ugfDvIsFolder(it)) {
t += material ? '' + ic("people", 16) + " " : ' Shared ';
}
if (material && it.starred) {
t += '' + ic("star", 16) + " ";
}
return t;
};
const table = function(list) {
const old = era === "dl07" || era === "dl09";
const caps = era === "dv12";
const sortMark = state.sort === "name" ? (state.dir > 0 ? " ▲" : " ▼") : "";
let h = '";
};
const rows = function(list) {
const sortMark = state.sort === "name" ? ic(state.dir > 0 ? "arrow_upward" : "arrow_downward", 18) : "";
let h = 'Name ' + sortMark + ' Owner ' +
(inTrash() ? "Trashed" : state.view.view === "recent" ? "Last opened by me" : "Last modified") + (state.sort ? "" : " " + ic("arrow_downward", 18)) +
' File size
';
list.forEach(function(it) {
h += '' + iconImg(it) + '' + esc(it.name) + " " + tags(it) +
' ' + esc(ownerOf(it)) + ' ' + esc(dateOf(it)) + ' ' + esc(ugfDvIsFolder(it) ? "—" : (it.size || "—")) + "
";
});
return '' + h + "
";
};
const grid = function(list) {
const folders = list.filter(ugfDvIsFolder);
const files = list.filter(function(it) {
return !ugfDvIsFolder(it);
});
let h = "";
if (folders.length) {
h += 'Folders
' + folders.map(function(it) {
return '
' + (material ? ic(it.kind === "sharedfolder" ? "folder_shared" : "folder", 24) : iconImg(it)) +
'' + esc(it.name) + "
";
}).join("") + "
";
}
if (files.length) {
h += 'Files
' + files.map(function(it) {
return '
' + iconImg(it) + '' + esc(it.name) + "
";
}).join("") + "
";
}
return '' + h + "
";
};
const drawList = function() {
const box = shell.querySelector(".list");
if (!box) {
return;
}
const list = visible();
const keepScroll = box.parentElement ? box.parentElement.scrollTop : 0;
let h;
if (!list.length) {
h = (material ? "" : table([])) + empty();
} else if (material || era === "dv12") {
h = state.grid ? grid(list) : (material ? rows(list) : table(list));
} else {
h = table(list);
}
box.innerHTML = trusted_policy.createHTML(h);
box.querySelectorAll(".gc .th img").forEach(function(img) {
img.addEventListener("error", function() {
img.src = img.getAttribute("data-fb");
img.classList.add("fb");
}, { once: true });
});
if (box.parentElement) {
box.parentElement.scrollTop = keepScroll;
}
drawTool();
};
// ---- choosing files
const choose = function(id, ev) {
const list = visible();
if (ev && (ev.metaKey || ev.ctrlKey)) {
state.sel[id] = !state.sel[id];
} else if (ev && ev.shiftKey && state.anchor) {
const ids = list.map(function(it) {
return it.id;
});
const a = ids.indexOf(state.anchor);
const b = ids.indexOf(id);
state.sel = {};
ids.slice(Math.min(a, b), Math.max(a, b) + 1).forEach(function(x) {
state.sel[x] = true;
});
} else {
state.sel = {};
state.sel[id] = true;
}
if (!(ev && ev.shiftKey)) {
state.anchor = id;
}
paintSel();
};
const paintSel = function() {
shell.querySelectorAll(".list [data-id]").forEach(function(el) {
const on = !!state.sel[el.getAttribute("data-id")];
el.classList.toggle(el.tagName === "TR" ? "hl" : "on", on);
const cb = el.querySelector("input[type=checkbox]");
if (cb) {
cb.checked = on;
}
});
drawTool();
};
// ---- messages ("Moved to the trash. Undo")
let noticeT = 0;
const notice = function(text, undo, stay) {
const n = shell.querySelector(".notice");
if (!n) {
return;
}
n.innerHTML = trusted_policy.createHTML("" + esc(text) + " " + (undo ? '' + (material && !gm ? "UNDO" : "Undo") + " " : "") +
(material ? "" : '' + (kennedy ? "×" : "Dismiss") + " "));
n.hidden = false;
const u = n.querySelector(".undo");
if (u) {
u.addEventListener("click", function(ev) {
ev.preventDefault();
n.hidden = true;
act.undo().then(function(ok) {
if (!ok) {
notice("Couldn't undo from here.");
}
});
});
}
const x = n.querySelector(".x");
if (x) {
x.addEventListener("click", function(ev) {
ev.preventDefault();
n.hidden = true;
});
}
clearTimeout(noticeT);
if (!stay) {
noticeT = setTimeout(function() {
n.hidden = true;
}, 8000);
}
};
const plural = function(n, w) {
return n + " " + (n === 1 ? w : w + "s");
};
// ---- menus
const closeMenus = function() {
shell.querySelectorAll(".dvmenu").forEach(function(m) {
m.remove();
});
shell.querySelectorAll(".dd.open").forEach(function(d) {
d.classList.remove("open");
});
};
const menu = function(anchor, items, at) {
closeMenus();
const m = document.createElement("div");
m.className = "dvmenu";
m.innerHTML = trusted_policy.createHTML(items.map(function(it, i) {
if (!it) {
return '
';
}
return '' + (material && it.icon ? '
' + (it.img ? ' ' : ic(it.icon, 20)) + " " :
(it.img && !material ? '
' : "")) + "
" + esc(it.label) + " ";
}).join(""));
shell.appendChild(m);
const r = at || anchor.getBoundingClientRect();
const mw = m.offsetWidth;
const mh = m.offsetHeight;
let x = at ? r.left : r.left;
let y = at ? r.top : r.bottom + (material ? 0 : 1);
if (x + mw > window.innerWidth - 8) {
x = Math.max(8, (at ? r.left : r.right) - mw);
}
if (y + mh > window.innerHeight - 8) {
y = Math.max(8, window.innerHeight - mh - 8);
}
m.style.left = x + "px";
m.style.top = y + "px";
if (anchor && anchor.classList) {
anchor.classList.add("open");
}
m.querySelectorAll(".mi2").forEach(function(el) {
el.addEventListener("click", function(ev) {
ev.stopPropagation();
const it = items[+el.getAttribute("data-i")];
if (it.off) {
return;
}
closeMenus();
it.fn();
});
});
};
const newItems = function() {
const doc = function(kind, label) {
return { label: label, icon: "insert_drive_file", img: ugfDvIcon(kind, material ? "mt" : era), fn: function() {
newDoc(kind);
} };
};
const folder = { label: material || era === "dv12" ? (gm ? "New folder" : "Folder") : W.Folder, icon: "create_new_folder", img: ugfDvIcon("folder", material ? "mt" : era), fn: function() {
ask(gm ? "New folder" : "New " + W.folder, "", gm ? "Create" : "Create", function(v) {
act.newFolder(v || "Untitled " + W.folder).then(function(ok) {
notice(ok ? (W.Folder + " created.") : "Couldn't create the " + W.folder + ".");
});
});
} };
const up = { label: "File upload", icon: "upload_file", fn: pickFiles };
const upF = { label: "Folder upload", icon: "drive_folder_upload", fn: folderUpload };
if (era === "dl07") {
return [doc("document", "Document"), doc("spreadsheet", "Spreadsheet"), doc("presentation", "Presentation"), null, folder];
}
if (era === "dl09") {
return [doc("document", "Document"), doc("presentation", "Presentation"), doc("spreadsheet", "Spreadsheet"), doc("form", "Form"), null, folder, null,
{ label: "From template...", fn: function() {
window.open("https://docs.google.com/document/u/0/?ftv=1&tgif=c", "_blank");
} }];
}
if (era === "dl10" || era === "dl11") {
return [doc("document", "Document"), doc("presentation", "Presentation"), doc("spreadsheet", "Spreadsheet"), doc("form", "Form"), doc("drawing", "Drawing"), null, folder, null,
{ label: "From template...", fn: function() {
window.open("https://docs.google.com/document/u/0/?ftv=1&tgif=c", "_blank");
} }];
}
if (era === "dv12") {
return [folder, null, doc("document", "Document"), doc("presentation", "Presentation"), doc("spreadsheet", "Spreadsheet"), doc("form", "Form"), doc("drawing", "Drawing")];
}
return [folder, null, up, upF, null, doc("document", "Google Docs"), doc("spreadsheet", "Google Sheets"), doc("presentation", "Google Slides"), doc("form", "Google Forms"),
doc("drawing", "Google Drawings")];
};
const moreItems = function(list) {
return actionsFor(list).map(function(a) {
return { label: a[1], icon: a[2], fn: function() {
doAction(a[0]);
} };
});
};
const sortItems = function() {
return [{ label: "Last modified", on: !state.sort, fn: function() {
state.sort = "";
drawList();
} }, { label: material ? "Name" : "Title", on: state.sort === "name", fn: function() {
state.sort = "name";
state.dir = 1;
drawList();
} }];
};
const gearItems = function() {
return [{ label: "Settings", icon: "settings", fn: function() {
window.open("https://drive.google.com/drive/settings", "_blank");
} }, { label: "Gplex settings", icon: "settings_applications", fn: function() {
window.open("https://www.google.com/gplex", "_blank");
} }, { label: "Help", icon: "help_outline", fn: function() {
window.open("https://support.google.com/drive", "_blank");
} }];
};
const moveItems = function() {
const sel = selected();
const ids = sel.map(function(it) {
return it.id;
});
const here2 = visible().filter(function(it) {
return ugfDvIsFolder(it) && ids.indexOf(it.id) < 0;
});
const items = [];
if (state.view.view === "folder") {
items.push({ label: "My Drive", icon: "folder", img: ugfDvIcon("folder", material ? "mt" : era), fn: function() {
moveTo(sel, "root", "My Drive");
} });
}
here2.slice(0, 15).forEach(function(f) {
items.push({ label: f.name, icon: "folder", img: ugfDvIcon("folder", material ? "mt" : era), fn: function() {
moveTo(sel, f.id, f.name);
} });
});
if (items.length) {
items.push(null);
}
items.push({ label: docsList ? "Other " + W.folder + "s..." : "Choose another folder...", fn: function() {
googleMove(sel[0]);
} });
return items;
};
const openMenu = function(anchor, which) {
if (anchor.classList.contains("open")) {
closeMenus();
return;
}
const sel = selected();
if (which === "new") {
menu(anchor, newItems());
} else if (which === "upload") {
menu(anchor, [{ label: "Files...", icon: "upload_file", fn: pickFiles }, { label: "Folder...", icon: "drive_folder_upload", fn: folderUpload }]);
} else if (which === "more") {
if (!sel.length) {
notice("Select one or more " + W.items + " first.");
return;
}
menu(anchor, moreItems(sel));
} else if (which === "move") {
if (!sel.length) {
notice("Select one or more " + W.items + " first.");
return;
}
menu(anchor, moveItems());
} else if (which === "sort") {
menu(anchor, sortItems());
} else if (which === "gear") {
menu(anchor, gearItems());
}
};
// ---- dialogs
const dialog = function(title, body, buttons, cls) {
const box = document.createElement("div");
box.className = "dvdlg-wrap";
box.innerHTML = trusted_policy.createHTML('
' + body + '
' + buttons.map(function(b, i) {
return '' + esc(b.label) + " ";
}).join("") + "
");
shell.appendChild(box);
const close = function() {
box.remove();
document.removeEventListener("keydown", onKey, true);
try {
shell.focus({ preventScroll: true });
} catch (e) {}
};
const onKey = function(ev) {
if (ev.key === "Escape") {
ev.preventDefault();
ev.stopPropagation();
close();
} else if (ev.key === "Enter" && ev.target && ev.target.tagName === "INPUT" && ev.target.type !== "checkbox") {
ev.preventDefault();
const pri = buttons.filter(function(b) {
return b.primary;
})[0];
if (pri && pri.fn(box) !== false) {
close();
}
}
};
document.addEventListener("keydown", onKey, true);
box.querySelectorAll(".dbtns button").forEach(function(b) {
b.addEventListener("click", function() {
const bt = buttons[+b.getAttribute("data-i")];
if (!bt.fn || bt.fn(box) !== false) {
close();
}
});
});
box.querySelector(".dx").addEventListener("click", function(ev) {
ev.preventDefault();
close();
});
box.querySelector(".dvfence").addEventListener("click", close);
const f = box.querySelector("input:not([readonly]), textarea");
if (f) {
setTimeout(function() {
f.focus();
f.select && f.select();
}, 0);
}
return { box: box, close: close };
};
const cancelLabel = era === "dv17" ? "CANCEL" : "Cancel";
const okLabel = function(s) {
return era === "dv17" ? s.toUpperCase() : s;
};
const ask = function(title, value, ok, fn) {
dialog(title, ' ', [{ label: okLabel(ok || "OK"), primary: true, fn: function(box) {
fn(box.querySelector(".dvin").value.trim());
} }, { label: cancelLabel }]);
};
const sure = function(title, text, ok, fn) {
dialog(title, "" + esc(text) + "
", [{ label: okLabel(ok), primary: true, fn: fn }, { label: cancelLabel }]);
};
// the details of a file: what Google's list says about it
const details = function(it) {
if (!it) {
return;
}
const row = function(k, v) {
return v ? "" + esc(k) + " " + esc(v) + " " : "";
};
const thumb = ["image", "pdf", "document", "spreadsheet", "presentation", "drawing", "video"].indexOf(it.kind) > -1;
let extra = "";
Object.keys(it.cols).forEach(function(k) {
if (["Owner", "Last modified", "File size", "Location", "Reason suggested"].indexOf(k) < 0) {
extra += row(k, it.cols[k]);
}
});
dialog(it.name, (thumb ? '' : "") + '' + row("Type", it.type || (ugfDvIsFolder(it) ? W.Folder : "")) +
row("Owner", ownerOf(it)) + row("Location", it.location) + row(inTrash() ? "Trashed" : "Modified", dateOf(it)) + row("Size", it.size) + row("Shared", it.shared ? "Yes" : "") +
row("Starred", it.starred ? "Yes" : "") + extra + "
", [{ label: okLabel("Open"), primary: true, fn: function() {
openItem(it);
} }, { label: era === "dv17" ? "CLOSE" : "Close" }], "wide");
const img = shell.querySelector(".dvthumb img");
if (img) {
img.addEventListener("error", function() {
img.parentElement.remove();
}, { once: true });
}
};
// a picture, large, over the page (the other kinds open in a new tab)
const preview = function(it) {
const box = document.createElement("div");
box.className = "dvprev";
box.innerHTML = trusted_policy.createHTML('" +
'');
shell.appendChild(box);
const close = function() {
box.remove();
document.removeEventListener("keydown", onKey, true);
};
const onKey = function(ev) {
if (ev.key === "Escape") {
ev.preventDefault();
close();
}
};
document.addEventListener("keydown", onKey, true);
box.addEventListener("click", function(ev) {
const a = ev.target.closest("[data-p]");
if (a && a.getAttribute("data-p") === "open") {
return;
}
ev.preventDefault();
if (a && a.getAttribute("data-p") === "dl") {
act.download(it.id);
}
if (!a || a.getAttribute("data-p") === "x" || a.getAttribute("data-p") === "dl" || ev.target.classList.contains("pimg")) {
close();
}
});
};
// sharing: the period's dialog, carried out in Google's own share dialog
const share = function(it) {
if (!it) {
return;
}
const link = ugfDvShareUrl(it);
const title = docsList ? (era === "dl11" ? "Sharing settings" : "Share " + it.name) : era === "dv12" ? "Sharing settings" : "Share with others";
const body = '" +
'' +
'";
const d = dialog(title, body, [{ label: okLabel(material ? "Done" : "Share & save"), primary: true, fn: function(box) {
const emails = box.querySelector(".who").value.split(/[\s,;]+/).filter(function(x) {
return /@/.test(x);
});
if (!emails.length) {
return true;
}
const role = box.querySelector(".role").value;
const notify = box.querySelector(".notify").checked;
const note = box.querySelector(".note").value;
notice("Sharing...", false, true);
act.share(it.id).then(async function(sd) {
if (!sd) {
notice("Couldn't open sharing for this " + W.item + ".");
return;
}
const ok = await ugfDvShareInvite(sd, emails, role, notify, note);
if (ok) {
notice("Shared with " + plural(emails.length, "person").replace("persons", "people") + ".");
} else {
notice("Finish sharing in the dialog below.");
ugfDvReveal(sd.frame || sd.dialog);
}
});
return true;
} }, { label: cancelLabel }], "share");
d.box.querySelector(".cpy").addEventListener("click", function() {
const inp = d.box.querySelector(".lnk");
inp.select();
const done = function() {
notice("Link copied to clipboard.");
};
try {
navigator.clipboard.writeText(link).then(done, function() {
document.execCommand("copy");
done();
});
} catch (e) {
document.execCommand("copy");
done();
}
});
d.box.querySelector(".adv").addEventListener("click", function(ev) {
ev.preventDefault();
d.close();
act.share(it.id).then(function(sd) {
if (sd) {
ugfDvReveal(sd.frame || sd.dialog);
} else {
notice("Couldn't open sharing for this " + W.item + ".");
}
});
});
};
// moving: Gplex's own list of folders; any other goes through Google's move dialog
const moveTo = function(list, target, name) {
let n = 0;
let bad = 0;
list.forEach(function(it) {
act.move(it.id, target).then(function(ok) {
ok ? n++ : bad++;
if (n + bad === list.length) {
if (bad && n === 0 && list.length === 1) {
googleMove(list[0]);
} else {
notice(n ? "Moved " + plural(n, W.item) + " to “" + name + "”." : "Couldn't move the " + W.items + ".", n > 0);
}
}
});
});
};
const googleMove = function(it) {
if (!it) {
return;
}
act.moveDialog(it.id).then(function(dl) {
if (dl) {
ugfDvReveal(dl);
} else {
notice("Couldn't open the move dialog.");
}
});
};
// ---- uploading: by Google's own File upload and Folder upload (its picker, its
// uploading), or by dropping files, which pass straight through to Google's page
// Google's own upload panel is watched (out of sight under Gplex's page), and the
// list: an upload is only called complete once Google has said so after saying it
// was uploading, or once the files are in the list. What Google's panel says is
// written to the console, so an upload that goes wrong can be followed.
let upNames = [];
window.addEventListener("change", function(ev) {
const t = ev.target;
if (t && t.type === "file" && !t.closest("#ugf-drive") && t.files && t.files.length) {
upNames = [].map.call(t.files, function(f) {
return f.name;
});
console.log("[Gplex] Drive: " + upNames.length + " file(s) chosen in Google's picker");
watchUpload(upNames);
}
}, true);
const watchUpload = function(names) {
names = names || [];
const started = Date.now();
const before = {};
state.items.forEach(function(it) {
before[it.id] = true;
});
let going = false;
let lastSaid = "";
clearInterval(watchUpload.t);
const panelText = function() {
let txt = "";
document.querySelectorAll("[role=alert], [role=status], [aria-live], [role=dialog], [role=log], [role=region], [role=complementary]").forEach(function(el) {
if (!el.closest("#ugf-drive") && !el.closest("[role=main]") && el.getClientRects().length) {
txt += " " + (el.innerText || el.textContent || "");
}
});
return txt.replace(/\s+/g, " ").trim();
};
const arrived = function() {
return state.items.filter(function(it) {
return !before[it.id] && (!names.length || names.some(function(nm) {
return it.name === nm || it.name === nm.replace(/\.[^.]+$/, "");
}));
}).length;
};
watchUpload.t = setInterval(function() {
const txt = panelText();
const bit = (txt.match(/[^.]{0,40}upload[^.]{0,60}/i) || [""])[0].trim();
if (bit && bit !== lastSaid) {
lastSaid = bit;
console.log("[Gplex] Drive: Google says: " + bit.slice(0, 120));
}
if (/uploading|preparing|\d+ (items?|files?) remaining|upload(s)? in progress/i.test(txt)) {
going = true;
notice("Uploading" + (names.length ? " " + plural(names.length, "file") : "") + "...", false, true);
}
const n = arrived();
if (n && (!names.length || n >= names.length)) {
clearInterval(watchUpload.t);
notice("Upload complete.");
} else if (going && /\b\d+ uploads? complete|\bupload complete/i.test(txt)) {
// (Google says it is done: the list catches up in a moment)
if (!watchUpload.doneAt) {
watchUpload.doneAt = Date.now();
} else if (Date.now() - watchUpload.doneAt > 8000) {
clearInterval(watchUpload.t);
watchUpload.doneAt = 0;
notice("Upload complete. (It may be in another folder: Google puts uploads where it was told to.)");
}
} else if (/upload(s)? failed|couldn.t upload|can.t upload|upload error|failed to upload/i.test(txt)) {
clearInterval(watchUpload.t);
notice("The upload didn't finish.");
} else if (!going && Date.now() - started > 20000) {
clearInterval(watchUpload.t);
if (names.length) {
console.log("[Gplex] Drive: Google never started uploading");
notice("Google didn't start the upload.");
}
} else if (Date.now() - started > 1800000) {
clearInterval(watchUpload.t);
}
}, 600);
};
const pickFiles = function() {
act.googleUpload(false).then(function(ok) {
console.log("[Gplex] Drive: Google's File upload " + (ok ? "pressed" : "not found"));
if (!ok) {
notice("Couldn't open the upload. Drag the files onto the list instead.");
}
});
};
const folderUpload = function() {
act.googleUpload(true).then(function(ok) {
console.log("[Gplex] Drive: Google's Folder upload " + (ok ? "pressed" : "not found"));
if (!ok) {
notice("Couldn't open the folder upload. Drag the folder onto the list instead.");
}
});
};
// ---- doing what was asked
const doAction = function(a) {
const sel = selected();
const one = sel[0];
if (!sel.length && ["all", "none", "grid", "morenav", "upload", "details"].indexOf(a) < 0) {
notice("Select one or more " + W.items + " first.");
return;
}
if (a === "open") {
openItem(one);
} else if (a === "share") {
share(one);
} else if (a === "link") {
const link = ugfDvShareUrl(one);
try {
navigator.clipboard.writeText(link).then(function() {
notice("Link copied to clipboard.");
}, function() {
share(one);
});
} catch (e) {
share(one);
}
} else if (a === "move") {
openMenu(shell.querySelector("[data-m=move]") || shell.querySelector(".tool") || shell, "move");
} else if (a === "star" || a === "star1") {
const on = !sel.every(function(it) {
return it.starred;
});
sel.forEach(function(it) {
if (it.starred !== on) {
it.starred = on;
act.star(it.id);
}
});
drawList();
} else if (a === "rename") {
ask(material ? "Rename" : "Rename " + W.item, one.name, "OK", function(v) {
if (v && v !== one.name) {
act.rename(one.id, v).then(function(ok) {
notice(ok ? "Renamed to “" + v + "”." : "Couldn't rename the " + W.item + ".");
});
}
});
} else if (a === "copy") {
sel.forEach(function(it) {
act.copy(it.id);
});
notice("Making a copy...");
} else if (a === "download") {
sel.forEach(function(it) {
act.download(it.id);
});
} else if (a === "details") {
details(one || null);
} else if (a === "trash") {
const go2 = function() {
let n = 0;
sel.forEach(function(it) {
act.trash(it.id).then(function(ok) {
if (ok) {
n++;
}
if (it === sel[sel.length - 1]) {
notice(n ? (sel.length === 1 ? "“" + one.name + "” has been moved to the trash." : plural(n, W.item) + " moved to the trash.") : "Couldn't remove the " + W.items + ".", n > 0);
}
});
});
state.sel = {};
};
if (docsList && era !== "dl11") {
sure("Delete", "Move " + (sel.length === 1 ? "“" + one.name + "”" : plural(sel.length, W.item)) + " to the trash?", "Delete", go2);
} else {
go2();
}
} else if (a === "restore") {
sel.forEach(function(it) {
act.restore(it.id);
});
notice(plural(sel.length, W.item) + " restored.");
state.sel = {};
} else if (a === "purge") {
sure("Delete forever", (sel.length === 1 ? "“" + one.name + "”" : plural(sel.length, W.item)) + " will be deleted forever. This can't be undone.", "Delete forever", function() {
sel.forEach(function(it) {
act.purge(it.id);
});
state.sel = {};
});
}
};
// ---- the page's clicks, keys and drops
shell.addEventListener("click", function(ev) {
const t = ev.target;
if (!t.closest(".dvmenu") && !t.closest(".dd")) {
closeMenus();
}
const ddEl = t.closest(".dd[data-m]");
if (ddEl && ddEl.getAttribute("data-m")) {
ev.preventDefault();
openMenu(ddEl, ddEl.getAttribute("data-m"));
return;
}
const goEl = t.closest("[data-go]");
if (goEl) {
ev.preventDefault();
go(goEl.getAttribute("data-go"));
return;
}
const fEl = t.closest("[data-folder]");
if (fEl) {
ev.preventDefault();
openFolder({ id: fEl.getAttribute("data-folder"), name: fEl.getAttribute("data-name") || "" }, "my-drive");
return;
}
const aEl = t.closest("[data-a]");
if (aEl) {
ev.preventDefault();
const a = aEl.getAttribute("data-a");
if (a === "star1") {
const tr = aEl.closest("[data-id]");
if (tr) {
state.sel = {};
state.sel[tr.getAttribute("data-id")] = true;
}
doAction("star");
} else if (a === "upload") {
pickFiles();
} else if (a === "grid") {
state.grid = !state.grid;
try {
localStorage.setItem("UGF_DV_GRID", state.grid ? "1" : "0");
} catch (e) {}
frame();
} else if (a === "morenav") {
state.moreNav = !state.moreNav;
drawNav();
} else if (a === "all" || a === "none") {
state.sel = {};
if (a === "all") {
visible().forEach(function(it) {
state.sel[it.id] = true;
});
}
paintSel();
} else if (a === "details" && !selected().length) {
notice("Select an " + W.item + " to see its details.");
} else {
doAction(a);
}
return;
}
const sortEl = t.closest("[data-sort]");
if (sortEl) {
const k = sortEl.getAttribute("data-sort");
if (k === "name" && state.sort === "name") {
state.dir = -state.dir;
} else {
state.sort = k;
state.dir = 1;
}
drawList();
return;
}
if (t.matches("thead input.all")) {
state.sel = {};
if (t.checked) {
visible().forEach(function(it) {
state.sel[it.id] = true;
});
}
paintSel();
return;
}
const row = t.closest(".list [data-id]");
if (row) {
const id = row.getAttribute("data-id");
if (t.closest("a.op")) {
ev.preventDefault();
openItem(byId(id));
return;
}
if (t.matches("input[type=checkbox]")) {
state.sel[id] = t.checked;
state.anchor = id;
paintSel();
return;
}
choose(id, ev);
return;
}
if (t.closest(".list") && !t.closest("thead, .lhead")) {
state.sel = {};
paintSel();
}
});
shell.addEventListener("dblclick", function(ev) {
const row = ev.target.closest(".list [data-id]");
if (row && !ev.target.closest("input, .star")) {
ev.preventDefault();
openItem(byId(row.getAttribute("data-id")));
}
});
shell.addEventListener("contextmenu", function(ev) {
const row = ev.target.closest(".list [data-id]");
if (!row || docsList) {
return;
}
ev.preventDefault();
const id = row.getAttribute("data-id");
if (!state.sel[id]) {
choose(id, null);
}
menu(null, moreItems(selected()), { left: ev.clientX, top: ev.clientY, right: ev.clientX, bottom: ev.clientY });
});
shell.addEventListener("submit", function(ev) {
const f = ev.target;
ev.preventDefault();
const v = (f.querySelector("input[name=q]") || {}).value || "";
if (v.trim()) {
window.location.href = ugfDvBase() + "/search?q=" + encodeURIComponent(v.trim());
}
});
shell.addEventListener("click", function(ev) {
if (ev.target.classList && ev.target.classList.contains("web")) {
const v = (shell.querySelector("form input[name=q]") || {}).value || "";
window.location.href = "https://www.google.com/search?q=" + encodeURIComponent(v);
}
});
// keys: kept from Google's page underneath (its shortcuts would act on its own list)
shell.addEventListener("keydown", function(ev) {
ev.stopPropagation();
const inField = /^(INPUT|TEXTAREA|SELECT)$/.test(ev.target.tagName);
if (inField || shell.querySelector(".dvdlg-wrap, .dvprev")) {
return;
}
const list = visible();
const ids = list.map(function(it) {
return it.id;
});
const cur = ids.indexOf(state.anchor);
if (ev.key === "ArrowDown" || ev.key === "ArrowUp") {
ev.preventDefault();
const n = Math.max(0, Math.min(ids.length - 1, cur + (ev.key === "ArrowDown" ? 1 : -1)));
if (ids[n]) {
choose(ids[n], ev.shiftKey ? { shiftKey: true } : null);
const el = shell.querySelector('.list [data-id="' + ids[n].replace(/"/g, "") + '"]');
if (el) {
el.scrollIntoView({ block: "nearest" });
}
}
} else if (ev.key === "Enter" && selected().length === 1) {
ev.preventDefault();
openItem(selected()[0]);
} else if ((ev.key === "Delete" || ev.key === "Backspace") && selected().length && !inTrash()) {
ev.preventDefault();
doAction("trash");
} else if ((ev.key === "a" || ev.key === "A") && (ev.ctrlKey || ev.metaKey)) {
ev.preventDefault();
doAction("all");
} else if (ev.key === "Escape") {
closeMenus();
}
});
["keyup", "keypress"].forEach(function(t) {
shell.addEventListener(t, function(ev) {
ev.stopPropagation();
});
});
// files dragged in from the computer: Gplex's page lets them through to Google's
// underneath (a real drop, which Google uploads into the folder being shown), and
// marks the list meanwhile
const hasFiles = function(ev) {
return ev.dataTransfer && [].indexOf.call(ev.dataTransfer.types || [], "Files") > -1;
};
let dragT = 0;
const dragOff = function(dropped) {
clearTimeout(dragT);
if (html.hasAttribute("gplex-dv-drag")) {
html.removeAttribute("gplex-dv-drag");
shell.classList.remove("drop");
if (dropped && dropped.length) {
console.log("[Gplex] Drive: " + dropped.length + " file(s) dropped on Google's page" + (dropTook ? "" : " (not taken)"));
if (dropTook) {
notice("Uploading...", false, true);
watchUpload(dropped);
}
}
}
};
let dropTook = false;
window.addEventListener("dragenter", function(ev) {
if (!hasFiles(ev) || shell.hidden) {
return;
}
html.setAttribute("gplex-dv-drag", "");
shell.classList.add("drop");
clearTimeout(dragT);
}, true);
window.addEventListener("dragover", function(ev) {
if (html.hasAttribute("gplex-dv-drag")) {
clearTimeout(dragT);
// (the drag has left the window when these stop coming)
dragT = setTimeout(function() {
dragOff(false);
}, 900);
}
}, true);
window.addEventListener("drop", function(ev) {
if (html.hasAttribute("gplex-dv-drag")) {
const names = ev.dataTransfer && ev.dataTransfer.files ? [].map.call(ev.dataTransfer.files, function(f) {
return f.name;
}) : [];
dropTook = true;
setTimeout(function() {
dragOff(names);
}, 50);
}
}, true);
window.addEventListener("dragend", function() {
dragOff(false);
}, true);
// (a drop Google's page did not take is not left to the browser, which would open
// the file in place of Drive)
window.addEventListener("dragover", function(ev) {
if (html.hasAttribute("gplex-dv-drag") && hasFiles(ev) && !ev.defaultPrevented) {
ev.preventDefault();
}
});
window.addEventListener("drop", function(ev) {
if (html.hasAttribute("gplex-dv-drag") && !ev.defaultPrevented) {
ev.preventDefault();
dropTook = false;
setTimeout(function() {
notice("Drop the files onto the list of files to upload them.");
}, 80);
}
});
// more of a long list: Google loads it as its own list is scrolled
shell.addEventListener("scroll", function(ev) {
const m = ev.target;
if (!m.classList || !m.classList.contains("main") || m.scrollTop + m.clientHeight < m.scrollHeight - 200) {
return;
}
const last = state.items[state.items.length - 1];
const row = last ? ugfDvRow(last.id) : null;
if (row) {
try {
row.scrollIntoView({ block: "end" });
} catch (e) {}
}
}, true);
// ---- keeping up with Google's page
const harvest = function() {
const items = ugfDvHarvest().filter(function(it) {
return it.el.getClientRects().length > 0;
});
const key = items.map(function(i) {
return i.id + "|" + i.name + "|" + i.starred + "|" + i.modified + "|" + i.owner + "|" + i.size;
}).join("#");
if (key !== state.lastKey) {
state.lastKey = key;
state.items = items;
if (items.length) {
state.loaded = true;
}
Object.keys(state.sel).forEach(function(id) {
if (!byId(id)) {
delete state.sel[id];
}
});
remember();
drawList();
quotaFill();
}
};
let myTitle = "";
const titleFor = function() {
const v = state.view.view;
const name = v === "folder" ? (currentTitle() || "Folder") : v === "search" ? "Search results" : placeName(v);
if (docsList) {
return "Google Docs - " + name;
}
return name + " - Google Drive";
};
const tick = function() {
const v = ugfDvView();
// a part of Drive Gplex does not draw (settings, a file's page...): Google's own
if (v.view === "") {
if (!shell.hidden) {
shell.hidden = true;
html.removeAttribute("gplex-dv");
}
return;
}
if (shell.hidden) {
shell.hidden = false;
html.setAttribute("gplex-dv", era);
}
if (document.title !== myTitle) {
state.gTitle = document.title;
}
const changed = v.view !== state.view.view || v.id !== state.view.id || v.q !== state.view.q;
if (changed) {
state.view = v;
state.sel = {};
state.items = [];
state.lastKey = "";
state.loaded = false;
closeMenus();
drawNav();
drawList();
setTimeout(function() {
state.loaded = true;
if (!state.items.length) {
drawList();
}
}, 6000);
}
// Drive opens on its Home page; the Drive of these years opened on My Drive
if ((v.view === "home" || v.view === "root") && era !== "dl10" && era !== "dl11" && !tick.left) {
tick.left = true;
go("my-drive");
}
myTitle = titleFor();
if (document.title !== myTitle) {
document.title = myTitle;
}
harvest();
if (changed || !tick.crumbAt || Date.now() - tick.crumbAt > 2000) {
tick.crumbAt = Date.now();
drawTool();
}
};
frame();
tick();
setTimeout(function() {
state.loaded = true;
if (!state.items.length) {
drawList();
}
}, 8000);
setInterval(tick, 700);
}
// ---- Drive: the styles of each period ----------------------------------------------
function ugfDriveCss(era, A) {
const H = "#ugf-drive";
const c = [];
const add = function(sel, body) {
c.push(sel.split(",").map(function(s) {
return H + " " + s.trim();
}).join(", ") + " { " + body + " }");
};
const l = String(layout || "");
const kennedy = era === "dl11" || era === "dv12";
const material = era === "dv14" || era === "dv17" || era === "dv19";
const gm = era === "dv19";
const classic = era === "dl07" || era === "dl09" || era === "dl10";
const f = gm ? "'Google Sans', Roboto, Arial, sans-serif" : material ? "Roboto, RobotoDraft, Helvetica, Arial, sans-serif" : "Arial, sans-serif";
// the Google bar and the account corner, from the shared styles (Google's page is
// left as it is underneath: Gplex's page simply covers it)
ugfNtBaseCss("ugf-drive").forEach(function(r) {
if (r.indexOf("html[gplex-nt]") !== 0 && r.indexOf(H + " {") !== 0) {
c.push(r);
}
});
c.push("html[gplex-dv], html[gplex-dv] body { overflow: hidden !important; }");
c.push("html[gplex-dv] body > [ugf-dv-up] { z-index: 2147483100 !important; }");
c.push("html[gplex-dv-reveal] " + H + " { display: none !important; }");
c.push("html[gplex-dv] #ugf-gmail-accfence { z-index: 2147483600 !important; } html[gplex-dv] #ugf-gmail-accmenu, html[gplex-dv] #ugf-gmail-appsmenu { z-index: 2147483601 !important; text-align: left; }");
c.push("html[gplex-dv] #ugf-gmail-accmenu a, html[gplex-dv] #ugf-gmail-appsmenu a { text-decoration: none; }");
c.push(H + " { position: fixed; inset: 0; z-index: 2147483000; display: flex; flex-direction: column; background: #fff; color: #000; font: 13px " + f + "; text-align: left; overflow: hidden; outline: none; }");
c.push(H + "[hidden] { display: none !important; }");
c.push(H + ".busy, " + H + ".busy * { cursor: progress !important; }");
// (while files are dragged in, the page lets them through to Google's)
c.push("html[gplex-dv-drag] " + H + " { pointer-events: none !important; }");
c.push(H + ".drop .main { outline: 3px dashed " + (material ? "#4285f4" : "#6d9eeb") + "; outline-offset: -6px; background: " + (gm ? "#e8f0fe" : "#f3f7fe") + "; }");
add("*", "box-sizing: border-box;");
add("a", "cursor: pointer;");
add(".mi", "display: inline-flex; font-style: normal;");
add(".mi svg", "display: block; fill: currentColor;");
add(".body", "flex: 1; display: flex; min-height: 0;");
add(".side", "flex: 0 0 auto; overflow: auto; display: flex; flex-direction: column;");
add(".main", "flex: 1; overflow: auto; min-width: 0; position: relative;");
add("form", "display: flex; align-items: center; margin: 0;");
add(".sp", "flex: 1;");
add(".dd, [data-a], [data-go], [data-folder], [data-sort]", "cursor: pointer; user-select: none;");
add(".empty", "padding: 24px; color: #777; font-size: 13px;");
add(".fi", "width: 16px; height: 16px; vertical-align: -3px; margin-right: 6px; flex: 0 0 16px;");
add(".nav .fi", "margin-right: 5px;");
add("table.list", "width: 100%; border-collapse: collapse; table-layout: fixed;");
add("table.list td, table.list th", "white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: left; font-weight: normal;");
add("table.list .cb", "width: 28px; text-align: center;");
add("table.list .st", "width: 24px;");
add("table.list .ow, table.list .fs", "width: 22%;");
add("table.list .dt", "width: 18%;");
add("table.list tr[data-id]", "cursor: default;");
add("table.list td.nm a", "text-decoration: none;");
add("table.list input", "margin: 0; vertical-align: middle;");
add(".tag", "font-size: 11px; color: #777;");
add(".star", "display: inline-block; width: 16px; height: 16px; vertical-align: middle;");
add(".upin", "display: none;");
// ---- the messages
add(".notice", "position: absolute; z-index: 60; display: flex; align-items: center; gap: 12px;");
add(".notice[hidden]", "display: none;");
if (material) {
add(".notice", "left: 24px; bottom: 24px; min-height: 48px; padding: 6px 24px; background: " + (gm ? "#202124" : "#323232") + "; color: #fff; font: 14px " + f + "; box-shadow: 0 3px 5px rgba(0,0,0,.2); border-radius: " + (gm ? "4px" : "2px") + "; max-width: 560px;");
add(".notice a", "color: " + (gm ? "#8ab4f8" : "#eeff41") + "; text-decoration: none; font-weight: 500; margin-left: 12px;");
} else if (kennedy) {
add(".notice", "left: 50%; top: 6px; transform: translateX(-50%); padding: 6px 12px; background: #f9edbe; border: 1px solid #f0c36d; box-shadow: 0 2px 4px rgba(0,0,0,.2); font: bold 13px Arial, sans-serif; color: #222; border-radius: 2px;");
add(".notice a", "color: #222; text-decoration: underline;");
add(".notice .x", "text-decoration: none; font-size: 16px; color: #777; margin-left: 4px;");
} else {
add(".notice", "left: 50%; top: 4px; transform: translateX(-50%); padding: 4px 10px; background: #fad163; font: bold 13px Arial, sans-serif; color: #000; border-radius: 3px;");
add(".notice a", "color: #00c; text-decoration: underline; font-weight: normal;");
}
// ---- menus: square until 2019
add(".dvmenu", "position: fixed; z-index: 70; background: #fff; min-width: 170px; max-height: 70vh; overflow: auto; " +
(gm ? "padding: 6px 0; border-radius: 4px; box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2); font: 14px Roboto, Arial, sans-serif;"
: material ? "padding: 8px 0; box-shadow: 0 2px 10px rgba(0,0,0,.2); font: 13px " + f + ";"
: kennedy ? "padding: 6px 0; border: 1px solid rgba(0,0,0,.2); box-shadow: 0 2px 4px rgba(0,0,0,.2); font: 13px Arial, sans-serif;"
: "padding: 2px 0; border: 1px solid; border-color: #ccc #666 #666 #ccc; font: 13px Arial, sans-serif;"));
add(".dvmenu .mi2", "display: flex; align-items: center; white-space: nowrap; color: " + (material ? "#202124" : "#222") + "; " +
(material ? "gap: 16px; padding: 0 24px 0 16px; line-height: 32px;" : kennedy ? "padding: 6px 44px 6px 30px; position: relative;" : "padding: 3px 18px 3px 8px;"));
add(".dvmenu .mi2:hover", material ? "background: " + (gm ? "#f1f3f4" : "#eee") + ";" : kennedy ? "background: #eee;" : "background: #316ac5; color: #fff;");
add(".dvmenu .mi2.off", "color: #aaa; pointer-events: none;");
add(".dvmenu .mi2.chk::before", "content: '\\2713'; " + (material ? "margin-right: 8px;" : kennedy ? "position: absolute; left: 10px;" : "margin-right: 4px;"));
add(".dvmenu .mic", "display: inline-flex; width: 20px; justify-content: center; color: #5f6368;");
add(".dvmenu .mic img", "width: 16px; height: 16px;");
add(".dvmenu .msep", "height: 1px; background: " + (material ? "#e0e0e0" : "#ebebeb") + "; margin: " + (material ? "8px 0" : "4px 0") + ";");
// ---- dialogs
// the dialogs: Kennedy's (with its blue and grey buttons, and boxed fields) until
// 2016, Material's flat ones from 2017
const kdlg = kennedy || era === "dv14";
const mdlg = material && era !== "dv14";
add(".dvdlg-wrap", "position: fixed; inset: 0; z-index: 80;");
add(".dvfence", "position: absolute; inset: 0; background: " + (mdlg ? "rgba(0,0,0,.4)" : kdlg ? "rgba(255,255,255,.75)" : "rgba(0,0,0,.25)") + ";");
add(".dvdlg", "position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); background: #fff; width: 440px; max-width: calc(100% - 32px); max-height: calc(100% - 32px); overflow: auto; " +
(gm ? "border-radius: 8px; padding: 24px; box-shadow: 0 1px 3px rgba(60,64,67,.3), 0 4px 8px 3px rgba(60,64,67,.15);"
: mdlg ? "padding: 24px; box-shadow: 0 16px 24px rgba(0,0,0,.3);"
: kdlg ? "padding: 30px 42px; border: 1px solid #acacac; box-shadow: 0 4px 16px rgba(0,0,0,.2);"
: "border: 1px solid #6b90da; padding: 0 0 10px;"));
add(".dvdlg.wide", "width: 520px;");
add(".dvdlg.share", "width: 560px;");
add(".dvdlg .dt2", "display: flex; align-items: center; " + (mdlg ? "font: " + (gm ? "400 22px 'Google Sans', Roboto, sans-serif; color: #202124;" : "500 20px Roboto, sans-serif; color: #212121;") + " margin-bottom: 20px;"
: kdlg ? "font: 16px Arial, sans-serif; color: #222; margin-bottom: 16px;" : "background: #e0ecff; padding: 5px 8px; font: bold 13px Arial, sans-serif; margin-bottom: 10px;"));
add(".dvdlg .dt2 span", "flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;");
add(".dvdlg .dx", "text-decoration: none; color: #777; font-size: " + (kdlg ? "22px" : "18px") + "; line-height: 1; margin-left: 12px;");
add(".dvdlg .db", (classic ? "padding: 0 12px;" : "") + " font-size: 13px; color: #222;");
add(".dvdlg .db p", "margin: 0 0 8px;");
add(".dvdlg .dvin, .dvdlg .shl input[type=text], .dvdlg .shi input[type=text]", "width: 100%; height: " + (mdlg ? "36px" : "29px") + "; font: 13px " + f + "; padding: 0 8px; outline: none; " +
(mdlg ? "border: 0; border-bottom: 1px solid #ccc; padding: 0 2px; font-size: 15px;" : "border: 1px solid #d9d9d9; border-top-color: #c0c0c0; border-radius: 1px;"));
add(".dvdlg .dvin:focus, .dvdlg input[type=text]:focus", mdlg ? "border-bottom: 2px solid #4285f4;" : "border-color: #4d90fe;");
add(".dvdlg .dbtns", "display: flex; gap: 8px; margin-top: 22px; " + (mdlg ? "justify-content: flex-end; flex-direction: row-reverse;" : classic ? "padding: 0 12px;" : ""));
if (mdlg) {
add(".dvdlg .dbtns", "justify-content: flex-start;");
add(".dvdlg .dbtns button", "border: 0; background: none; color: " + (gm ? "#1a73e8" : "#4285f4") + "; font: 500 14px " + (gm ? "'Google Sans', Roboto" : "Roboto") + ", sans-serif; height: 36px; padding: 0 12px; cursor: pointer; border-radius: " + (gm ? "4px" : "2px") + ";");
add(".dvdlg .dbtns button:hover", "background: rgba(66,133,244,.08);");
add(".dvdlg .dbtns", "flex-direction: row-reverse; justify-content: flex-start;");
add(".dvdlg .dbtns button.pri", gm ? "background: #1a73e8; color: #fff; padding: 0 24px;" : "");
} else if (kdlg) {
add(".dvdlg .dbtns button", "height: 29px; min-width: 72px; padding: 0 12px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px Arial, sans-serif; cursor: default;");
add(".dvdlg .dbtns button.pri", "background: linear-gradient(#4d90fe, #4787ed); border-color: #3079ed; color: #fff;");
} else {
add(".dvdlg .dbtns button", "font: 13px Arial, sans-serif; padding: 2px 10px;");
add(".dvdlg .dbtns button.pri", "font-weight: bold;");
}
add(".dvprops", "border-collapse: collapse; width: 100%; margin-top: 8px;");
add(".dvprops th", "text-align: left; font-weight: normal; color: #777; padding: 4px 16px 4px 0; width: 110px; vertical-align: top;");
add(".dvprops td", "padding: 4px 0; word-break: break-word;");
add(".dvthumb", "text-align: center; background: #f5f5f5; margin-bottom: 8px;");
add(".dvthumb img", "max-width: 100%; max-height: 220px; display: inline-block;");
// sharing
add(".dvdlg .lab", "font-weight: bold; margin: 0 0 6px; " + (mdlg ? "font-weight: 500; color: #202124; font-size: 14px;" : ""));
add(".dvdlg .row", "display: flex; gap: 8px; align-items: center;");
add(".dvdlg .shl", "padding-bottom: 14px; margin-bottom: 14px; border-bottom: 1px solid #ebebeb;");
add(".dvdlg .shl .lnk", "color: #666;");
add(".dvdlg .row button, .dvdlg select", "height: " + (mdlg ? "36px" : "29px") + "; font: " + (mdlg ? "500 13px Roboto" : "bold 11px Arial") + ", sans-serif; white-space: nowrap; " +
(mdlg ? "border: 0; background: none; color: " + (gm ? "#1a73e8" : "#4285f4") + "; padding: 0 8px;" : "border: 1px solid #d9d9d9; border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; padding: 0 8px;"));
add(".dvdlg select", mdlg ? "border: 0; border-bottom: 1px solid #ccc; color: #444; font-weight: normal;" : "font-weight: normal;");
add(".dvdlg .nt", "display: flex; align-items: center; gap: 6px; margin: 10px 0 6px;");
add(".dvdlg .nt input", "margin: 0;");
add(".dvdlg .note", "width: 100%; font: 13px " + f + "; padding: 6px 8px; resize: vertical; " + (mdlg ? "border: 1px solid #ddd;" : "border: 1px solid #d9d9d9; border-top-color: #c0c0c0;"));
add(".dvdlg .shadv", "margin-top: 12px;");
add(".dvdlg .shadv a", "color: " + (mdlg ? "#4285f4" : "#15c") + "; text-decoration: none;");
// a picture, large
add(".dvprev", "position: fixed; inset: 0; z-index: 85; background: rgba(0,0,0,.85); display: flex; flex-direction: column;");
add(".dvprev .pbar", "display: flex; align-items: center; gap: 12px; height: 56px; padding: 0 16px; color: #fff; background: rgba(0,0,0,.6); font: 14px " + f + ";");
add(".dvprev .pbar a", "color: #fff; text-decoration: none; display: inline-flex; align-items: center;" + (material ? "" : " border: 1px solid #777; padding: 4px 10px; border-radius: 2px; font: bold 11px Arial, sans-serif;"));
add(".dvprev .pn", "display: flex; align-items: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;");
add(".dvprev .pimg", "flex: 1; display: flex; align-items: center; justify-content: center; min-height: 0; padding: 16px;");
add(".dvprev .pimg img", "max-width: 100%; max-height: 100%; box-shadow: 0 4px 16px rgba(0,0,0,.5); background: #fff;");
// ---- the Docs list: 2007-2008
add(".toplinks", "display: flex; justify-content: space-between; padding: 3px 8px 0; height: 24px; font-size: 13px; flex: 0 0 auto;");
add(".toplinks .left > *", "margin-right: 8px;");
add(".toplinks a", "color: #00c;");
add(".toplinks .more small", "font-size: 9px;");
if (classic) {
add(".hdr", "display: flex; align-items: center; gap: 10px; padding: 8px 8px 10px; flex: 0 0 auto;");
add(".hdr .logo img", "display: block;");
add(".srch input", "width: 290px; height: 22px; font-size: 13px; padding: 1px 3px; border: 1px solid; border-color: #999 #ccc #ccc #999;");
add(".srch button", "margin-left: 5px; font-size: 13px; padding: 2px 6px;");
add(".srch .opts, .srch .tpl", "margin-left: 8px; font-size: 11px; color: #00c;");
add(".star", "background: url(" + (era === "dl10" ? A.sprite_doclist2011 : A.sprite_doclist2008) + ") no-repeat -304px 0; cursor: pointer;");
add(".star.on", "background-position: -240px 0;");
add(".nav .ni, .nav .grp, .nav .in", "padding: 3px 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;");
add(".nav .ni.sel", "font-weight: bold;");
add(".nav .in", "padding-left: 22px;");
add(".nav .in.none", "color: #777;");
add(".nav .grp", "margin-top: 8px; color: #000;");
add(".quota", "margin-top: auto; padding: 10px 6px; color: #666; font-size: 11px;");
add(".mhead", "font-size: 14px; padding: 5px 8px;");
add(".mhead .cr[data-go], .mhead .cr[data-folder]", "color: #00c; text-decoration: underline;");
}
if (era === "dl07") {
add(".hdr .logo img", "height: 55px;");
add(".bar", "display: flex; gap: 22px; align-items: center; margin: 0 10px; height: 33px; padding: 0 12px; background: linear-gradient(#78aee4, #4a8bd0); color: #fff; font-size: 14px; border-radius: 4px 4px 0 0; flex: 0 0 auto;");
add(".bar > span, .bar .tool span", "color: #fff; cursor: pointer;");
add(".bar .tool", "display: flex; gap: 22px;");
add(".bar .dd.open", "text-decoration: underline;");
add(".body", "margin: 0 10px; border: 1px solid #a9c4e8; border-top: 0;");
add(".side", "width: 210px; background: #fff; border-right: 3px solid #c3d9ff; padding: 4px 0; font-size: 13px;");
add(".nav .ni, .nav .grp", "padding: 3px 10px;");
add(".nav .in", "padding-left: 30px;");
add(".nav .ni.sel", "background: #c3d9ff;");
add("table.list thead th", "background: #e8eef7; border-bottom: 1px solid #c3d9ff; height: 24px; font-weight: bold; color: #333; padding: 0 4px;");
add("table.list td", "height: 23px; border-bottom: 1px solid #eee; padding: 0 4px;");
add("table.list td.nm a", "color: #000; font-weight: bold;");
add("table.list td.fs, table.list td.dt", "color: #666;");
add("tr.hl td", "background: #ffc;");
add(".foot", "display: flex; justify-content: space-between; margin: 0 10px 6px; padding: 4px 8px; background: #e8eef7; font-size: 13px; flex: 0 0 auto;");
add(".foot a", "color: #00c;");
}
if (era === "dl09" || era === "dl10") {
add(".side", "width: " + (era === "dl09" ? "190" : "200") + "px; padding: 0 0 0 8px; font-size: 13px;");
add(".btns", "display: flex; gap: 6px; margin: 2px 0 10px;");
add(".gbtn", era === "dl09" ? "display: inline-block; padding: 2px 8px; border: 1px solid; border-color: #bbb #999 #999 #bbb; border-radius: 2px; background: linear-gradient(#fff, #ddd); color: #000; font-size: 13px; white-space: nowrap;"
: "display: inline-block; padding: 3px 8px; border: 1px solid #bbb; border-radius: 2px; background: linear-gradient(#f9f9f9, #eee 60%, #e3e3e3); color: #222; font: bold 13px Arial, sans-serif; white-space: nowrap;");
add(".gbtn:hover, .gbtn.open", "border-color: #888;");
add(".nav .ni.sel", "background: " + (era === "dl09" ? "#c3d9ff" : "#e0ecff") + ";");
add(".main", era === "dl09" ? "margin: 0 8px; border: 1px solid #c3d9ff;" : "margin: 0 8px 0 4px;");
add(".mhead", era === "dl09" ? "background: #c3d9ff;" : "font-size: 18px; padding: 2px 4px 6px;");
add(".acts", "display: flex; gap: 4px; padding: 5px 6px; " + (era === "dl09" ? "background: #e8eef7; border-bottom: 1px solid #c3d9ff;" : "background: #c3d9ff;"));
add("table.list thead th", "height: 24px; color: #666; font-size: 12px; padding: 0 4px; border-bottom: 1px solid #ddd;");
add("table.list td", "height: 24px; border-bottom: 1px solid #eee; padding: 0 4px;");
add("table.list td.nm a", "color: #000;");
add("table.list td.fs, table.list td.ow, table.list td.dt", "color: #666; font-size: 12px;");
add("tr.hl td", "background: " + (era === "dl09" ? "#e8eef7" : "#ffc") + ";");
}
if (era === "dl10") {
add(".hdr .logo.g10", "display: flex; align-items: flex-end; text-decoration: none;");
add(".hdr .logo.g10 img", "height: 40px; width: auto;");
add(".hdr .logo.g10 .dw", "font: 26px Arial, sans-serif; color: #3a66cc; margin: 0 0 3px 3px; line-height: 1;");
}
// ---- Kennedy: the Docs list of late 2011 and the first Drive
if (kennedy) {
add(".khead", "display: flex; align-items: center; height: 72px; padding: 0 16px 0 20px; background: #f1f1f1; border-bottom: 1px solid #e5e5e5; flex: 0 0 auto;");
add(".glogo img", "display: block; width: 117px; height: 44px;");
add(".ksrch", "margin-left: 78px;");
add(".ksrch input", "width: 460px; max-width: 40vw; height: 29px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 0 8px; font-size: 13px; background: #fff; outline: none;");
add(".ksrch input:focus", "border-color: #4d90fe;");
add(".kbtn", "display: inline-flex; align-items: center; justify-content: center; height: 29px; min-width: 54px; padding: 0 8px; margin-right: 8px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px Arial, sans-serif; cursor: default; white-space: nowrap;");
add(".kbtn:hover, .kbtn.open", "border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); color: #222;");
add(".kbtn.ico", "min-width: 42px;");
add(".kbtn.ico svg", "fill: #666;");
add(".kbtn.blue", "background: linear-gradient(#4d90fe, #4787ed); border-color: #3079ed; color: #fff; margin: 0 0 0 8px; width: 72px;");
add(".kbtn.blue svg", "fill: #fff;");
add(".kbtn.red", "background: linear-gradient(#dd4b39, #d14836); border-color: #c6322a; color: #fff; min-width: 0; padding: 0 12px;");
add(".kbtn.red svg", "fill: #fff; transform: rotate(180deg);");
add(".kbtn.red.up", "padding: 0 6px; margin-right: 0;");
add(".ktool", "display: flex; align-items: center; height: 57px; padding: 0 16px 0 0; border-bottom: 1px solid #ebebeb; flex: 0 0 auto;");
add(".ktool .app", "width: 214px; flex: 0 0 214px; padding-left: 20px; font-size: 20px; color: #dd4b39;");
add(".ktool .crumb", "font-size: 18px; color: #222; margin-right: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40%;");
add(".ktool .crumb .cr[data-go], .ktool .crumb .cr[data-folder]", "color: #666;");
add(".ktool .crumb .cr[data-go]:hover, .ktool .crumb .cr[data-folder]:hover", "text-decoration: underline;");
add(".ktool .tool", "display: flex;");
add(".side", "width: 214px; padding: 16px 0 0 0;");
add(".btns", "display: flex; padding-left: 20px; margin-bottom: 16px;");
add(".nav .ni", "padding: 0 8px 0 20px; line-height: 24px; color: #222; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;");
add(".nav .ni:hover", "background: #eee;");
add(".nav .ni.sel", "color: #dd4b39; font-weight: bold;");
add(".nav .ni.sub", "padding-left: 36px; font-weight: normal; color: #222;");
add(".nav .ni.sub.open", "font-weight: bold;");
add(".nav .grp", "padding-left: " + (era === "dl11" ? "8px" : "20px") + "; margin-top: 8px; line-height: 24px; color: #222;");
add(".nav .in", "padding: 0 8px 0 28px; line-height: 24px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;");
add(".nav .in.none", "color: #999;");
add(".nav .in.sel", "color: #dd4b39; font-weight: bold;");
add(".quota", "margin-top: auto; padding: 16px 20px; color: #666; font-size: 11px;");
add(".quota a", "color: #15c; text-decoration: none;");
add(".main", "padding: 0 16px 0 0;");
add("table.list thead th", "height: 34px; color: #666; font-size: 13px; padding: 0 4px; border-bottom: 1px solid #ebebeb;" + (era === "dv12" ? " font-size: 11px; font-weight: bold;" : ""));
add("table.list thead th.on", "color: #dd4b39;");
add("table.list td", "height: " + (era === "dv12" ? "30" : "34") + "px; border-bottom: 1px solid #ebebeb; padding: 0 4px;");
add("table.list td.nm a", "color: #222;");
add("table.list td.nm a:hover", "text-decoration: underline;");
add("table.list td.ow, table.list td.dt", "color: #222;");
add(".star", "opacity: .35; background: url(" + A.sprite_jfk + ") no-repeat 0 -672px; width: 21px; height: 21px; cursor: pointer;");
add(".star.on", "opacity: 1; filter: sepia(1) saturate(8) hue-rotate(5deg);");
add("tr[data-id]:hover td", "background: #f5f5f5;");
add("tr.hl td, tr.hl:hover td", "background: #ffc;");
// the grid of the first Drive
add(".gview", "padding: 12px 0;");
add(".gsec", "font: bold 11px Arial, sans-serif; color: #666; padding: 8px 0;");
add(".gfold, .gfiles", "display: flex; flex-wrap: wrap; gap: 12px;");
add(".gf", "display: flex; align-items: center; gap: 6px; width: 190px; height: 34px; padding: 0 10px; border: 1px solid #ebebeb; white-space: nowrap; overflow: hidden;");
add(".gc", "width: 190px; border: 1px solid #ebebeb;");
add(".gc .th", "height: 130px; background: #f5f5f5; display: flex; align-items: center; justify-content: center; overflow: hidden;");
add(".gc .th img", "max-width: 100%;");
add(".gc .th img.fb", "width: 32px; height: 32px;");
add(".gc .ft", "display: flex; align-items: center; padding: 6px 8px; white-space: nowrap; overflow: hidden;");
add(".gf.on, .gc.on", "background: #ffc; border-color: #f0c36d;");
add(".n", "overflow: hidden; text-overflow: ellipsis;");
}
// ---- Drive from June 2014
if (material) {
const sel = gm ? "#e8f0fe" : "#e3edfd";
const selText = gm ? "#1967d2" : "#202124";
add(".ib", "display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; color: #5f6368; border-radius: " + (gm ? "50%" : "0") + ";");
add(".ib:hover, .ib.open", "background: rgba(60,64,67,.08);");
add(".side", "width: " + (gm ? "256px" : "240px") + "; padding: " + (gm ? "8px 0" : "16px 0") + ";");
add(".btns", "padding: " + (gm ? "8px 0 16px 8px" : "0 16px 20px 24px") + ";");
add(".nbtn", gm ? "display: inline-flex; align-items: center; gap: 12px; height: 48px; padding: 0 24px 0 12px; border-radius: 24px; background: #fff; color: #3c4043; font: 500 14px 'Google Sans', Roboto, sans-serif; box-shadow: 0 1px 2px 0 rgba(60,64,67,.3), 0 1px 3px 1px rgba(60,64,67,.15);"
: "display: inline-flex; align-items: center; justify-content: center; height: 36px; min-width: 96px; padding: 0 16px; border-radius: 2px; background: " + (era === "dv14" ? "#4285f4" : "#2196f3") + "; color: #fff; font: 500 14px Roboto, sans-serif; letter-spacing: .5px; box-shadow: 0 2px 2px rgba(0,0,0,.24);");
add(".nbtn:hover, .nbtn.open", gm ? "background: #f8f9fa; box-shadow: 0 1px 3px 0 rgba(60,64,67,.3), 0 4px 8px 3px rgba(60,64,67,.15);" : "box-shadow: 0 4px 8px rgba(0,0,0,.28);");
add(".nbtn .mi svg", "width: 36px; height: 36px; fill: #1a73e8;");
add(".nav .ni", "display: flex; align-items: center; gap: " + (gm ? "18px" : "20px") + "; height: " + (gm ? "40px" : "40px") + "; padding: 0 16px 0 24px; color: #202124; font-size: 14px; white-space: nowrap; overflow: hidden;" +
(gm ? " border-radius: 0 20px 20px 0; margin-right: 12px;" : ""));
add(".nav .ni .mi", "color: #5f6368;");
add(".nav .ni:hover", "background: " + (gm ? "#f1f3f4" : "#f5f5f5") + ";");
add(".nav .ni.sel", "background: " + (gm ? sel : era === "dv14" ? "#eee" : "#eee") + "; color: " + (gm ? selText : era === "dv14" ? "#4285f4" : "#212121") + "; font-weight: " + (gm ? "500" : era === "dv17" ? "500" : "normal") + ";");
add(".nav .ni.sel .mi", gm ? "color: #1967d2;" : era === "dv14" ? "color: #4285f4;" : "");
add(".nav .tree", "margin: 0 0 4px;");
add(".nav .ni.sub", "height: 32px; padding-left: 52px; font-size: 13px; gap: 12px;");
add(".nav .ni.sub.open", "font-weight: 500;");
add(".quota", "margin-top: auto; padding: 16px 24px; color: #5f6368; font-size: 13px; border-top: 1px solid " + (gm ? "#dadce0" : "#e0e0e0") + ";");
add(".qbar", "height: 4px; background: #e0e0e0; margin-bottom: 8px;" + (gm ? " border-radius: 2px; overflow: hidden;" : ""));
add(".qbar i", "display: block; height: 100%; background: " + (gm ? "#1a73e8" : "#4285f4") + "; width: 0;");
add(".qup", "display: inline-block; margin-top: 10px; color: " + (gm ? "#1a73e8" : "#4285f4") + "; text-decoration: none; font-weight: 500;" + (gm ? " border: 1px solid #dadce0; border-radius: 4px; padding: 8px 16px;" : ""));
add(".dbar", "display: flex; align-items: center; flex: 0 0 auto; height: " + (era === "dv14" ? "56px" : "56px") + "; padding: 0 16px 0 0; border-bottom: 1px solid " + (gm ? "#dadce0" : "#e0e0e0") + ";");
add(".dbar .app", "width: 240px; flex: 0 0 240px; padding-left: 24px; font: 20px " + f + "; color: #666;");
add(".crumb", "display: flex; align-items: center; min-width: 0; white-space: nowrap; overflow: hidden; font: " + (gm ? "400 18px 'Google Sans', Roboto" : "18px Roboto") + ", sans-serif; color: #5f6368;");
add(".crumb .cr", "display: inline-flex; align-items: center; padding: 4px 8px; overflow: hidden; text-overflow: ellipsis;" + (gm ? " border-radius: 4px;" : ""));
add(".crumb .cr:hover", "background: rgba(60,64,67,.08);");
add(".crumb .cr.last", "color: #202124;");
add(".crumb .sep", "display: inline-flex; color: #5f6368;");
add(".tool", "display: flex; align-items: center;");
add(".main", "background: #fff;");
add(".list", "padding: 0 " + (gm ? "16px" : "24px") + " 80px 0;");
// the list
add(".lhead, .lrow", "display: flex; align-items: center; height: 48px; border-bottom: 1px solid " + (gm ? "#dadce0" : "#e0e0e0") + "; font-size: 13px; color: #202124; cursor: default;");
add(".lhead", "height: 48px; color: #5f6368; font-weight: 500; position: sticky; top: 0; background: #fff; z-index: 1;");
add(".lhead .mi svg", "width: 16px; height: 16px;");
add(".lhead .c", "display: flex; align-items: center; gap: 4px;");
add(".c", "white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 12px;");
add(".c.nm", "flex: 1; min-width: 0; display: flex; align-items: center; padding-left: 16px; font-weight: 500;");
add(".lhead .c.nm", "padding-left: 16px;");
add(".c.nm .fi", "margin-right: 16px;");
add(".c.nm .n", "overflow: hidden; text-overflow: ellipsis;");
add(".c.ow", "width: 150px; color: #5f6368;");
add(".c.dt", "width: 170px; color: #5f6368;");
add(".c.sz", "width: 100px; color: #5f6368;");
add(".shr", "display: inline-flex; color: #5f6368; margin-left: 8px; flex: 0 0 auto;");
add(".lrow:hover", "background: " + (gm ? "#f1f3f4" : "#f5f5f5") + ";");
add(".lrow.on", "background: " + sel + "; color: " + selText + ";");
add(".lrow.on .c", gm ? "color: #1967d2;" : "");
// the grid
add(".gview", "padding: 8px 0 0 0;");
add(".gsec", "font-size: 14px; font-weight: 500; color: #202124; padding: 16px 0 12px;");
add(".gfold", "display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px;");
add(".gf", "display: flex; align-items: center; gap: 16px; height: 48px; padding: 0 16px; color: #202124; font-weight: 500; white-space: nowrap; overflow: hidden; " +
(gm ? "border: 1px solid #dadce0; border-radius: 8px;" : "box-shadow: 0 1px 2px rgba(0,0,0,.2);"));
add(".gf .mi", "color: #5f6368;");
add(".gfiles", "display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px;");
add(".gc", "display: flex; flex-direction: column; height: 200px; overflow: hidden; " + (gm ? "border: 1px solid #dadce0; border-radius: 8px;" : "box-shadow: 0 1px 2px rgba(0,0,0,.2);"));
add(".gc .th", "flex: 1; min-height: 0; background: #f1f3f4; display: flex; align-items: center; justify-content: center; overflow: hidden;");
add(".gc .th img", "width: 100%; height: 100%; object-fit: cover; object-position: top;");
add(".gc .th img.fb", "width: 48px; height: 48px; object-fit: contain;");
add(".gc .ft", "display: flex; align-items: center; height: 48px; padding: 0 16px; font-weight: 500; color: #202124; white-space: nowrap; overflow: hidden; border-top: 1px solid " + (gm ? "#dadce0" : "#e0e0e0") + ";");
add(".gc .ft .fi", "margin-right: 12px;");
add(".n", "overflow: hidden; text-overflow: ellipsis;");
add(".gf.on, .gc.on", "background: " + sel + "; color: " + selText + ";" + (gm ? " border-color: " + sel + ";" : " box-shadow: 0 0 0 2px #4285f4;"));
add(".empty", "padding: 60px 24px; text-align: center; color: #5f6368; font-size: 16px;");
}
if (era === "dv14") {
add(".gtop", "display: flex; align-items: center; height: 60px; padding: 0 16px 0 24px; background: #f1f1f1; border-bottom: 1px solid #e5e5e5; flex: 0 0 auto;");
add(".gtop .glogo img", "display: block; height: 30px; width: auto;");
add(".gsrch", "margin-left: 40px; flex: 0 1 560px; display: flex;");
add(".gsrch input", "flex: 1; height: 29px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; border-right: 0; padding: 0 8px; font: 16px Arial, sans-serif; outline: none; background: #fff; color: #222;");
add(".gsrch input:focus", "border-color: #4d90fe;");
add(".gsrch .gbtn", "width: 60px; height: 29px; border: 1px solid #3079ed; background: linear-gradient(#4d90fe, #4787ed); color: #fff; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; border-radius: 0 2px 2px 0;");
add(".gsrch .gbtn svg", "fill: #fff;");
add(".gtop .kcorner", "margin-left: auto;");
add(".dbar", "background: #fff;");
add(".dbar .crumb", "margin-left: 0;");
}
if (era === "dv17" || era === "dv19") {
add(".appbar", "display: flex; align-items: center; height: 64px; padding: 0 8px 0 " + (gm ? "8px" : "16px") + "; border-bottom: 1px solid " + (gm ? "#dadce0" : "#e0e0e0") + "; flex: 0 0 auto; background: #fff;");
add(".brand", "display: flex; align-items: center; gap: " + (gm ? "8px" : "12px") + "; width: " + (gm ? "238px" : "224px") + "; padding-left: " + (gm ? "8px" : "0") + "; text-decoration: none; color: #5f6368; font: 22px " + (gm ? "'Product Sans', 'Google Sans', Arial" : "Roboto, Arial") + ", sans-serif;");
add(".brand img", "width: 40px; height: 40px;");
add(".msrch", "position: relative; flex: 0 1 720px;");
add(".msrch input", "width: 100%; height: " + (gm ? "48px" : "46px") + "; border: 0; border-radius: " + (gm ? "8px" : "2px") + "; padding: 0 16px 0 60px; font: 16px " + f + "; outline: none; background: " + (gm ? "#f1f3f4" : "#f1f1f1") + "; color: #202124;");
add(".msrch input:focus", "background: #fff; box-shadow: 0 1px 1px 0 rgba(65,69,73,.3), 0 1px 3px 1px rgba(65,69,73,.15);");
add(".msrch .sic", "position: absolute; left: 6px; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border: 0; background: none; color: #5f6368; cursor: pointer;" + (gm ? " border-radius: 50%;" : ""));
add(".appbar .corner", "display: flex; align-items: center; margin-left: 4px;");
add(".main .dbar", "padding-left: 8px;");
}
return c;
}
// ---- Drive: a file's own page (drive.google.com/file/d/.../view) ------------------------
// PDFs (and pictures) are shown in the viewer of the period: the file is downloaded the
// way Download does it, and drawn page by page with PDF.js. Anything else, or anything
// that cannot be read, is left to Google's page.
function ugfDvFileId() {
const m = (window.location.pathname || "").match(/^\/file(?:\/u\/\d+)?\/d\/([\w-]{10,})\/(view|edit)\b/);
return m ? m[1] : "";
}
function ugfDvViewerGiveUp(why) {
console.log("[Gplex] Drive viewer: left to Google (" + why + ")");
const veil = document.getElementById("ugf-dv-veil");
if (veil) {
veil.remove();
}
const v = document.getElementById("ugf-dvv");
if (v) {
v.remove();
}
document.documentElement.removeAttribute("gplex-dvv");
}
// the file's bytes, as Download gives them (on to Google's download host if need be)
function ugfDvFetchFile(id, onDone) {
const q = new URLSearchParams(window.location.search);
const rk = q.get("resourcekey");
const au = q.get("authuser") || ((window.location.pathname || "").match(/\/u\/(\d+)\//) || [])[1] || "0";
const url = "https://drive.google.com/uc?id=" + encodeURIComponent(id) + "&export=download&authuser=" + au + (rk ? "&resourcekey=" + encodeURIComponent(rk) : "");
const okType = function(ct) {
return !ct || /pdf|image\/|octet-stream|binary/i.test(ct);
};
if (typeof GM_xmlhttpRequest === "function") {
let aborted = false;
const req = GM_xmlhttpRequest({
method: "GET", url: url, responseType: "arraybuffer", timeout: 120000,
onreadystatechange: function(r) {
if (r.readyState === 2 && !aborted) {
const h = String(r.responseHeaders || "");
const ct = (h.match(/content-type:\s*([^\r\n;]+)/i) || [])[1] || "";
const len = +((h.match(/content-length:\s*(\d+)/i) || [])[1] || 0);
if (!okType(ct) || len > 200 * 1024 * 1024) {
aborted = true;
try {
req.abort();
} catch (e) {}
onDone(null, !okType(ct) ? "type " + ct : "too large");
}
}
},
onload: function(r) {
if (!aborted) {
onDone(r.status < 400 ? r.response : null, "status " + r.status);
}
},
onerror: function() {
if (!aborted) {
onDone(null, "network");
}
},
ontimeout: function() {
if (!aborted) {
onDone(null, "timeout");
}
}
});
return;
}
fetch(url, { credentials: "include" }).then(function(r) {
return r.ok && okType(r.headers.get("content-type")) ? r.arrayBuffer() : null;
}).then(function(b) {
onDone(b, "fetch");
}, function() {
onDone(null, "fetch failed");
});
}
function ugfDvSniff(buf) {
const b = new Uint8Array(buf, 0, Math.min(16, buf.byteLength));
const s = String.fromCharCode.apply(null, b);
if (s.indexOf("%PDF-") > -1 || String.fromCharCode.apply(null, new Uint8Array(buf, 0, Math.min(1024, buf.byteLength))).indexOf("%PDF-") > -1) {
return "pdf";
}
if (b[0] === 0x89 && s.slice(1, 4) === "PNG") {
return "image/png";
}
if (b[0] === 0xff && b[1] === 0xd8) {
return "image/jpeg";
}
if (s.slice(0, 3) === "GIF") {
return "image/gif";
}
if (s.slice(0, 4) === "RIFF" && s.slice(8, 12) === "WEBP") {
return "image/webp";
}
return "";
}
function ugfDvViewer(era) {
const id = ugfDvFileId();
const A = ugfDocsArt();
const esc = ugfDocsEsc;
const ic = ugfFeIcon;
const l = String(layout || "");
const kennedy = era === "dl11";
const dark = era === "dv12" || era === "dv14" || era === "dv17" || era === "dv19";
const gm = era === "dv19";
const classic = era === "dl07" || era === "dl09" || era === "dl10";
const html = document.documentElement;
const nameNow = function() {
return String(document.title || "").replace(/\s*-\s*Google Drive\s*$/, "").trim() || "Untitled";
};
html.setAttribute("gplex-dvv", era);
const style = document.createElement("style");
style.id = "ugf-dvv-styles";
style.textContent = ugfDvViewerCss(era, A).join("\n");
(document.head || document.documentElement).appendChild(style);
const box = document.createElement("div");
box.id = "ugf-dvv";
box.setAttribute("era", era);
box.setAttribute("tabindex", "-1");
document.body.appendChild(box);
const veil = document.getElementById("ugf-dv-veil");
if (veil) {
veil.remove();
}
const fav = { dl07: A.fav2007, dl09: A.fav2008, dl10: A.fav2010, dl11: A.fav2011, dv12: A.dvFav2012, dv14: A.dvFav2014, dv17: A.dvFav2017, dv19: l === "2022" ? A.dvFav2020 : A.dvFav2017 }[era];
ugfApplyFavicon(fav);
ugfKeepFavicon(function() {
return fav;
});
const st = { name: nameNow(), kind: "", bytes: null, pdf: null, pages: [], zoom: 0, fit: 1, cur: 1 };
const back = ugfDvBase() + "/my-drive";
const kindIcon = function() {
const k = st.kind === "pdf" ? "pdf" : "image";
return ' ';
};
// ---- the frame of the period
const draw = function() {
let h = "";
const pageBox = '' + (classic ? "Page " : "") + ' ' + (classic ? "of" : "/") + ' ? ';
if (classic) {
h = '' +
'';
} else if (kennedy) {
h = '' + kindIcon() + "" + esc(st.name) + "
" +
'
− + ' + pageBox +
'
Print Download ';
} else if (era === "dv12") {
h = '× ' + kindIcon() + "" + esc(st.name) + "
" +
'
Open ' + ic("print", 18) + ' ' + ic("file_download", 18) + " ";
} else {
h = '";
}
h += '';
if (dark) {
h += '' + ic("remove", 20) + ' ' + ic("zoom_in", 20) + ' ' +
ic("add", 20) + '
' + pageBox + "
";
}
box.innerHTML = trusted_policy.createHTML(h);
// Google's own "Open with Google Docs" stays usable, from here
setTimeout(function() {
const o = ugfDvButton(document, /^Open with Google Docs$/i);
const mine = box.querySelector(".vopen");
if (o && mine) {
mine.hidden = false;
mine.addEventListener("click", function() {
ugfDvPress(o);
});
}
}, 1500);
};
const msg = function(t) {
const p = box.querySelector(".vpages");
if (p) {
p.innerHTML = trusted_policy.createHTML('' + esc(t) + "
");
}
};
// ---- drawing the pages
const scroller = function() {
return box.querySelector(".vbody");
};
const scaleNow = function() {
return st.fit * (st.zoom ? Math.pow(1.25, st.zoom) : 1);
};
let io = null;
const renderPage = function(pg) {
if (pg.done === scaleNow() || pg.busy) {
return;
}
pg.busy = true;
const sc = scaleNow();
const dpr = Math.min(3, window.devicePixelRatio || 1);
st.pdf.getPage(pg.n).then(function(page) {
const vp = page.getViewport({ scale: sc * dpr });
const c = document.createElement("canvas");
c.width = Math.floor(vp.width);
c.height = Math.floor(vp.height);
c.style.width = Math.floor(vp.width / dpr) + "px";
c.style.height = Math.floor(vp.height / dpr) + "px";
return page.render({ canvasContext: c.getContext("2d"), viewport: vp }).promise.then(function() {
pg.el.innerHTML = ugfTT("");
pg.el.appendChild(c);
pg.done = sc;
pg.busy = false;
if (pg.done !== scaleNow()) {
renderPage(pg);
}
});
}).catch(function(e) {
pg.busy = false;
console.log("[Gplex] Drive viewer: page " + pg.n + ": " + e);
});
};
const layoutPages = function() {
const sc = scaleNow();
st.pages.forEach(function(pg) {
pg.el.style.width = Math.floor(pg.w * sc) + "px";
pg.el.style.height = Math.floor(pg.h * sc) + "px";
});
if (io) {
io.disconnect();
st.pages.forEach(function(pg) {
io.observe(pg.el);
});
}
};
const showPdf = function() {
const lib = typeof pdfjsLib !== "undefined" ? pdfjsLib : (globalThis["pdfjs-dist/build/pdf"] || null);
if (!lib) {
ugfDvViewerGiveUp("PDF.js is not loaded");
return;
}
lib.getDocument({ data: new Uint8Array(st.bytes.slice(0)), isEvalSupported: false }).promise.then(function(pdf) {
st.pdf = pdf;
const wrap = box.querySelector(".vpages");
wrap.innerHTML = ugfTT("");
box.querySelectorAll(".vpt").forEach(function(e) {
e.textContent = pdf.numPages;
});
const jobs = [];
for (let n = 1; n <= pdf.numPages; n++) {
jobs.push(n);
}
// every page's size first (from page 1 for the rest, then corrected)
return pdf.getPage(1).then(function(p1) {
const v1 = p1.getViewport({ scale: 1 });
const avail = Math.max(300, scroller().clientWidth - (dark ? 160 : 60));
st.fit = Math.min(1.25, avail / v1.width);
jobs.forEach(function(n) {
const el = document.createElement("div");
el.className = "vpg";
el.setAttribute("data-n", n);
wrap.appendChild(el);
st.pages.push({ n: n, el: el, w: v1.width, h: v1.height, done: 0 });
});
io = new IntersectionObserver(function(ents) {
ents.forEach(function(en) {
if (en.isIntersecting) {
const pg = st.pages[+en.target.getAttribute("data-n") - 1];
if (pg) {
renderPage(pg);
}
}
});
}, { root: scroller(), rootMargin: "600px 0px" });
layoutPages();
// the true size of each page, as it comes
jobs.slice(1).forEach(function(n) {
pdf.getPage(n).then(function(pp) {
const v = pp.getViewport({ scale: 1 });
const pg = st.pages[n - 1];
if (v.width !== pg.w || v.height !== pg.h) {
pg.w = v.width;
pg.h = v.height;
pg.done = 0;
layoutPages();
}
});
});
});
}).catch(function(e) {
console.log("[Gplex] Drive viewer: " + e);
ugfDvViewerGiveUp("PDF.js could not read it");
});
};
const showImage = function(type) {
const url = URL.createObjectURL(new Blob([st.bytes], { type: type }));
const wrap = box.querySelector(".vpages");
wrap.innerHTML = trusted_policy.createHTML(' ');
const img = wrap.querySelector("img");
img.onload = function() {
st.pages = [{ n: 1, el: wrap.querySelector(".vpg"), w: img.naturalWidth, h: img.naturalHeight, img: true }];
st.fit = Math.min(1, Math.max(300, scroller().clientWidth - 160) / img.naturalWidth, Math.max(200, scroller().clientHeight - 80) / img.naturalHeight);
layoutImg();
};
img.src = url;
box.querySelectorAll(".vpt").forEach(function(e) {
e.textContent = "1";
});
};
const layoutImg = function() {
const pg = st.pages[0];
if (!pg) {
return;
}
const sc = scaleNow();
const img = pg.el.querySelector("img");
img.style.width = Math.floor(pg.w * sc) + "px";
img.style.height = Math.floor(pg.h * sc) + "px";
};
const zoom = function(d) {
st.zoom = Math.max(-4, Math.min(6, st.zoom + d));
if (st.kind === "pdf") {
layoutPages();
} else {
layoutImg();
}
};
// ---- the buttons
const download = function() {
if (!st.bytes) {
return;
}
const a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([st.bytes], { type: st.kind === "pdf" ? "application/pdf" : st.kind }));
a.download = st.name;
document.body.appendChild(a);
a.click();
setTimeout(function() {
a.remove();
}, 1000);
};
const print = function() {
// every page drawn first, then the browser's own printing of just the pages
if (st.kind === "pdf") {
const waitAll = function(tries) {
const todo = st.pages.filter(function(pg) {
return pg.done !== scaleNow();
});
todo.slice(0, 4).forEach(renderPage);
if (todo.length && tries < 600) {
setTimeout(function() {
waitAll(tries + 1);
}, 100);
} else {
window.print();
}
};
waitAll(0);
} else {
window.print();
}
};
box.addEventListener("click", function(ev) {
const t = ev.target;
const z = t.closest("[data-z]");
if (z) {
ev.preventDefault();
zoom(+z.getAttribute("data-z"));
return;
}
if (t.closest(".zi")) {
st.zoom = 0;
zoom(0);
return;
}
if (t.closest(".vdl")) {
ev.preventDefault();
download();
return;
}
if (t.closest(".vprint")) {
ev.preventDefault();
print();
return;
}
const x = t.closest(".vx, .vback, .vlogo");
if (x && window.history.length > 1 && document.referrer && /^https:\/\/drive\.google\.com\//.test(document.referrer)) {
ev.preventDefault();
window.history.back();
}
});
box.addEventListener("keydown", function(ev) {
ev.stopPropagation();
if (ev.target.classList && ev.target.classList.contains("vpin")) {
if (ev.key === "Enter") {
const n = Math.max(1, Math.min(st.pages.length, parseInt(ev.target.value, 10) || 1));
const pg = st.pages[n - 1];
if (pg) {
pg.el.scrollIntoView({ block: "start" });
}
}
return;
}
if (ev.key === "+" || ev.key === "=") {
zoom(1);
} else if (ev.key === "-") {
zoom(-1);
}
});
box.addEventListener("scroll", function() {
const sc = scroller();
if (!sc || !st.pages.length) {
return;
}
const mid = sc.getBoundingClientRect().top + sc.clientHeight / 3;
let cur = 1;
st.pages.forEach(function(pg) {
if (pg.el.getBoundingClientRect().top <= mid) {
cur = pg.n;
}
});
if (cur !== st.cur) {
st.cur = cur;
box.querySelectorAll(".vpin").forEach(function(i) {
if (document.activeElement !== i) {
i.value = cur;
}
});
}
}, true);
draw();
box.focus();
// the name: Google's page names it in its title
let named = st.name;
setInterval(function() {
const n = nameNow();
if (n && n !== named && !/^Google Drive$/i.test(n)) {
named = n;
st.name = n;
box.querySelectorAll(".vname b, .vname span").forEach(function(e) {
e.textContent = n;
});
}
}, 1000);
ugfDvFetchFile(id, function(buf, why) {
if (!buf || !buf.byteLength) {
ugfDvViewerGiveUp("download: " + why);
return;
}
const k = ugfDvSniff(buf);
if (!k) {
ugfDvViewerGiveUp("not a PDF or picture");
return;
}
st.bytes = buf;
st.kind = k;
const fi = box.querySelector(".vfi");
if (fi) {
fi.src = ugfDvIcon(k === "pdf" ? "pdf" : "image", dark && era !== "dv12" ? "mt" : era);
}
msg("Loading...");
if (k === "pdf") {
showPdf();
} else {
showImage(k);
}
});
}
function ugfDvViewerCss(era, A) {
const V = "#ugf-dvv";
const c = [];
const add = function(sel, body) {
c.push(sel.split(",").map(function(s) {
return V + " " + s.trim();
}).join(", ") + " { " + body + " }");
};
const dark = era === "dv12" || era === "dv14" || era === "dv17" || era === "dv19";
const gm = era === "dv19";
const kennedy = era === "dl11";
const classic = !dark && !kennedy;
const f = gm ? "'Google Sans', Roboto, Arial, sans-serif" : (era === "dv14" || era === "dv17") ? "Roboto, Arial, sans-serif" : "Arial, sans-serif";
c.push("html[gplex-dvv], html[gplex-dvv] body { overflow: hidden !important; }");
c.push(V + " { position: fixed; inset: 0; z-index: 2147483000; display: flex; flex-direction: column; font: 13px " + f + "; text-align: left; outline: none; background: " +
(dark ? (era === "dv12" ? "#202020" : "#333") : classic ? "#ebebeb" : "#f1f1f1") + "; color: " + (dark ? "#fff" : "#222") + "; }");
c.push("@media print { html[gplex-dvv] body > *:not(#ugf-dvv) { display: none !important; } html[gplex-dvv], html[gplex-dvv] body { overflow: visible !important; background: #fff !important; } " +
V + " { position: static !important; display: block !important; background: #fff !important; } " + V + " .vtop, " + V + " .vtool, " + V + " .vzoom, " + V + " .vpageind { display: none !important; } " +
V + " .vbody { overflow: visible !important; padding: 0 !important; } " + V + " .vpg { box-shadow: none !important; margin: 0 auto !important; break-after: page; } }");
add("*", "box-sizing: border-box;");
add(".mi", "display: inline-flex; font-style: normal;");
add(".mi svg", "display: block; fill: currentColor;");
add(".sp", "flex: 1;");
add("[hidden]", "display: none !important;");
add(".vtop", "display: flex; align-items: center; gap: 10px; flex: 0 0 auto;");
add(".vname", "display: flex; align-items: center; gap: 8px; min-width: 0; white-space: nowrap; overflow: hidden;");
add(".vname b, .vname span", "overflow: hidden; text-overflow: ellipsis;");
add(".vfi", "width: 16px; height: 16px; flex: 0 0 16px;");
add(".vbody", "flex: 1; overflow: auto; min-height: 0; position: relative; padding: " + (dark ? "24px 0 90px" : "16px 0 40px") + ";");
add(".vpages", "display: flex; flex-direction: column; align-items: center; gap: " + (dark ? "16px" : "12px") + ";");
add(".vpg", "background: #fff; flex: 0 0 auto; " + (dark ? "box-shadow: 0 2px 8px rgba(0,0,0,.5);" : "border: 1px solid #c6c6c6; box-shadow: 0 1px 3px rgba(0,0,0,.2);"));
add(".vpg canvas", "display: block;");
add(".vpg.vimg", "background: transparent; border: 0; box-shadow: none;");
add(".vpg.vimg img", "display: block; box-shadow: 0 2px 8px rgba(0,0,0,.4);");
add(".vmsg", "padding: 60px 0; color: " + (dark ? "#ccc" : "#666") + "; font-size: 14px;");
add(".vpin", "width: 36px; text-align: center; font: inherit; padding: 1px 2px; " + (dark ? "background: rgba(0,0,0,.4); color: #fff; border: 1px solid #777;" : "border: 1px solid #bbb;"));
add(".vpgn", "display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;");
if (classic) {
add(".vtop", "height: 50px; padding: 0 12px; background: #fff; border-bottom: 1px solid #c9d7f1;");
add(".vlogo img", "display: block; height: " + (era === "dl07" ? "40px" : "auto") + ";");
add(".vname", "font-size: 16px; margin-left: 10px;");
add(".vdl, .vprint, .vback", "color: #00c; text-decoration: underline; cursor: pointer; margin-left: 14px;");
add(".vtool", "display: flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px; background: #f0f0f0; border-bottom: 1px solid #ccc; flex: 0 0 auto;");
add(".vbtn", "display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 22px; border: 1px solid; border-color: #ccc #999 #999 #ccc; background: linear-gradient(#fff, #e3e3e3); font: bold 14px Arial, sans-serif; cursor: pointer; user-select: none;");
add(".vsep", "width: 1px; height: 18px; background: #ccc; margin: 0 6px;");
}
if (kennedy) {
add(".vtop", "height: 64px; padding: 0 16px 0 20px; background: #f1f1f1; border-bottom: 1px solid #e5e5e5;");
add(".vlogo img", "display: block; width: 95px; height: auto;");
add(".vname", "font-size: 18px; color: #222; margin-left: 24px;");
add(".kbtn", "display: inline-flex; align-items: center; justify-content: center; height: 29px; min-width: 32px; padding: 0 10px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px Arial, sans-serif; cursor: default; user-select: none;");
add(".kbtn:hover", "border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1);");
add(".kbtn.blue", "background: linear-gradient(#4d90fe, #4787ed); border-color: #3079ed; color: #fff;");
add(".vpgn", "margin: 0 8px; color: #444;");
}
if (era === "dv12") {
add(".vtop", "height: 56px; padding: 0 16px; background: #000; border-bottom: 1px solid #333; font: 16px Arial, sans-serif;");
add(".vx", "color: #ccc; text-decoration: none; font-size: 26px; line-height: 1; padding: 0 6px;");
add(".vname", "color: #fff;");
add(".dbtn", "display: inline-flex; align-items: center; justify-content: center; height: 29px; min-width: 34px; padding: 0 10px; border: 1px solid #555; border-radius: 2px; background: linear-gradient(#4a4a4a, #3a3a3a); color: #eee; font: bold 11px Arial, sans-serif; cursor: default; user-select: none;");
add(".dbtn:hover", "border-color: #888;");
add(".dbtn svg", "fill: #eee;");
}
if (era === "dv14" || era === "dv17" || gm) {
add(".vtop", "height: 64px; padding: 0 12px; background: linear-gradient(rgba(0,0,0,.65), rgba(0,0,0,.3)); font-size: 16px;");
add(".ib", "display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; color: #fff; text-decoration: none; cursor: pointer; border-radius: " + (gm ? "50%" : "0") + ";");
add(".ib:hover", "background: rgba(255,255,255,.12);");
add(".vname", "color: #fff; margin-left: 4px;");
add(".vfi", "background: #fff; padding: 2px; width: 20px; height: 20px; flex-basis: 20px;" + (gm ? " border-radius: 2px;" : ""));
add(".obtn", "display: inline-flex; align-items: center; height: 36px; padding: 0 16px; color: #fff; border: 1px solid rgba(255,255,255,.6); border-radius: " + (gm ? "4px" : "2px") + "; font: 500 14px " + f + "; cursor: pointer; white-space: nowrap;");
add(".obtn:hover", "background: rgba(255,255,255,.12);");
}
if (dark) {
add(".vzoom", "position: absolute; left: 50%; bottom: 24px; transform: translateX(-50%); display: flex; align-items: center; background: " + (era === "dv12" ? "#111" : "rgba(33,33,33,.9)") + "; " +
(gm ? "border-radius: 24px; padding: 0 6px;" : "border-radius: 0;") + " box-shadow: 0 2px 6px rgba(0,0,0,.4); z-index: 2;");
add(".zb", "display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 40px; color: #fff; cursor: pointer; user-select: none;" + (gm ? " border-radius: 50%;" : ""));
add(".zb:hover", "background: rgba(255,255,255,.12);");
add(".vpageind", "position: absolute; left: 24px; bottom: 30px; color: #ddd; font-size: 13px; background: rgba(33,33,33,.9); padding: 6px 10px;" + (gm ? " border-radius: 4px;" : "") + " z-index: 2;");
}
return c;
}
// ---- Gplex for Google Photos (5.6) ----------------------------------------------------
// Picasa Web Albums (2007-2011), Google+ Photos (late 2012-2014) and Google Photos of
// each period from 2015, drawn over Google's own Photos page, which keeps running
// underneath: the photos are read from it, and everything done is done by pressing
// Google's own controls (as Gplex's Drive does).
function ugfPhAu() {
return ((window.location.pathname || "").match(/^\/u\/(\d+)(\/|$)/) || ["", "0"])[1];
}
function ugfPhBase() {
const a = ugfPhAu();
return "https://photos.google.com" + (a !== "0" ? "/u/" + a : "");
}
// where in Photos we are
function ugfPhView() {
const p = (window.location.pathname || "/").replace(/^\/u\/\d+/, "") || "/";
let m;
if (p === "/" || /^\/photos\/?$/.test(p)) {
return { view: "library" };
}
if ((m = p.match(/^\/album\/([\w-]+)\/photo\/([\w-]+)/))) {
return { view: "photo", id: m[2], album: m[1] };
}
if ((m = p.match(/^\/(?:search\/[^/]+\/|share\/[\w-]+\/)?photo\/([\w-]+)/))) {
return { view: "photo", id: m[1] };
}
// a photo in the trash opens at /trash/
if ((m = p.match(/^\/trash\/([\w-]{20,})\/?$/))) {
return { view: "photo", id: m[1], trash: true };
}
if ((m = p.match(/^\/album\/([\w-]+)\/?$/))) {
return { view: "album", id: m[1] };
}
if (/^\/albums\/?$/.test(p)) {
return { view: "albums" };
}
if ((m = p.match(/^\/search\/([^/]+)\/?$/))) {
return { view: "search", token: m[1] };
}
if ((m = p.match(/^\/(archive|trash|sharing)\/?$/))) {
return { view: m[1] };
}
return { view: "" };
}
function ugfPhWanted() {
return window.location.host === "photos.google.com" && ugfNtTopFrame() && ugfNtOn("UGF_PHOTOS_ON") && ugfPhView().view !== "";
}
// which Photos a layout gets
// pw07 2007-2009: Picasa Web Albums under the blue links
// pw10 2010: Picasa Web Albums under the Google bar of 2010
// pw11 late 2011-2012: Picasa Web Albums under the black bar
// gp13 late 2012-2014: Google+ Photos
// ph15 2015-2016: Google Photos (May 2015)
// ph17 2017-2018: Google Photos with its places on the left
// ph19 2019 on: Google Material 2
function ugfPhEra() {
const l = String(layout || "2015");
if (l === "2019" || l === "2022") {
return "ph19";
}
if (l === "2017" || l === "2018" || l === "2018M") {
return "ph17";
}
if (["2015", "2015L", "2016", "2016C", "2016L"].indexOf(l) > -1) {
return "ph15";
}
if (l === "2013" || l === "2013L" || l === "2014") {
return "gp13";
}
if (l === "2011" || l === "2012") {
return "pw11";
}
if (l === "2010" || l === "2010N") {
return "pw10";
}
return "pw07";
}
// a picture's address without its size, and with the size wanted
function ugfPhStripSize(u) {
return String(u || "").replace(/[?#].*$/, "").replace(/=[^=/]*$/, "");
}
function ugfPhSized(base, spec) {
return base ? base + "=" + spec + "?authuser=" + ugfPhAu() : "";
}
// "Photo - Landscape - Sep 25, 2026, 8:04:44 PM": the kind, and the day and time
function ugfPhParseLabel(lbl) {
const s = String(lbl || "").replace(/ /g, " ");
const kind = /^Video\b/i.test(s) ? "video" : /^Animation\b/i.test(s) ? "animation" : "photo";
const d = s.match(/([A-Z][a-z]{2} \d{1,2}, \d{4})(?:, (\d{1,2}:\d{2}(?::\d{2})? ?[AP]M))?/);
return { kind: kind, day: d ? d[1] : "", time: d && d[2] ? d[2] : "", orient: (s.match(/ - (Landscape|Portrait|Square) - /) || [])[1] || "" };
}
function ugfPhBg(el) {
if (!el) {
return "";
}
const d = el.getAttribute("data-latest-bg");
if (d) {
return d;
}
const m = String(el.getAttribute("style") || "").match(/url\(["']?(?:")?([^"')&]+)/);
return m ? m[1] : "";
}
// ---- reading Google's page
function ugfPhHarvest() {
const photos = [];
const albums = [];
const seen = {};
document.querySelectorAll("a[href*='/photo/'], a[href*='/trash/']").forEach(function(a) {
if (a.closest("#ugf-photos") || !a.getClientRects().length) {
return;
}
const lbl = a.getAttribute("aria-label") || "";
if (!/^(Photo|Video|Animation|Screenshot|Image)\b/i.test(lbl) && !a.querySelector("[data-latest-bg]")) {
return;
}
const href = a.getAttribute("href") || "";
const m = href.match(/\/photo\/([\w-]+)/) || href.match(/\/trash\/([\w-]{20,})/);
if (!m || seen[m[1]]) {
return;
}
seen[m[1]] = true;
const bgEl = a.querySelector("[data-latest-bg]") || a.querySelector("[style*='background-image']");
const p = ugfPhParseLabel(lbl);
const box = a.parentElement;
photos.push({ id: m[1], href: href, base: ugfPhStripSize(ugfPhBg(bgEl)), kind: p.kind, day: p.day, time: p.time, orient: p.orient, label: lbl,
el: a, check: box ? box.querySelector("[role=checkbox]") : null });
});
const seenA = {};
document.querySelectorAll("a[href*='/album/']").forEach(function(a) {
if (a.closest("#ugf-photos") || !a.getClientRects().length || /\/photo\//.test(a.getAttribute("href") || "")) {
return;
}
const m = (a.getAttribute("href") || "").match(/\/album\/([\w-]+)/);
if (!m || seenA[m[1]]) {
return;
}
// the albums of the list (not the short list on the left)
const bgEl = a.querySelector("[style*='background-image']");
const bg = ugfPhBg(bgEl);
if (!a.hasAttribute("data-item-type") && !/=s(1\d\d|[2-9]\d\d)/.test(bg)) {
return;
}
seenA[m[1]] = true;
const t = a.querySelector("[dir=auto] span, [dir=auto]");
const txt = String(a.textContent || "").replace(/\s+/g, " ");
albums.push({ id: m[1], href: a.getAttribute("href"), base: ugfPhStripSize(bg), title: t ? String(t.textContent || "").trim() : "Untitled album",
count: (txt.match(/(\d[\d,]*) items?/) || ["", ""])[1], shared: a.getAttribute("data-is-shared") === "true", el: a });
});
return { photos: photos, albums: albums };
}
// the photo on show in Google's viewer
function ugfPhViewerMedia(id) {
let hit = null;
document.querySelectorAll("c-wiz[data-media-key][data-url]").forEach(function(c) {
if (c.closest("#ugf-photos")) {
return;
}
if (c.getAttribute("data-media-key") === id || (!hit && !id)) {
hit = c;
}
});
if (!hit) {
return null;
}
const img = hit.querySelector("img[aria-label]");
const p = ugfPhParseLabel(img ? img.getAttribute("aria-label") : "");
return { id: hit.getAttribute("data-media-key"), base: hit.getAttribute("data-url"), w: +hit.getAttribute("data-width") || 0, h: +hit.getAttribute("data-height") || 0,
kind: hit.querySelector("video") ? "video" : p.kind, day: p.day, time: p.time };
}
// one of Google's buttons on show, by its label (the last on show, which is the one
// of the view in front)
function ugfPhGoogleButton(re, within) {
let hit = null;
(within || document).querySelectorAll("button[aria-label], [role=button][aria-label], a[aria-label]").forEach(function(b) {
if (!b.closest("#ugf-photos") && re.test(b.getAttribute("aria-label")) && b.getClientRects().length && b.getAttribute("aria-disabled") !== "true") {
hit = b;
}
});
return hit;
}
// Google's places on the left (All photos, Albums, Favorites...), for their addresses
function ugfPhNavHref(re) {
let hit = "";
document.querySelectorAll("a[role=tab][aria-label], a[aria-label][href*='photos.google.com']").forEach(function(a) {
if (!hit && !a.closest("#ugf-photos") && re.test(a.getAttribute("aria-label"))) {
hit = a.getAttribute("href");
}
});
return hit;
}
// ---- Photos: starting, and the page ----------------------------------------------------
function ugfPhStart() {
if (window.location.host !== "photos.google.com" || !ugfNtTopFrame() || !ugfNtOn("UGF_PHOTOS_ON")) {
return;
}
if (ugfPhWanted()) {
ugfPhotosMain();
return;
}
const veil = document.getElementById("ugf-dv-veil");
if (veil) {
veil.remove();
}
const t = setInterval(function() {
if (ugfPhWanted()) {
clearInterval(t);
ugfPhotosMain();
}
}, 500);
}
function ugfPhotosMain() {
const era = ugfPhEra();
const A = ugfDocsArt();
// (the paper pinwheel until the new one of October 2020)
const fav = era.indexOf("pw") === 0 ? A.phPicasaFav : era === "gp13" ? A.phGplusFav : String(layout || "") === "2022" ? A.phFav : A.phFav2015;
console.log("[Gplex] Photos: layout " + layout + " (" + era + ")" + (UGF_VERSION ? " - Gplex " + UGF_VERSION : ""));
ugfApplyFavicon(fav);
ugfKeepFavicon(function() {
return fav;
});
ugfPhotosHome(era);
}
function ugfPhotosHome(era) {
const A = ugfDocsArt();
const esc = ugfDocsEsc;
const ic = ugfFeIcon;
const l = String(layout || "");
const who = ugfCalWho();
const signedIn = !!(who.email || who.name);
const pw = era.indexOf("pw") === 0;
const gp = era === "gp13";
const ph = era.indexOf("ph") === 0;
const gm = era === "ph19";
const html = document.documentElement;
html.setAttribute("gplex-ph", era);
const style = document.createElement("style");
style.id = "ugf-photos-styles";
style.textContent = ugfPhotosCss(era, A).join("\n");
(document.head || document.documentElement).appendChild(style);
const shell = document.createElement("div");
shell.id = "ugf-photos";
shell.setAttribute("era", era);
shell.setAttribute("tabindex", "-1");
document.body.appendChild(shell);
const veil = document.getElementById("ugf-dv-veil");
if (veil) {
veil.remove();
}
const state = { view: { view: "" }, photos: [], albums: [], sel: {}, key: "", bases: {}, favs: {}, info: false, loaded: false, lastGrid: "library" };
// ---- small helpers
const notice = function(text, stay) {
let n = shell.querySelector(".pnote");
if (!n) {
n = document.createElement("div");
n.className = "pnote";
shell.appendChild(n);
}
n.textContent = text;
n.hidden = false;
clearTimeout(notice.t);
if (!stay) {
notice.t = setTimeout(function() {
n.hidden = true;
}, 6000);
}
};
const plural = function(n, w) {
return n + " " + (n === 1 ? w : w + "s");
};
const W = pw ? { photos: "photos", album: "album", albums: "My Photos", lib: "Recent photos", fav: "Favorites" } :
gp ? { photos: "photos", album: "album", albums: "Albums", lib: "Photos", fav: "Favorites" } :
{ photos: "photos", album: "album", albums: "Albums", lib: "Photos", fav: "Favorites" };
const dayLabel = function(day) {
if (!day) {
return "";
}
const d = new Date(day);
if (isNaN(d)) {
return day;
}
const now = new Date();
const y = new Date(now);
y.setDate(now.getDate() - 1);
if (d.toDateString() === now.toDateString()) {
return ph ? "Today" : day;
}
if (d.toDateString() === y.toDateString()) {
return ph ? "Yesterday" : day;
}
if (ph) {
const wd = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][d.getDay()];
const mo = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][d.getMonth()];
return d.getFullYear() === now.getFullYear() ? wd + ", " + mo + " " + d.getDate() : mo + " " + d.getDate() + ", " + d.getFullYear();
}
return day;
};
// ---- going places (Google's own links on its left, so the page does not reload)
const hrefFor = function(v) {
const b = ugfPhBase();
if (v === "library") {
return b + "/";
}
if (v === "favorites") {
return ugfPhNavHref(/^Favorites$/) || b + "/search/Favorites";
}
return b + "/" + v;
};
const go = function(v) {
state.sel = {};
const re = { library: /^(All photos|Photos)$/, albums: /^Albums$/, favorites: /^Favorites$/, archive: /^Archive$/, trash: /^(Trash|Bin)$/, sharing: /^Sharing$/ }[v];
let a = null;
if (re) {
document.querySelectorAll("a[aria-label]").forEach(function(x) {
if (!a && !x.closest("#ugf-photos") && re.test(x.getAttribute("aria-label"))) {
a = x;
}
});
}
const url = hrefFor(v);
if (a) {
ugfDvPress(a);
setTimeout(function() {
if (ugfPhView().view === state.view.view && v !== state.view.view) {
window.location.href = url;
}
}, 2000);
} else {
window.location.href = url;
}
};
const openLink = function(el, href) {
const abs = /^https?:/.test(href) ? href : "https://photos.google.com" + (href.charAt(0) === "/" ? "" : "/") + href.replace(/^\.\//, "");
const before = window.location.pathname;
if (el && el.isConnected) {
ugfDvPress(el);
setTimeout(function() {
if (window.location.pathname === before) {
window.location.href = abs;
}
}, 1500);
} else {
window.location.href = abs;
}
};
const byId = function(id) {
let f = null;
state.photos.forEach(function(p) {
if (p.id === id) {
f = p;
}
});
return f;
};
// ---- the bars at the top, per period
const searchForm = function(cls, ph2, btn) {
return '";
};
const topLinks = function() {
const apps = [["Web", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Video", "https://www.youtube.com/"], ["News", "https://news.google.com/"],
["Maps", "https://www.google.com/maps"], ["Gmail", "https://mail.google.com/"], [ugfDocsLabel(), "https://docs.google.com/document/"], ["Photos", ""]];
return '";
};
const tabsFor = function() {
if (pw) {
return [[W.lib, "library"], [W.albums, "albums"], [W.fav, "favorites"]];
}
if (gp) {
return [["Photos", "library"], ["Albums", "albums"], ["Favorites", "favorites"], ["Trash", "trash"]];
}
return [["Photos", "library", "photo_library"], ["Albums", "albums", "photo_album"], ["Favorites", "favorites", "star_border"], ["Archive", "archive", "archive"], ["Trash", "trash", "delete"]];
};
const current = function() {
const v = state.view.view;
if (v === "photo") {
return state.view.trash ? "trash" : state.view.album ? "albums" : state.lastGrid;
}
if (v === "album") {
return "albums";
}
if (v === "search" && state.view.token && ugfPhNavHref(/^Favorites$/).indexOf(state.view.token) > -1) {
return "favorites";
}
return v;
};
const frame = function() {
const v = state.view.view;
let h = "";
if (v === "photo") {
h = viewerFrame();
} else if (pw) {
const bar = era === "pw07" ? topLinks() : era === "pw10" ? ugfNtGbar("classic", "Photos", "2010") : ugfNtGbar("dark", "Photos", "2011");
h = bar + 'Web Albums ' +
searchForm("psrch", "", '
" + (era === "pw11" ? ic("search", 18) : "Search Photos") + " ") +
(era === "pw11" ? ugfNtHeadCorner() : "") + "
" +
'' + tabsFor().map(function(t) {
return '
' + esc(t[0]) + " ";
}).join("") + '
Upload ' +
(current() === "albums" ? '
New album ' : "") + "
" +
'
';
} else if (gp) {
// (the black bar until 2014; the bevelled logo of 2010 until the flat one of
// late 2013)
h = (l === "2014" ? "" : ugfNtGbar("dark", "Photos", "2011")) + '' +
searchForm("gsrch", "Search photos", '
' + ic("search", 18) + " ") + ugfNtHeadCorner() + "
" +
'Photos ' + tabsFor().map(function(t) {
return '
' + esc(t[0]) + " ";
}).join("") + '
' + (current() === "albums" ? '
New album ' : "") +
'
Upload photos
';
} else if (era === "ph15") {
// 2015-2016: Google's bar of those years on top (the logo, the search box
// with its blue button, the apps and the photo), as over Drive, and the
// app's own bar under it: "Photos", and the place shown, with the others
// in its menu
const newLogo = ["2016", "2016C", "2016L"].indexOf(l) > -1;
let place = "Photos";
tabsFor().forEach(function(t) {
if (t[1] === current()) {
place = t[0];
}
});
if (state.view.view === "album") {
place = heading();
}
h = '" +
searchForm("gsrch", "Search Photos", '
' + ic("search", 20) + " ") + ugfNtHeadCorner() + "
" +
'Photos ' + esc(place) + " " + ic("arrow_drop_down", 24) + "
" +
'
' + (current() === "albums" ? '
' + ic("add_photo_alternate", 24) + " " : "") +
'
' + ic("cloud_upload", 24) + '
';
} else {
h = '' +
'
' + (gm ? "Google Photos" : "Photos") + " " +
searchForm("msrch", gm ? "Search your photos" : "Search", '
' + ic("search", 24) + " ") +
'
' + (gm ? '
' + ic("cloud_upload", 20) + "Upload " : '
' + ic("cloud_upload", 24) + " ") +
'
' + ugfNtCorner() + " " +
'
' + (era === "ph15" ? '
' : "") + '
';
}
const note = shell.querySelector(".pnote");
shell.innerHTML = trusted_policy.createHTML(h);
// (a message on show outlives the page it was said on)
if (note && !note.hidden) {
shell.appendChild(note);
}
ugfNtMenus(shell, gm);
state.drawn = "";
if (v === "photo") {
drawViewer();
} else {
drawContent();
}
};
// ---- the photos and albums
const thumbOf = function(p, size, crop) {
return ugfPhSized(p.base, crop ? "s" + size + "-c" : "w" + size + "-h" + size + "-no");
};
const gridHtml = function(list) {
if (!list.length) {
return '' + (state.loaded ? esc(emptyWords()) : "Loading...") + "
";
}
const tile = function(p) {
const on = !!state.sel[p.id];
return '' +
(p.kind === "video" ? '
' + ic("play_circle", 22) + " " : "") + '
' + ic("check_circle", 22) + " ";
};
if (pw) {
return '' + list.map(tile).join("") + "
";
}
// grouped by day, from 2012 on
let h = "";
let lastDay = null;
list.forEach(function(p) {
if (p.day !== lastDay) {
if (lastDay !== null) {
h += "";
}
lastDay = p.day;
h += '' + esc(dayLabel(p.day) || "") + '
';
}
h += tile(p);
});
return h + "
";
};
const albumsHtml = function(list) {
if (!list.length) {
return '' + (state.loaded ? "No albums yet." : "Loading...") + "
";
}
return '' + list.map(function(a) {
return '
' +
'
' + esc(a.title) + "
" + '
' + (a.count ? plural(+a.count.replace(/,/g, ""), pw ? "photo" : "item") : "") + (a.shared ? (a.count ? " · " : "") + "Shared" : "") + "
";
}).join("") + "
";
};
const emptyWords = function() {
const v = state.view.view;
return { trash: "Trash is empty", archive: "No photos in the archive", search: "No results", album: "This album is empty" }[v] ||
(pw ? "No photos yet. Upload some with the Upload button." : "No photos yet. Drag photos here or use Upload.");
};
const heading = function() {
const v = state.view.view;
if (v === "album") {
const t = document.querySelector("textarea[aria-label='Edit album name'], [data-title]");
const name = t ? (t.value || t.getAttribute("data-title") || "") : "";
return name || "Album";
}
if (v === "search") {
return current() === "favorites" ? W.fav : "Search results";
}
return { library: W.lib, albums: W.albums, archive: "Archive", trash: "Trash", sharing: "Sharing" }[v] || "";
};
const drawContent = function() {
const box = shell.querySelector(".pcontent");
if (!box) {
return;
}
const v = state.view.view;
let h = "";
const head = heading();
if (v === "albums") {
h = (pw || gp ? "" : '") +
albumsHtml(state.albums);
} else {
const albumBar = v === "album" ? '' + (pw ? "" : ic("share", 20)) + "" + (pw ? "Share album" : "Share") + " " : "";
h = (pw ? '"
: (v === "library" && ph ? "" : '")) +
gridHtml(state.photos);
}
if (h === state.drawn) {
return;
}
state.drawn = h;
const main = shell.querySelector(".pmain");
const keep = main ? main.scrollTop : 0;
box.innerHTML = trusted_policy.createHTML(h);
// the rows of 2012 on are filled edge to edge: each picture as wide as its shape
box.querySelectorAll(".pgrid.jr img").forEach(function(img) {
const fit = function() {
if (img.naturalWidth && img.naturalHeight) {
const r = img.naturalWidth / img.naturalHeight;
const t = img.parentElement;
t.style.flexGrow = String(r);
t.style.flexBasis = Math.round(r * rowH()) + "px";
}
};
if (img.complete) {
fit();
} else {
img.addEventListener("load", fit, { once: true });
}
});
if (main) {
main.scrollTop = keep;
}
drawSel();
};
const rowH = function() {
return gp ? 180 : gm ? 220 : 200;
};
// ---- choosing photos
const selected = function() {
return state.photos.filter(function(p) {
return state.sel[p.id];
});
};
const drawSel = function() {
const bar = shell.querySelector(".pselbar");
if (!bar) {
return;
}
const sel = selected();
shell.classList.toggle("selecting", sel.length > 0);
if (!sel.length) {
bar.hidden = true;
return;
}
bar.hidden = false;
const trashView = state.view.view === "trash";
const acts = trashView ? [["restore", "Restore", "restore"]] : [["share", "Share", "share"], ["fav", "Add to favorites", "star_border"], ["download", "Download", "file_download"], ["trash", pw ? "Delete" : "Move to trash", "delete"]];
if (ph) {
bar.innerHTML = trusted_policy.createHTML('' + ic("close", 24) + ' ' + sel.length + " selected " +
acts.map(function(a) {
return '' + ic(a[2], 24) + " ";
}).join(""));
} else {
bar.innerHTML = trusted_policy.createHTML('' + plural(sel.length, "photo") + " selected: " + acts.map(function(a) {
return '' + esc(a[1]) + " ";
}).join(" | ") + ' | Clear ');
}
};
const paintSel = function() {
shell.querySelectorAll(".pt[data-id]").forEach(function(t) {
t.classList.toggle("on", !!state.sel[t.getAttribute("data-id")]);
});
drawSel();
};
// ---- dialogs of the period
const dialog = function(title, body, buttons) {
const box = document.createElement("div");
box.className = "pdlg-wrap";
box.innerHTML = trusted_policy.createHTML('
' + esc(title) + '
' + body + '
' +
buttons.map(function(b, i) {
return '' + esc(b.label) + " ";
}).join("") + "
");
shell.appendChild(box);
const close = function() {
box.remove();
document.removeEventListener("keydown", onKey, true);
};
const onKey = function(ev) {
if (ev.key === "Escape") {
ev.preventDefault();
ev.stopPropagation();
close();
} else if (ev.key === "Enter" && ev.target.tagName === "INPUT") {
ev.preventDefault();
const pri = buttons.filter(function(b) {
return b.primary;
})[0];
if (pri) {
pri.fn(box);
close();
}
}
};
document.addEventListener("keydown", onKey, true);
box.querySelectorAll(".pdbtns button").forEach(function(b) {
b.addEventListener("click", function() {
const bt = buttons[+b.getAttribute("data-i")];
if (bt.fn) {
bt.fn(box);
}
close();
});
});
box.querySelector(".pfence").addEventListener("click", close);
const f = box.querySelector("input");
if (f) {
setTimeout(function() {
f.focus();
f.select();
}, 0);
}
};
const caps = era === "ph17";
const okL = function(s) {
return caps ? s.toUpperCase() : s;
};
const sure = function(title, text, ok, fn) {
dialog(title, "" + esc(text) + "
", [{ label: okL(ok), primary: true, fn: fn }, { label: okL("Cancel") }]);
};
// ---- doing things, by Google's own controls
const busy = { n: 0 };
const pressThen = async function(re, confirmRe, ms) {
const b = await ugfDvWait(function() {
return ugfPhGoogleButton(re);
}, ms || 2500);
if (!b) {
console.log("[Gplex] Photos: no button on Google's page matching " + re);
return false;
}
ugfDvFire(b, ["pointerover", "mouseover", "pointerenter", "mouseenter"]);
ugfDvPress(b);
if (confirmRe) {
const c = await ugfDvWait(function() {
return ugfDvDialogButton(confirmRe);
}, 3000);
if (c) {
ugfDvPress(c);
console.log("[Gplex] Photos: pressed Google's " + ugfDvText(b) + ", then " + ugfDvText(c));
} else {
// (no question asked: fine, if the photo went; else what the dialogs offered)
console.log("[Gplex] Photos: pressed Google's " + ugfDvText(b) + "; no confirmation matching " + confirmRe + " (dialogs on show: " + (ugfDvDialogWords() || "none") + ")");
}
}
return true;
};
// Moving to the trash: Google's button, then whatever Google asks (the first time
// it explains the trash and wants "Got it"; later it may ask to confirm), until the
// photo has gone - the button pressed again once if Google only wanted the "Got it"
const trashIt = async function(ids, inViewer) {
const before = window.location.pathname;
const re = /^(Move to trash|Delete|Move to bin|Remove)$/;
const conf = /^(Move to trash|Move to bin|Delete|Remove|OK|Got it|Continue|Yes)$/i;
const gone = function() {
if (inViewer) {
return window.location.pathname !== before || !ugfPhViewerMedia(ids[0]);
}
const hv = ugfPhHarvest();
return !hv.photos.some(function(p) {
return ids.indexOf(p.id) > -1;
});
};
// Google's answers, as long as it keeps asking
const answer = async function() {
let any = false;
for (let i = 0; i < 3; i++) {
const c = await ugfDvWait(function() {
return ugfDvDialogButton(conf);
}, i ? 1200 : 3000);
if (!c) {
break;
}
console.log("[Gplex] Photos: answered Google's question with " + ugfDvText(c));
ugfDvPress(c);
any = true;
await ugfDvSleep(500);
if (gone()) {
break;
}
}
return any;
};
for (let round = 0; round < 2; round++) {
const b = await ugfDvWait(function() {
return ugfPhGoogleButton(re);
}, 1500);
if (b) {
ugfDvFire(b, ["pointerover", "mouseover", "pointerenter", "mouseenter"]);
ugfDvPress(b);
console.log("[Gplex] Photos: pressed Google's " + ugfDvText(b));
} else {
// Google's own key for it
["keydown", "keypress", "keyup"].forEach(function(t) {
try {
(document.activeElement && !document.activeElement.closest("#ugf-photos") ? document.activeElement : document.body).dispatchEvent(new KeyboardEvent(t, { bubbles: true, cancelable: true, key: "#", code: "Digit3", shiftKey: true, keyCode: t === "keypress" ? 35 : 51, which: t === "keypress" ? 35 : 51 }));
} catch (e) {}
});
console.log("[Gplex] Photos: no trash button; tried Google's # key");
}
await answer();
if (await ugfDvWait(gone, 3000)) {
return true;
}
if (!b) {
break;
}
}
const left = ugfDvDialogWords();
if (left) {
console.log("[Gplex] Photos: Google's dialogs still open: " + left);
// (never left open underneath)
const x = ugfDvDialogButton(/^(Cancel|Close|No thanks)$/i);
if (x) {
ugfDvPress(x);
}
}
return false;
};
const menuDownload = async function() {
const more = await ugfDvWait(function() {
return ugfPhGoogleButton(/^More options$/);
}, 2000);
if (!more) {
console.log("[Gplex] Photos: Google's More options was not found");
return false;
}
ugfDvPress(more);
const it = await ugfDvWait(function() {
return ugfDvMenuItem(/^Download/);
}, 2500);
if (!it) {
console.log("[Gplex] Photos: no Download in Google's menu");
ugfDvCloseMenus();
return false;
}
ugfDvPress(it);
return true;
};
// choosing the photos in Google's own grid (its tick on each), before its bar's buttons
const selectInGoogle = async function(list) {
list.forEach(function(p) {
const live = byId(p.id);
const c = live && live.check;
if (c && c.isConnected && c.getAttribute("aria-checked") !== "true") {
ugfDvFire(live.el, ["pointerover", "mouseover", "pointerenter", "mouseenter", "pointermove", "mousemove"]);
ugfDvPress(c);
}
});
await ugfDvSleep(400);
const n = list.filter(function(p) {
const live = byId(p.id);
return live && live.check && live.check.getAttribute("aria-checked") === "true";
}).length;
console.log("[Gplex] Photos: " + n + " of " + list.length + " chosen in Google's grid");
};
const clearGoogle = function() {
const b = ugfPhGoogleButton(/^(Clear selection|Cancel selection|Close selection|Deselect all)/);
if (b) {
ugfDvPress(b);
} else {
ugfDvCloseMenus();
}
};
const doSel = async function(a) {
const sel = selected();
if (!sel.length) {
return;
}
if (a === "clear") {
state.sel = {};
paintSel();
return;
}
const run = async function() {
await selectInGoogle(sel);
let ok = false;
if (a === "trash") {
ok = await trashIt(sel.map(function(p) {
return p.id;
}), false);
notice(ok ? plural(sel.length, "photo") + " moved to the trash." : "The photos didn't go to the trash.");
} else if (a === "download") {
ok = await pressThen(/^Download/) || await menuDownload();
if (!ok) {
notice("Couldn't start the download.");
}
} else if (a === "fav") {
ok = await pressThen(/^(Add to favorites|Favorite)$/);
if (!ok) {
ok = (await ugfDvWait(function() {
return ugfPhGoogleButton(/^More options$/);
}, 800)) && (ugfDvPress(ugfPhGoogleButton(/^More options$/)), true);
const it = ok ? await ugfDvWait(function() {
return ugfDvMenuItem(/^(Add to favorites|Favorite)/);
}, 2000) : null;
ok = !!it && ugfDvPress(it);
}
notice(ok ? "Added to favorites." : "Couldn't add to favorites.");
} else if (a === "restore") {
ok = await pressThen(/^Restore$/);
notice(ok ? plural(sel.length, "photo") + " restored." : "Couldn't restore the photos.");
} else if (a === "share") {
ok = await pressThen(/^Share$/);
if (ok) {
revealSoon();
} else {
notice("Couldn't open sharing.");
}
}
if (a !== "share") {
setTimeout(clearGoogle, 400);
}
state.sel = {};
paintSel();
};
if (a === "trash") {
sure(pw ? "Delete photos" : "Move to trash?", pw ? "Delete " + plural(sel.length, "photo") + "?" : plural(sel.length, "photo") + " will be moved to the trash.", pw ? "Delete" : "Move to trash", run);
} else {
run();
}
};
// Google's own dialog, shown above Gplex's page, where Gplex cannot carry it out
// itself (sharing, adding photos to an album)
const revealSoon = function() {
ugfDvWait(function() {
return ugfDvDialog();
}, 4000).then(function(d) {
if (d) {
ugfDvReveal(d);
}
});
};
// uploading: Google's own "Upload" (its picker, its uploading), or files dropped
// on the page, which go straight through to Google's page underneath
const upload = function() {
const btn = ugfPhGoogleButton(/^(Upload|Create and add photos|Create)$/);
if (!btn) {
notice("Couldn't find Google's upload. Drag the photos onto the page instead.");
return;
}
ugfDvPress(btn);
const re = /^(Upload( photos)?|Import photos|From computer|Computer)\b/i;
const now = ugfDvMenuItem(re);
const pick = function(it) {
ugfDvPress(it);
// a menu of places to upload from: the computer
setTimeout(function() {
const c = ugfDvMenuItem(/^(Computer|From computer|From your computer)\b/i);
if (c) {
ugfDvPress(c);
}
}, 250);
};
if (now) {
pick(now);
return;
}
ugfDvWait(function() {
return ugfDvMenuItem(re);
}, 2500).then(function(it) {
if (it) {
pick(it);
} else {
const offered = [];
document.querySelectorAll("[role=menuitem]").forEach(function(el) {
if (ugfDvShown(el)) {
offered.push(String(el.textContent || "").replace(/\s+/g, " ").trim().slice(0, 40));
}
});
console.log("[Gplex] Photos: no upload in Google's menu" + (offered.length ? " (it has: " + offered.join(" | ") + ")" : ""));
ugfDvCloseMenus();
notice("Couldn't open the upload. Drag the photos onto the page instead.");
}
});
};
const newAlbum = function() {
dialog(gm ? "Create album" : "New album", ' ', [{ label: okL("Create"), primary: true, fn: function(box) {
const name = box.querySelector(".pin").value.trim();
const run = async function() {
if (state.view.view !== "albums") {
go("albums");
await ugfDvWait(function() {
return ugfPhView().view === "albums";
}, 4000);
}
if (!(await pressThen(/^(Create album|New album)$/))) {
notice("Couldn't create the album.");
return;
}
if (name) {
const f = await ugfDvWait(function() {
let t = null;
document.querySelectorAll("textarea[aria-label='Edit album name'], textarea[placeholder='Add a title'], input[placeholder='Add a title']").forEach(function(x) {
if (!x.closest("#ugf-photos") && x.getClientRects().length) {
t = x;
}
});
return t;
}, 5000);
if (f) {
ugfDvType(f, name);
ugfDvKey(f, "Enter");
f.blur();
}
}
notice("Album created. Add photos to it from Google's picker.");
revealSoon();
};
run();
} }, { label: okL("Cancel") }]);
};
// ---- the photo viewer of the period
const viewerFrame = function() {
if (pw) {
const bar = era === "pw07" ? topLinks() : era === "pw10" ? ugfNtGbar("classic", "Photos", "2010") : ugfNtGbar("dark", "Photos", "2011");
return bar + '' +
'';
}
if (gp) {
return '' + ugfGmailAvatar() + '
' + esc(who.name || who.email || "") + '
' +
'
';
}
return '';
};
const drawViewer = function() {
const id = state.view.id;
shell.classList.toggle("intrash", !!state.view.trash);
const m = ugfPhViewerMedia(id);
const base = (m && m.base) || state.bases[id] || "";
if (base) {
state.bases[id] = base;
}
const img = shell.querySelector(".pvimg img, .gvimg img, .pvstage img");
if (!img) {
return;
}
const stage = img.parentElement;
const dpr = Math.min(2, window.devicePixelRatio || 1);
const w = Math.round(Math.max(200, stage.clientWidth || 1000) * dpr);
const h = Math.round(Math.max(200, stage.clientHeight || 700) * dpr);
const want = base ? ugfPhSized(base, "w" + w + "-h" + h + "-no") : "";
if (want && img.getAttribute("data-src") !== want) {
img.setAttribute("data-src", want);
img.src = want;
}
// what is known of it
const known = byId(id) || {};
const day = (m && m.day) || known.day || "";
const time = (m && m.time) || known.time || "";
const rows = [["Date", day + (time ? ", " + time : "")], ["Size", m && m.w ? m.w + " × " + m.h : ""], ["Kind", (m && m.kind === "video") || known.kind === "video" ? "Video" : "Photo"]];
const infoH = rows.filter(function(r) {
return r[1];
}).map(function(r) {
return "" + esc(r[0]) + " " + esc(r[1]) + "
";
}).join("");
shell.querySelectorAll(".pvinfo").forEach(function(x) {
if (x.ugfH !== infoH) {
x.ugfH = infoH;
x.innerHTML = trusted_policy.createHTML(infoH);
}
});
const gd = shell.querySelector(".gvdate");
if (gd) {
gd.textContent = day;
}
const crumb = shell.querySelector(".pvcrumb");
if (crumb) {
const hh = '' + esc(state.view.album ? W.albums : W.lib) + " › Photo";
if (crumb.ugfH !== hh) {
crumb.ugfH = hh;
crumb.innerHTML = trusted_policy.createHTML(hh);
}
}
// favorite or not, as Google's own button says
const fb = ugfPhGoogleButton(/^(Favorite|Unfavorite|Remove from favorites|Add to favorites)$/);
const isFav = !!fb && /^(Unfavorite|Remove from favorites)$/.test(fb.getAttribute("aria-label"));
shell.querySelectorAll("[data-v=fav]").forEach(function(x) {
if (x.classList.contains("ib")) {
const want2 = ic(isFav ? "star" : "star_border", 24);
if (x.ugfH !== want2) {
x.ugfH = want2;
x.innerHTML = trusted_policy.createHTML(want2);
}
} else {
x.textContent = isFav ? "Remove from favorites" : "Add to favorites";
}
});
shell.querySelectorAll("[data-v=prev]").forEach(function(x) {
x.classList.toggle("off", !ugfPhGoogleButton(/^View previous photo$/));
});
shell.querySelectorAll("[data-v=next]").forEach(function(x) {
x.classList.toggle("off", !ugfPhGoogleButton(/^View next photo$/));
});
};
const viewerAct = function(a) {
if (a === "prev" || a === "next") {
const b = ugfPhGoogleButton(a === "prev" ? /^View previous photo$/ : /^View next photo$/);
if (b) {
ugfDvPress(b);
}
} else if (a === "back") {
const b = ugfPhGoogleButton(/^Back to (photos|album)/i) || ugfPhGoogleButton(/^Back$/);
if (b) {
ugfDvPress(b);
} else if (window.history.length > 1) {
window.history.back();
} else {
window.location.href = ugfPhBase() + "/";
}
} else if (a === "info") {
const p = shell.querySelector(".pvpanel");
if (p) {
p.hidden = !p.hidden;
shell.classList.toggle("infoopen", !p.hidden);
setTimeout(drawViewer, 50);
}
} else if (a === "fav") {
pressThen(/^(Favorite|Unfavorite|Remove from favorites|Add to favorites)$/).then(function() {
setTimeout(drawViewer, 400);
});
} else if (a === "download") {
menuDownload().then(function(ok) {
if (!ok) {
notice("Couldn't start the download.");
}
});
} else if (a === "share") {
pressThen(/^Share$/).then(function(ok) {
if (ok) {
revealSoon();
} else {
notice("Couldn't open sharing.");
}
});
} else if (a === "restore") {
pressThen(/^Restore$/, /^Restore$/).then(function(ok) {
notice(ok ? "Restored." : "Couldn't restore the photo.");
});
} else if (a === "purge") {
sure("Delete forever?", "This photo will be deleted forever. This can't be undone.", "Delete forever", function() {
pressThen(/^(Delete permanently|Delete forever|Delete)$/, /^(Delete permanently|Delete forever|Delete|Got it)$/i).then(function(ok) {
notice(ok ? "Deleted forever." : "Couldn't delete the photo.");
});
});
} else if (a === "trash") {
sure(pw ? "Delete photo" : "Move to trash?", pw ? "Delete this photo?" : "This photo will be moved to the trash.", pw ? "Delete" : "Move to trash", function() {
trashIt([state.view.id], true).then(function(ok) {
notice(ok ? (pw ? "Photo deleted." : "Moved to the trash.") : "The photo didn't go to the trash.");
});
});
}
};
// ---- clicks, keys, drops
shell.addEventListener("click", function(ev) {
const t = ev.target;
if (!t.closest("[data-a=places]")) {
const pl = shell.querySelector(".pplaces");
if (pl) {
pl.hidden = true;
}
}
if (t.closest(".pfence2")) {
shell.classList.remove("dopen");
return;
}
const g = t.closest("[data-go]");
if (g) {
shell.classList.remove("dopen");
ev.preventDefault();
go(g.getAttribute("data-go"));
return;
}
const v = t.closest("[data-v]");
if (v) {
ev.preventDefault();
if (!v.classList.contains("off")) {
viewerAct(v.getAttribute("data-v"));
}
return;
}
const a = t.closest("[data-a]");
if (a) {
ev.preventDefault();
const w = a.getAttribute("data-a");
if (w === "places") {
const pl = shell.querySelector(".pplaces");
if (pl) {
const r = a.getBoundingClientRect();
pl.style.left = Math.round(r.left) + "px";
pl.style.top = Math.round(r.bottom) + "px";
pl.hidden = !pl.hidden;
}
} else if (w === "drawer") {
shell.classList.toggle("dopen");
} else if (w === "upload") {
upload();
} else if (w === "newalbum") {
newAlbum();
} else if (w === "share-album") {
pressThen(/^Share$/).then(function(ok) {
if (ok) {
revealSoon();
} else {
notice("Couldn't open sharing.");
}
});
} else {
doSel(w);
}
return;
}
const chk = t.closest(".pchk");
const tile = t.closest(".pt[data-id]");
if (tile) {
const id = tile.getAttribute("data-id");
if (chk || ev.metaKey || ev.ctrlKey || shell.classList.contains("selecting")) {
state.sel[id] = !state.sel[id];
paintSel();
return;
}
const p = byId(id);
if (p) {
state.bases[id] = p.base;
state.lastGrid = state.view.view === "album" ? "albums" : state.view.view;
openLink(p.el, p.href);
}
return;
}
const al = t.closest(".pa[data-album]");
if (al) {
let f = null;
state.albums.forEach(function(x) {
if (x.id === al.getAttribute("data-album")) {
f = x;
}
});
if (f) {
openLink(f.el, f.href);
}
}
});
shell.addEventListener("submit", function(ev) {
ev.preventDefault();
const q = ((ev.target.querySelector("input[name=q]") || {}).value || "").trim();
if (q) {
window.location.href = ugfPhBase() + "/search/" + encodeURIComponent(q);
}
});
shell.addEventListener("keydown", function(ev) {
ev.stopPropagation();
if (/^(INPUT|TEXTAREA)$/.test(ev.target.tagName) || shell.querySelector(".pdlg-wrap")) {
return;
}
if (state.view.view === "photo") {
if (ev.key === "ArrowLeft") {
viewerAct("prev");
} else if (ev.key === "ArrowRight") {
viewerAct("next");
} else if (ev.key === "Escape") {
viewerAct("back");
}
} else if (ev.key === "Escape") {
state.sel = {};
paintSel();
}
});
// photos dragged in from the computer go through to Google's page underneath
let dragT = 0;
const hasFiles = function(ev) {
return ev.dataTransfer && [].indexOf.call(ev.dataTransfer.types || [], "Files") > -1;
};
const dragOff = function() {
clearTimeout(dragT);
html.removeAttribute("gplex-ph-drag");
shell.classList.remove("drop");
};
window.addEventListener("dragenter", function(ev) {
if (hasFiles(ev) && !shell.hidden) {
html.setAttribute("gplex-ph-drag", "");
shell.classList.add("drop");
}
}, true);
window.addEventListener("dragover", function() {
if (html.hasAttribute("gplex-ph-drag")) {
clearTimeout(dragT);
dragT = setTimeout(dragOff, 900);
}
}, true);
window.addEventListener("drop", function(ev) {
if (html.hasAttribute("gplex-ph-drag")) {
const n = ev.dataTransfer && ev.dataTransfer.files ? ev.dataTransfer.files.length : 0;
setTimeout(function() {
dragOff();
if (n) {
notice("Uploading " + plural(n, "photo") + "...", false);
}
}, 50);
}
}, true);
window.addEventListener("dragover", function(ev) {
if (html.hasAttribute("gplex-ph-drag") && hasFiles(ev) && !ev.defaultPrevented) {
ev.preventDefault();
}
});
window.addEventListener("drop", function(ev) {
if (html.hasAttribute("gplex-ph-drag") && !ev.defaultPrevented) {
ev.preventDefault();
}
});
window.addEventListener("resize", function() {
if (state.view.view === "photo") {
drawViewer();
}
});
// ---- keeping up with Google's page
let myTitle = "";
const titleFor = function() {
const v = state.view.view;
const what = v === "photo" ? "Photo" : heading() || "Photos";
return pw ? "Picasa Web Albums - " + what : gp ? what + " - Google+" : what + " - Google Photos";
};
const tick = function() {
const v = ugfPhView();
if (v.view === "") {
if (!shell.hidden) {
shell.hidden = true;
html.removeAttribute("gplex-ph");
}
return;
}
if (shell.hidden) {
shell.hidden = false;
html.setAttribute("gplex-ph", era);
}
const changed = v.view !== state.view.view || v.id !== state.view.id || v.token !== state.view.token || v.album !== state.view.album;
const wasPhoto = state.view.view === "photo";
if (changed) {
state.view = v;
state.sel = {};
if (!(wasPhoto && v.view === "photo")) {
state.photos = [];
state.albums = [];
state.key = "";
state.loaded = false;
frame();
setTimeout(function() {
state.loaded = true;
drawContent();
}, 5000);
}
}
if (v.view === "photo") {
drawViewer();
} else {
const hv = ugfPhHarvest();
const key = hv.photos.map(function(p) {
return p.id + p.base.slice(-12);
}).join("|") + "#" + hv.albums.map(function(a) {
return a.id + a.title + a.count;
}).join("|") + "#" + heading();
// (the grid keeps the photos it had while Google's list refills itself)
if (key !== state.key) {
state.key = key;
state.photos = hv.photos;
state.albums = hv.albums;
hv.photos.forEach(function(p) {
if (p.base) {
state.bases[p.id] = p.base;
}
});
if (hv.photos.length || hv.albums.length) {
state.loaded = true;
}
drawContent();
}
}
myTitle = titleFor();
if (document.title !== myTitle) {
document.title = myTitle;
}
};
// more of a long list: Google loads it as its own grid is scrolled
shell.addEventListener("scroll", function(ev) {
const m = ev.target;
if (!m.classList || !m.classList.contains("pmain") || m.scrollTop + m.clientHeight < m.scrollHeight - 300) {
return;
}
const last = state.photos[state.photos.length - 1];
if (last && last.el && last.el.isConnected) {
try {
last.el.scrollIntoView({ block: "end" });
} catch (e) {}
}
}, true);
tick();
setInterval(tick, 600);
}
// ---- Photos: the styles of each period ---------------------------------------------
function ugfPhotosCss(era, A) {
const H = "#ugf-photos";
const c = [];
const add = function(sel, body) {
c.push(sel.split(",").map(function(s) {
return H + " " + s.trim();
}).join(", ") + " { " + body + " }");
};
const pw = era.indexOf("pw") === 0;
const gp = era === "gp13";
const ph = era.indexOf("ph") === 0;
const gm = era === "ph19";
const k11 = era === "pw11";
const f = gm ? "'Google Sans', Roboto, Arial, sans-serif" : ph ? "Roboto, RobotoDraft, Helvetica, Arial, sans-serif" : "Arial, sans-serif";
ugfNtBaseCss("ugf-photos").forEach(function(r) {
if (r.indexOf("html[gplex-nt]") !== 0 && r.indexOf(H + " {") !== 0) {
c.push(r);
}
});
c.push("html[gplex-ph], html[gplex-ph] body { overflow: hidden !important; }");
c.push("html[gplex-ph] body > [ugf-dv-up] { z-index: 2147483100 !important; }");
c.push("html[gplex-dv-reveal] " + H + " { display: none !important; }");
c.push("html[gplex-ph-drag] " + H + " { pointer-events: none !important; }");
c.push("html[gplex-ph] #ugf-gmail-accfence { z-index: 2147483600 !important; } html[gplex-ph] #ugf-gmail-accmenu, html[gplex-ph] #ugf-gmail-appsmenu { z-index: 2147483601 !important; text-align: left; }");
c.push("html[gplex-ph] #ugf-gmail-accmenu a, html[gplex-ph] #ugf-gmail-appsmenu a { text-decoration: none; }");
c.push(H + " { position: fixed; inset: 0; z-index: 2147483000; display: flex; flex-direction: column; background: " + (gp ? "#f1f1f1" : "#fff") + "; color: #222; font: 13px " + f + "; text-align: left; overflow: hidden; outline: none; }");
c.push(H + "[hidden] { display: none !important; }");
c.push(H + ".drop .pmain { outline: 3px dashed " + (ph ? "#4285f4" : "#6d9eeb") + "; outline-offset: -8px; }");
add("*", "box-sizing: border-box;");
// (a photo in the trash: Restore and Delete forever in place of the rest)
c.push(H + ":not(.intrash) .tr-only, " + H + ".intrash .not-tr { display: none !important; }");
add("a, [data-a], [data-go], [data-v], .pt, .pa", "cursor: pointer;");
add(".mi", "display: inline-flex; font-style: normal;");
add(".mi svg", "display: block; fill: currentColor;");
add(".sp", "flex: 1;");
add("form", "display: flex; align-items: center; margin: 0;");
add(".pmain", "flex: 1; overflow: auto; min-height: 0; position: relative;");
add(".pempty", "padding: 40px 24px; color: #777; font-size: 14px;" + (ph ? " text-align: center; padding-top: 80px; font-size: 16px;" : ""));
add(".pnote", "position: absolute; z-index: 50; " + (ph ? "left: 24px; bottom: 24px; background: " + (gm ? "#202124" : "#323232") + "; color: #fff; padding: 14px 24px; font-size: 14px; border-radius: " + (gm ? "4px" : "2px") + ";"
: "left: 50%; top: 6px; transform: translateX(-50%); background: " + (k11 || gp ? "#f9edbe; border: 1px solid #f0c36d;" : "#fad163;") + " padding: 5px 12px; font-weight: bold; border-radius: 2px;"));
add(".pnote[hidden]", "display: none;");
// the tiles
add(".pgrid", "display: flex; flex-wrap: wrap; gap: " + (pw ? "18px" : gp ? "4px" : "4px") + ";");
add(".pgrid.sq .pt", "width: 160px; height: 160px; padding: 7px; background: #fff; border: 1px solid #ccc; box-shadow: 1px 1px 2px rgba(0,0,0,.15);");
add(".pgrid.sq .pt img", "width: 144px; height: 144px; object-fit: cover; display: block;");
add(".pgrid.jr::after", "content: ''; flex-grow: 1000000;");
add(".pgrid.jr .pt", "height: " + (gp ? 180 : gm ? 220 : 200) + "px; flex: 1 1 200px; min-width: 60px; max-width: 800px; overflow: hidden; background: #eee;");
add(".pgrid.jr .pt img", "width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .12s;");
add(".pt", "position: relative; user-select: none;");
add(".pt .pchk", "position: absolute; left: 6px; top: 6px; display: none; color: rgba(255,255,255,.85); filter: drop-shadow(0 1px 2px rgba(0,0,0,.5));");
add(".pt:hover .pchk, " + H + ".selecting .pt .pchk", "display: inline-flex;");
add(".pt.on .pchk", "display: inline-flex; color: " + (ph ? "#4285f4" : "#3079ed") + "; filter: none; background: #fff; border-radius: 50%;");
add(".pt.on img", ph ? "transform: scale(.86);" : "outline: 3px solid #3079ed; outline-offset: -3px;");
add(".pt.on", ph ? "background: " + (gm ? "#e8f0fe" : "#dde7fb") + ";" : "");
add(".pt .pv", "position: absolute; right: 6px; top: 6px; color: #fff; filter: drop-shadow(0 1px 2px rgba(0,0,0,.6));");
add(".pday", "font: " + (ph ? "500 14px " + f : gp ? "bold 13px Arial" : "bold 13px Arial") + "; color: " + (ph ? "#202124" : "#444") + "; padding: " + (ph ? "24px 0 12px" : "16px 0 8px") + ";");
// the albums
add(".palbums", "display: grid; grid-template-columns: repeat(auto-fill, " + (pw ? "180px" : "minmax(180px, 1fr)") + "); gap: " + (pw ? "24px 18px" : "24px 16px") + ";");
add(".pa", "min-width: 0;");
add(".pac", pw ? "width: 172px; height: 172px; padding: 6px; background: #fff; border: 1px solid #ccc; box-shadow: 3px 3px 0 #fff, 4px 4px 0 #ccc, 6px 6px 0 #fff, 7px 7px 0 #bbb;"
: "aspect-ratio: 1; overflow: hidden; background: #eee; border-radius: " + (gm ? "8px" : "0") + ";" + (gp ? " box-shadow: 0 1px 2px rgba(0,0,0,.2);" : ""));
add(".pac img", "width: 100%; height: 100%; object-fit: cover; display: block;");
add(".pat", "margin-top: " + (pw ? "10px" : "8px") + "; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; " +
(pw ? "color: #00c; text-decoration: underline; font-weight: bold;" : "color: #202124; font-weight: 500; font-size: 14px;"));
add(".pam", "color: #777; font-size: 12px; margin-top: 2px;");
add(".phd", "display: flex; align-items: center; gap: 8px; padding: " + (ph ? "20px 0 16px" : "12px 0") + "; font: " + (ph ? (gm ? "400 22px 'Google Sans', Roboto" : "400 20px Roboto") : "bold 16px Arial") + ", sans-serif; color: #202124;");
add(".phd .plink", "display: inline-flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 500; color: " + (ph ? "#1a73e8" : "#00c") + ";");
add(".phd .pback", "display: inline-flex; color: #5f6368;");
add(".pwhd a", "color: #00c; font-weight: normal;");
// the bar over the chosen photos
add(".pselbar", "display: flex; align-items: center; gap: 6px; flex: 0 0 auto;");
add(".pselbar[hidden]", "display: none;");
// ---- dialogs (Kennedy's until 2016, Material's after)
const kd = !ph || era === "ph15";
add(".pdlg-wrap", "position: fixed; inset: 0; z-index: 80;");
add(".pfence", "position: absolute; inset: 0; background: " + (kd ? "rgba(255,255,255,.75)" : "rgba(0,0,0,.4)") + ";");
add(".pdlg", "position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: 420px; max-width: calc(100% - 32px); background: #fff; " +
(kd ? "padding: 30px 42px; border: 1px solid #acacac; box-shadow: 0 4px 16px rgba(0,0,0,.2);" : "padding: 24px; box-shadow: 0 16px 24px rgba(0,0,0,.3); border-radius: " + (gm ? "8px" : "2px") + ";"));
add(".pdt", kd ? "font: 16px Arial, sans-serif; margin-bottom: 16px;" : "font: " + (gm ? "400 22px 'Google Sans'" : "500 20px Roboto") + ", sans-serif; margin-bottom: 20px;");
add(".pdb p", "margin: 0;");
add(".pdb .pin", "width: 100%; height: " + (kd ? "29px" : "36px") + "; font: 13px " + f + "; outline: none; " + (kd ? "border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 0 8px;" : "border: 0; border-bottom: 1px solid #ccc; font-size: 15px;"));
add(".pdb .pin:focus", kd ? "border-color: #4d90fe;" : "border-bottom: 2px solid #1a73e8;");
add(".pdbtns", "display: flex; gap: 8px; margin-top: 22px;" + (kd ? "" : " flex-direction: row-reverse; justify-content: flex-start;"));
add(".pdbtns button", kd ? "height: 29px; min-width: 72px; padding: 0 12px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px Arial, sans-serif;"
: "border: 0; background: none; color: #1a73e8; font: 500 14px " + f + "; height: 36px; padding: 0 12px; border-radius: " + (gm ? "4px" : "2px") + ";");
add(".pdbtns button.pri", kd ? "background: linear-gradient(#4d90fe, #4787ed); border-color: #3079ed; color: #fff;" : gm ? "background: #1a73e8; color: #fff; padding: 0 24px;" : "");
// ---- Picasa Web Albums
if (pw) {
add(".toplinks", "display: flex; justify-content: space-between; padding: 3px 8px 0; height: 24px; font-size: 13px; flex: 0 0 auto;");
add(".toplinks .left > *", "margin-right: 8px;");
add(".toplinks a", "color: #00c;");
add(".phead", "display: flex; align-items: center; gap: 18px; padding: " + (k11 ? "0 16px 0 20px; height: 72px; background: #f1f1f1; border-bottom: 1px solid #e5e5e5;" : "10px 12px 8px;") + " flex: 0 0 auto;");
add(".plogo", "display: flex; align-items: flex-end; gap: 4px; text-decoration: none;");
add(".plogo img", "display: block; height: 40px;");
add(".plogo span", "font: 20px Arial, sans-serif; color: " + (k11 ? "#777" : "#666") + "; margin-bottom: 4px;");
add(".psrch input", k11 ? "width: 380px; height: 29px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 0 8px; font-size: 13px; outline: none;" : "width: 260px; height: 22px; font-size: 13px; padding: 1px 3px; border: 1px solid; border-color: #999 #ccc #ccc #999;");
add(".psrch button", k11 ? "" : "margin-left: 5px; font-size: 13px; padding: 2px 6px;");
add(".ptabs", "display: flex; align-items: center; gap: " + (k11 ? "24px" : "4px") + "; padding: " + (k11 ? "0 20px" : "0 12px") + "; height: " + (k11 ? "50px" : "30px") + "; flex: 0 0 auto; " +
(k11 ? "border-bottom: 1px solid #ebebeb;" : "border-bottom: 1px solid #c3d9ff;"));
add(".ptab", k11 ? "color: #666; font-size: 13px; font-weight: bold; text-decoration: none;" : "padding: 5px 12px; color: #00c; text-decoration: underline; border: 1px solid transparent; border-bottom: 0; margin-bottom: -1px;");
add(".ptab.on", k11 ? "color: #dd4b39;" : "background: #fff; border-color: #c3d9ff; color: #000; text-decoration: none; font-weight: bold; border-radius: 4px 4px 0 0;");
add(".pbtn", "display: inline-block; padding: 2px 10px; margin-left: 6px; border: 1px solid; border-color: #bbb #999 #999 #bbb; border-radius: 2px; background: linear-gradient(#fff, #ddd); color: #000; font-size: 13px;");
add(".kbtn", "display: inline-flex; align-items: center; justify-content: center; height: 29px; min-width: 54px; padding: 0 12px; margin-left: 8px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px Arial, sans-serif;");
add(".kbtn.red", "background: linear-gradient(#dd4b39, #d14836); border-color: #c6322a; color: #fff;");
add(".kbtn.blue", "background: linear-gradient(#4d90fe, #4787ed); border-color: #3079ed; color: #fff; width: 60px; margin: 0 0 0 6px;");
add(".kbtn svg", "fill: #fff;");
add(".pmain", "padding: 8px 20px 40px;");
add(".pselbar", "padding: 6px 20px; background: " + (k11 ? "#f9edbe" : "#e8eef7") + "; font-size: 13px;");
add(".pselbar a", "color: #00c; text-decoration: underline;");
// the photo on its own page
add(".pvw", "flex: 1; display: flex; flex-direction: column; min-height: 0; padding: 0 20px;");
add(".pvcrumb", "padding: 8px 0; font-size: 14px;");
add(".pvcrumb a", "color: #00c;");
add(".pvnav", "padding: 0 0 8px; font-size: 13px;");
add(".pvnav a", "color: #00c; text-decoration: underline;");
add(".pvnav a.off", "color: #999; text-decoration: none; cursor: default;");
add(".pvsep", "color: #999; margin: 0 6px;");
add(".pvbody", "flex: 1; display: flex; gap: 20px; min-height: 0;");
add(".pvimg", "flex: 1; display: flex; align-items: flex-start; justify-content: center; min-width: 0; min-height: 0; padding-bottom: 20px;");
add(".pvimg img", "max-width: min(100%, 800px); max-height: min(100%, 640px); border: 1px solid #ccc; padding: 6px; background: #fff; box-shadow: 2px 2px 4px rgba(0,0,0,.15);");
add(".pvside", "width: 220px; flex: 0 0 220px; font-size: 13px;");
add(".pvside a", "display: block; color: #00c; text-decoration: underline; margin: 4px 0;");
add(".pvsh", "font-weight: bold; margin: 14px 0 6px; padding-bottom: 3px; border-bottom: 1px solid #c3d9ff;");
add(".pvinfo div", "margin: 3px 0; color: #444;");
add(".pvinfo span", "color: #777;");
}
// ---- Google+ Photos
if (gp) {
add(".ghead", "display: flex; align-items: center; height: 60px; padding: 0 16px 0 20px; background: #f5f5f5; border-bottom: 1px solid #e5e5e5; flex: 0 0 auto;");
add(".glogo img", "display: block; height: 30px; width: auto;");
add(".glogo.g10 img", "height: 38px;");
add(".gsrch", "margin-left: 40px; flex: 0 1 520px; display: flex;");
add(".gsrch input", "flex: 1; height: 29px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; border-right: 0; padding: 0 8px; font-size: 13px; outline: none;");
add(".gsrch .gbtn", "width: 60px; height: 29px; border: 1px solid #3079ed; background: linear-gradient(#4d90fe, #4787ed); display: inline-flex; align-items: center; justify-content: center; color: #fff;");
add(".gsrch .gbtn svg", "fill: #fff;");
add(".ghead .kcorner", "margin-left: auto;");
add(".gbar2", "display: flex; align-items: center; gap: 26px; height: 52px; padding: 0 20px; background: #fff; border-bottom: 1px solid #e5e5e5; flex: 0 0 auto;");
add(".gtitle", "font-size: 20px; color: #404040; margin-right: 12px;");
add(".gtab", "color: #666; font-size: 13px; font-weight: bold; height: 52px; line-height: 49px; border-bottom: 3px solid transparent;");
add(".gtab.on", "color: #dd4b39; border-bottom-color: #dd4b39;");
add(".kbtn", "display: inline-flex; align-items: center; height: 29px; padding: 0 12px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px Arial, sans-serif;");
add(".kbtn.red", "background: linear-gradient(#dd4b39, #d14836); border-color: #c6322a; color: #fff;");
add(".pmain", "padding: 12px 20px 40px;");
add(".pselbar", "padding: 8px 20px; background: #f9edbe; border-bottom: 1px solid #f0c36d; font-size: 13px;");
add(".pselbar a", "color: #15c;");
add(".pday", "color: #404040; font-weight: normal; font-size: 15px;");
// the lightbox
add(".gv", "position: fixed; inset: 0; display: flex; background: #000; z-index: 5;");
add(".gvimg", "flex: 1; position: relative; display: flex; align-items: center; justify-content: center; min-width: 0;");
add(".gvimg img", "max-width: 100%; max-height: 100%;");
add(".gvx", "position: absolute; left: 14px; top: 8px; color: #aaa; font-size: 34px; text-decoration: none;");
add(".gvarr", "position: absolute; top: 50%; transform: translateY(-50%); color: #fff; opacity: 0; transition: opacity .15s; display: flex;");
add(".gvimg:hover .gvarr", "opacity: .8;");
add(".gvarr.l", "left: 8px;");
add(".gvarr.r", "right: 8px;");
add(".gvarr.off", "display: none;");
add(".gvside", "width: 300px; background: #fff; padding: 20px; overflow: auto;");
add(".gvwho", "display: flex; gap: 10px; align-items: center; margin-bottom: 14px;");
add(".gvwho .pfp", "width: 40px; height: 40px;");
add(".gvdate", "color: #999; font-size: 12px; margin-top: 2px;");
add(".gvacts a", "display: block; color: #15c; padding: 5px 0;");
add(".pvinfo", "margin-top: 14px; padding-top: 12px; border-top: 1px solid #ebebeb;");
add(".pvinfo div", "margin: 4px 0;");
add(".pvinfo span", "color: #999;");
}
// ---- Google Photos
if (ph) {
add(".ib", "display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; color: #5f6368; border-radius: " + (gm ? "50%" : "0") + ";");
add(".ib:hover", "background: rgba(60,64,67,.08);");
add(".pbar", "display: flex; align-items: center; height: 64px; padding: 0 12px 0 16px; background: #fff; flex: 0 0 auto; " +
(era === "ph15" ? "box-shadow: 0 1px 3px rgba(0,0,0,.2); position: relative; z-index: 2;" : "border-bottom: 1px solid " + (gm ? "#dadce0" : "#e0e0e0") + ";"));
add(".brand", "display: flex; align-items: center; gap: 10px; width: 232px; text-decoration: none; color: #5f6368; font: " + (gm ? "22px 'Product Sans', 'Google Sans', Arial" : "20px Roboto, Arial") + ", sans-serif;");
add(".brand img", "width: 32px; height: 32px;");
add(".msrch", "position: relative; flex: 0 1 720px;");
add(".msrch input", "width: 100%; height: " + (gm ? "48px" : "44px") + "; border: 0; padding: 0 16px 0 56px; font: 16px " + f + "; outline: none; color: #202124; border-radius: " + (gm ? "8px" : "2px") + "; background: " +
(era === "ph15" ? "#fff; border-bottom: 1px solid #e0e0e0; border-radius: 0" : "#f1f3f4") + ";");
add(".msrch input:focus", era === "ph15" ? "border-bottom-color: #4285f4;" : "background: #fff; box-shadow: 0 1px 1px 0 rgba(65,69,73,.3), 0 1px 3px 1px rgba(65,69,73,.15);");
add(".msrch .sic", "position: absolute; left: 8px; top: 50%; transform: translateY(-50%); width: 40px; height: 40px; border: 0; background: none; color: #5f6368; display: inline-flex; align-items: center; justify-content: center;");
add(".upbtn", "display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 16px; margin-right: 8px; color: #5f6368; font: 500 14px " + f + "; border-radius: 4px;");
add(".upbtn:hover", "background: rgba(60,64,67,.08);");
add(".corner", "display: flex; align-items: center; margin-left: 4px;");
add(".pbody", "flex: 1; display: flex; min-height: 0;");
add(".pnav", "width: " + (gm ? "256px" : "232px") + "; flex: 0 0 auto; padding: 8px 0; overflow: auto;");
add(".pni", "display: flex; align-items: center; gap: " + (gm ? "18px" : "24px") + "; height: " + (gm ? "40px" : "48px") + "; padding: 0 16px 0 24px; color: #202124; text-decoration: none; font-size: 14px; font-weight: 500;" +
(gm ? " border-radius: 0 20px 20px 0; margin-right: 12px;" : ""));
add(".pni .mi", "color: #5f6368;");
add(".pni:hover", "background: " + (gm ? "#f1f3f4" : "#eee") + ";");
add(".pni.on", gm ? "background: #e8f0fe; color: #1967d2;" : "color: #4285f4;");
add(".pni.on .mi", gm ? "color: #1967d2;" : "color: #4285f4;");
add(".pmain", "padding: 0 " + (gm ? "20px" : "24px") + " 60px " + (gm ? "8px" : "16px") + ";");
add(".pselbar", "position: absolute; left: 0; right: 0; top: 0; height: 64px; z-index: 5; padding: 0 12px; background: " + (gm ? "#fff" : "#4285f4") + "; color: " + (gm ? "#202124" : "#fff") + "; " +
(gm ? "border-bottom: 1px solid #dadce0;" : "box-shadow: 0 1px 4px rgba(0,0,0,.3);"));
add(".pselbar .ib", gm ? "" : "color: #fff;");
add(".pselbar .ib:hover", gm ? "" : "background: rgba(255,255,255,.12);");
add(".scount", "font-size: 20px; margin-left: 12px;");
// the viewer
add(".pview", "position: fixed; inset: 0; background: #000; display: flex; flex-direction: column; z-index: 5;");
add(".pvtop", "position: absolute; left: 0; right: 0; top: 0; height: 64px; display: flex; align-items: center; padding: 0 12px; z-index: 3; background: linear-gradient(rgba(0,0,0,.5), transparent);");
add(".pvtop .ib, .pvph .ib", "color: #fff;");
add(".pvtop .ib:hover", "background: rgba(255,255,255,.12);");
add(".pvstage", "flex: 1; position: relative; display: flex; align-items: center; justify-content: center; min-height: 0;");
add(".pvstage img", "max-width: 100%; max-height: 100%;");
add(".pvarr", "position: absolute; top: 50%; transform: translateY(-50%); display: flex; color: #fff; opacity: 0; transition: opacity .15s; width: 64px; height: 64px; align-items: center; justify-content: center;" + (gm ? " border-radius: 50%;" : ""));
add(".pvstage:hover .pvarr", "opacity: .85;");
add(".pvarr:hover", "background: rgba(255,255,255,.12);");
add(".pvarr.l", "left: 12px;");
add(".pvarr.r", "right: 12px;");
add(".pvarr.off", "display: none;");
add(".pvpanel", "position: absolute; right: 0; top: 0; bottom: 0; width: 360px; background: #fff; color: #202124; z-index: 4; box-shadow: -2px 0 6px rgba(0,0,0,.3);");
add(".pvpanel[hidden]", "display: none;");
add(".pvph", "display: flex; align-items: center; gap: 16px; height: 64px; padding: 0 12px; font-size: 20px;");
add(".pvph .ib", "color: #5f6368;");
add(".pvinfo", "padding: 8px 24px;");
add(".pvinfo div", "margin: 12px 0; font-size: 14px;");
add(".pvinfo span", "display: block; color: #5f6368; font-size: 12px;");
c.push(H + ".infoopen .pvstage { margin-right: 360px; }");
// 2015-2016: Google's grey bar of those years, then the app's bar (as Drive's)
if (era === "ph15") {
add(".gtop", "display: flex; align-items: center; height: 60px; padding: 0 16px 0 24px; background: #f1f1f1; border-bottom: 1px solid #e5e5e5; flex: 0 0 auto;");
add(".gtop .glogo img", "display: block; height: 30px; width: auto;");
add(".gsrch", "margin-left: 40px; flex: 0 1 560px; display: flex;");
add(".gsrch input", "flex: 1; height: 29px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; border-right: 0; padding: 0 8px; font: 16px Arial, sans-serif; outline: none; background: #fff; color: #222;");
add(".gsrch input:focus", "border-color: #4d90fe;");
add(".gsrch .gbtn", "width: 60px; height: 29px; border: 1px solid #3079ed; background: linear-gradient(#4d90fe, #4787ed); color: #fff; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; border-radius: 0 2px 2px 0;");
add(".gsrch .gbtn svg", "fill: #fff;");
add(".gtop .kcorner", "margin-left: auto;");
add(".dbar", "display: flex; align-items: center; flex: 0 0 auto; height: 56px; padding: 0 16px 0 0; background: #fff; border-bottom: 1px solid #e0e0e0;");
add(".dbar .app", "display: flex; align-items: center; gap: 10px; width: 240px; flex: 0 0 240px; padding-left: 24px; font: 20px Roboto, Arial, sans-serif; color: #666;");
add(".dbar .app img", "width: 24px; height: 24px;");
add(".crumb", "display: flex; align-items: center; font: 18px Roboto, sans-serif; color: #202124;");
add(".crumb .cr", "display: inline-flex; align-items: center; padding: 4px 8px;");
add(".crumb .cr:hover", "background: rgba(60,64,67,.08);");
add(".pplaces", "position: fixed; z-index: 40; min-width: 200px; background: #fff; padding: 8px 0; box-shadow: 0 2px 10px rgba(0,0,0,.2);");
add(".pplaces[hidden]", "display: none;");
add(".ppl", "display: flex; align-items: center; gap: 16px; padding: 0 24px 0 16px; line-height: 36px; color: #202124; font-size: 13px; text-decoration: none;");
add(".ppl .mi", "color: #5f6368;");
add(".ppl:hover", "background: #eee;");
add(".ppl.on", "color: #4285f4;");
add(".ppl.on .mi", "color: #4285f4;");
add(".pmain", "padding: 0 32px 60px;");
add(".pselbar", "top: 60px; height: 56px;");
}
}
return c;
}
// ---- end Gplex for Google Docs ----
// ---- Gplex for Google News and Google Translate (4.4) ----------------------------
// Both take over their page the way Calendar does: Google's own page stays loaded
// underneath, out of sight, and Gplex draws the period's page over it. News reads
// the stories from Google News' own RSS feeds (and the pictures from Google's page
// for the same section); Translate asks Google's translation service directly.
function ugfNtArt() {
if (!ugfNtArt.c) {
ugfNtArt.c = {"news2005":"data:image/gif;base64,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","news2007":"data:image/gif;base64,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","news2009":"data:image/gif;base64,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","news2010":"data:image/gif;base64,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","envelope":"data:image/gif;base64,R0lGODlhEAAPAJEAAP///2ZmZgAAAAAAACH5BAAAAAAALAAAAAAQAA8AQAImhI8JcaJugpy0ToVXzgxmJyWQF1nmtaXqQn4h0DYlQpIvHd9qUAAAOw==","fav_g1999":"data:image/x-icon;base64,AAABAAEAEBAAAAAAIAAfAwAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAuZJREFUeJydk0uLW3UAR899JDeZOMk80dF0Oo4UtdgqSp2C+EDQjZUKBRe2K4sgiC5Kt4KK7lyIdtOVgogIbtSFIgMqpYLB6bSZoS9rhmHGaZNMJs+be29u7v/nIh9A8HyAszrH8k7f0fETr9OhiRcUMekW/VSOqbhKaDLgTtKkw4wTEVjjpOI2m06KgnEB4NGT19Uf1CVJsR/IaEt1GcWStvvS5sauOpJarVBRIqkvaRBK7Uh/Hl6Uu2PNY6eyREB/LEO1W+Trb2vcKv1OqWzTD2epuXUOHfR45tgSrzxuceR+h5zpYocVmD29KqNQDfX1my+9eLak6Sd+1t91qSppKOmOpD+uScWjH+vhx85qb09SV7oy4YmFUyUZbSmU9MZH1/XAkfOqRZLRlgamKQ0ThcnItHKrq1J5XYG6UtRV+aGC2Pfmbfmx9P75Dd391GdauxEpkBRqRy0FCrWpQG0pkOLBSOSrrURVrRxErtuysF3Ys8ZIJYs8UkxDEiMnjxd7tFPzWEAm8SGTQ/jYDLHjaUwtj52O9wgw/LB+GRaHmLEaWAYrzkFiUUggnwBWGseAwSYhAYkp18Vu5HMIG7cxBU1hR5PQNSjl000ZiEFOBBlIbOGYLFkEqhBl9mF7SYs0UJyeYPvGDpEzgHGPqJNj3LHxM1DDcLFSZbUes1aDlfUsxpug7VzB9uwMNrscfTIG50E+PLdG046w88AQxgi4uZrh7VOXeOm57zhx7EeWlyvI5MlZc7D/1UCSdDuUFg5fVGHqcy1fkwLFMpLUa0hDKYqly/9Is/vf05ffrMhoS5dm5mQPstsInxlvk19/WmJuZpfjz37Fp59UqA4gyaVpOT16Lmw0Yuq9q3jjPgCZXA9r9q2ybp47hGdGbzQjw5l3f+HC92tE3iSkDuDkB4T1uyjcU+WF530+OPMy92WzlBfmYenkVakzKu+/6A+SUduhpH5ffx24V27qtXd4+gL/iy/8Hf4FGW4Nq9+pMjQAAAAASUVORK5CYII=","fav_g2009":"data:image/x-icon;base64,AAABAAEAEBAAAAAAIABDAwAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAwpJREFUeJwl0strnFUYwOHfe873TSaTyW0ySRPa2GgiDUoWbUQhSANW2y68gVJcqC0I6lZddlu1GzeKm9YLbmIRUUQQgwSE2nrBW2yN0RQS0qbRGNOZdGYy35zL66L/wbN4AHBe9celVR05PqPJwx/oax/Pa1CvWfWGnp+e0t8FbRmjATRgtCHoFiiA8U7VWjh1boGVZh9x192c/uJfltcb5Do7mXz7LKWOAjZGRCxIBCCSsGJQYxMI3nP5nwjFbqK1bO+kfPj9CmDJj99FNnU/HiGagEdoqUXFoxGMRkgkYVdPHtOKGDKMWC4vexCPWAidBRwWGyFRg5VAS8EZSyLmFunIRJkLf6yTtPUSY4YxCRGLyWBjYZG1IcONzl7SFgxUavRvO5wGkiurFUZvK/H80TFmzl9l8e8qXe2RE9N7EIQzs+9w6kiTq3fux0qOECLtDcf+Kzs8fnEV2ffs+/rqift4YnqcSt3x2U9rTI12Mzrcy+nZs5z84S3sYDdEJcQAGMQJalKkZpH+Y+fUZTUOjBR4YHKQk08fBFG+XvqZQ+8eI44NQDQgIK0UAHUe8Sl4wZRsi2Iuz8WlJm/M/MXKRh1Vyx2l3YyNHoCsiYkGExIUj0RFSBFATQvjKpvsac949J4yzxwdp7IdUIHhviEuPHWGw+WDaKNGVAG1RLk1KCrgUmTmq1/1ockJ+noNvrrA1n9LNLavMzT2JPliPy54HvvoZb5cn0NzXRAsxkVisBBANKjWNudZ+vZFevmNJG2gmaHmxtl96FO6SqMsblzj3veOc7PQwnqLBiF6AQ8mi3X+nHuB25Pv2NvfZLCrQLmnjbIssPHNSyiGfeW9DHYMQOYIosQAqU8RD0mrukHRXyOf9nCz5hFviQEK7SVCcw1xdXZMB81aHSTF+BxRHEEDGhXT3jNCW/+D1Lc82iygIUciRcKOpW3oETRX5PNfZrleXUeCQUKEHUNsRYg5kjQx4mqbWpkfRquXENfAJXnaxg6Tn3iOS6vLvPLJm4TEYrKEgIAGIIXX5+R/yZB7kQeZcRMAAAAASUVORK5CYII=","fav_news2009":"data:image/x-icon;base64,AAABAAEAEBAAAAAAIAASAwAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAtlJREFUeJylk1tIUwEAhv+zc842z+Y0t3MkJpXNldnmbDNNypbVSJw3dGhkUln4GFJB0UOXFyl6K7KCQAy60YUUb7MLEVFaMBseuqgTd2nzks5L5nRz6yUiiSzof/7/7+n7gf8M8S8ljU4fA8ACwMrbbZ5/Bmh0+i0cy9bOzc8bDPoNjGNg4CspIHc3PXrQ8keARqcXAzCtXLHijFqdtNa0c4fEKI9D+EkH+rZuw7Wbt0dfve7cztttPABQvwylHMuWyRXyY0kqlSovd5cw5csogi1NmHzXDYoAkqVSWEpL2N7evhcanX41b7dNED/G2Vqt5nI8xyVX7q2gEz97MHb9OjA8BIoAZHlmSM1mCFe9R3imG/UdWjS3tj7u73eYKQCIEotbc4xGaenqVRg+cxruoSHQUglicnOxbJ8FtPAhBJN7EPG4QQCozG9AZ5ciZ25urlAAALOBgKmzq2tq3OPBwvQ0YisrwVy5gbgDYYhmTCDHzoMIuRGmEuATXUV7pxBlZRZKSAtrBYkqtUwkpIudTid9zzcE7u5dnBsx4eTVaYRCIRDhKUSIaPgiNXjQcwr1913o4Xsgi5YiPp5TUgAsCoXiaE6OkWpptSIzIwOhBQ7Wl7MYPFQNGa2DvY/Eh48DCAYHQdM0sjZlgWVZxHOchACANH16FUWSdQVFhSLnoBNHag6j+uw8NmpIHCwRoKmpEQCgULBINxjAMAzarB1oa7fO/PQgM2tzkVgsuimXs5Lionywy7WoOBFE40UaXs8nMFEMlAkJcDgceNTYHPRP+HmXy12+SKREldqoVCrb1ElJUVVV+3GhQYhsfQRb0sLw+nx4+uw5vF6vc2zcf9bv99/h7bbZ30xMz8gsl8XE3iow5wlSU7VwudzoevMWbo/HHQgE6oaHR+p4u21qyS+kGTYeZxXsOUbCRCYmJsdJUnBhZGT0Em+3fVvqO4uyZt362hSNLv9vve+s3gxN+4CXUAAAAABJRU5ErkJggg==","fav_news2012":"data:image/x-icon;base64,AAABAAEAEBAAAAAAIAAHAQAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAM5JREFUeJzFkzEKg0AQRd9uxMsIixex8AbiAdJsb2GTysYDBG/gUYSF7WztkzYgplGjxgSjRX6zw2f+nz8wK7quExyAPCIGcACMMdc9YqVU7PR1tDPAaIB7jhBSIuUJKSVieMX6lvdLDvQrADzyYleE0SDLstUGrTXW2jfe87y5AUCapmNdVRVlWc6avyYYkCQJAGEYjtzmBMsUPycYpi9hraWua3zfn9KFUuploLX+OKVtW1zXnYmDIIhhwykbY2iaZlU8NbjtEQOIv//GJ2rEQ71KdQzQAAAAAElFTkSuQmCC","fav_news2013":"data:image/x-icon;base64,AAABAAIAEBAAAAAAIAAHAQAAJgAAACAgAAAAACAASwMAAC0BAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAADOSURBVHicxZMxCoNAEEXfbsTLCIsXsfAG4gHSbG9hk8rGAwRv4FGEhe1s7ZM2IKZRo8YEo0V+s8Nn/p8/MCu6rhMcgDwiBnAAjDHXPWKlVOz0dbQzwGiAe44QUiLlCSklYnjF+pb3Sw70KwA88mJXhNEgy7LVBq011to33vO8uQFAmqZjXVUVZVnOmr8mGJAkCQBhGI7c5gTLFD8nGKYvYa2lrmt835/ShVLqZaC1/jilbVtc152JgyCIYcMpG2NommZVPDW47REDiL//xidqxEO9SnUM0AAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAAAxJJREFUeJztVsluE0EQfW04ceKU5AoSByB2JuE7IjshgROS/RkIJFvc+ACUo0d8QfgPkhk7IXhN4myebFKQOHdxmO6e3sZ2bhxS0mi6uqurXr2uXoAH+V/k/GLc1Nu6fnJ23jw5PVP64dFx8/DoWOm9wbDZ7Q+UftDpNg9+d5Te3t9vtvb2lR6391SbycbFOCEAoVCrRAQAIRGBiKrib+jc0kEU8vRv2HM5LvwBqAalInMAMKZUCAfuB4A4h3Cs+jGDnfQLABJAwV4KHYQjcswymTBjqjgASEPriOy3hnOsZ5LHemApfz+sAoyBMQYGJtoFQy8whkeMwcyfFBoDlPD95+s3B0DBtNPX1PHiTM7L/D6MeBkAAWCiaNKcpRGIpTkTWGrC9En3Fy+AJ99/ZC61qgZxcCJwLqrctwO0fuIchNR+dgCMqTVTABQQZMssAks7gtWvtp0Wjay/A0AE/9KoGyh1dvT2x0+fASJEOz+947a8fL0o4mc2/hqYIbjoAAEIVt5kS4HsALLp98WwAJinVblcBgAEQaAmxHGM7e1trS4I8e7OxCTk2KvFolOrJgBrMAgCNBoN9XcyESCWllc8xejPnqwgCgAXBiwnk0qlopio1+vCWWrbinanZg8gZUBO9DHA4JAAAEiSBFEUIYoi1Go10zERSsGywYB++RjZe1iYWIRJkijqZeA4jvXUQABa0e7U7AGxC/JqQO13bdLW1lauYyBbgtJSoNY9JWJK9rnnwIxiOCVCuxU7NsejEZ49fwHGGAoFcZFl7VDaqZO80+05COwbzWBIf2RYmXe6PYzHl1iYn3MAMMbC9cqqKiT3JIS5ppOYKZZK4AT82murvtHoFDe3tyAQFubn7ClGcIOBg07Xc99q9WpXtme9e/0BkuQSnHMQwWYg3Fgv12BJxgDn3ixtBnyBAaA/GOLy6tqw1HyEm28rTnATANEdgKcOAHU8+wEBwGAwxJUM7h6o4buNNW9wQHsREWiNE90R0oNEfkRI7/+ct+JweIjrmxuJTm0z+Sx/v7meG/xBHgQA/gFOSuKx3z9wpQAAAABJRU5ErkJggg==","fav_news2017":"data:image/x-icon;base64,AAABAAEAICAAAAAAIAA8BAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAABANJREFUeJztVk1oXFUU/s67701eEkOwan4WTiqC1kWgSMRfcOFKqIhQQRG7KS60pVu7cOdG1IA4MC7EdqO0FLUr/8C6ak1rQjErGc1L3sybl0kkIaWZxOTNu/e4mLyZ9z+TtR4Y5t5zvnO+79137n0X+M+b4zizzEwA4Lpu0bbtW0tLSzNB3Lbtc5ZlXWJmAQCWZY1alvWLZVkvBZh6vX7CcZyf1tfX7wGAhYUFw7bty47jvBVgqtXqzPLy8nXbticBgJmpWq1+QK7rslKqVCgUPvU87xoRFaWUd5RSLxLRc0T0ETNDSnkVwNvM/KOmaceJyBNCvKbrOimlLgEoSCnnDMN4eW9v74Ku6yeICEqpd5RSv2ua9gMRjUop/zIM4wXP897VNO0M1et1BgDf93d1XR/SNA3MDM/z/hFCDBIRDuKQUu4KIYY0TYNSCkqpVqFQgBDCICJIKdFqtXaFEENCCACAlBK+7+8ahjFEREHtHSHEMABQvV5nIQSUUgjIlFJg5sirYuaIj5mhlIJpmp28wBfMw3lhX4CRUkKLAwKSeJE0I6LcvDAua66HA0qpnqThWB6mV25HQLAc576+N4SK/IFjc/DBmBm/PkxQB/M4jsERX7he5amttoA4aXyaRp54qqQLnOpNmp5ornCRDPK4uN5icgRkgRLkGZYrpg8frayscLBno8DkNoz7mRmmaebi83y+70d3Qb+FeuUcxjo9cPa9SrJwhCSNjPH5h9MAgEajcSihExMTbQF5pGHiJHn6O+7XglqdFcgjTiOP2+TkZCYuy8fMoV2QUT89+TDYfF/iHAgAhk449eoUnn3ifoCBazf+xlff1mKvpDvO64E0EWNjY20BWaA3T07hoeIw3v/kDxAAc0Bk9kM/340sSzRhYM/M3IePP/sTK7UdPP/0AwCAJ4eP4ObtzW5xdFcv6Oo84rSzJFMAMwBq/08/NoqxIwUMDAjcvL3Z+3TMaTqg+9VVSrUFtIPRhOu3NnDqZBFfXK7iu58bOP36USwsbkXJQ5O1tbVMEVJKNJvNyAqMjIxASumkrgAz48urNbzxShHnzzwKIuDGb5v45ns3QdxrBXzfR61Wg+/7EQEbGxt3t7e3pzObsNVSuHjFxsUrduoTt3O64/Hx8VQhrusmyH3fb8zNzT1SLpebWrh2/Id4MEScd0KG/VLKCLmUctm27WPlcrkJZDVh5kETJ+02VrwHAkyz2eyM9/f3rcXFxcdLpdLdAKN37oF9kHaJ+7POMd++9NYcxzleKpWaYQxVKpUVTdOOpt1ms4qGx4ODg6nx4IruOA5WV1e35ufnH5ydnd2J19NbrdZpXdcvMPNUP6Rxf/gyk3GXWDVN81ga+f8GAP8CaF4B3WWvs8wAAAAASUVORK5CYII=","fav_news2018":"data:image/x-icon;base64,AAABAAEAICAAAAAAIABgBQAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAABSdJREFUeJztlluIlVUUx39rf5dzZs5xxmPqmGIDEzZWakXmJbwUUfbQSxE9lA89pA9CBRE+ZARiUBHZQxcqowsFhURF1INBmURihZNTaaOVDV4yp3G8zIxnzvftb68evnOdm9GrLdiwv73/31r/ddl7bfhfLnaRyTYXbX9oj5cNl2riAEUBVQVARTmrcCQGDHSII1PGoJrOjCEeKX17+L5tyyay4U9GYMiWCqYY4xKtEhhWpU8Fio61XsT6GX1cWzjB7b3Xsc8JraKopmgVwSa2MJmNSQkgooLgUHpVwAmdieXV1n5WX3aMQvYXsAakyGNT53DHmUs5j2O6Kj4gAkbSoPwnAocdigpYw2stZ7mt5Tjt+YOQFEFDsHlS9RluzR1i+85Wfm0P2ZQX8CjvyX8n8EJrMViV62dR80HQv0GzYH0gV9ZeHmoIc30sPfMHa7p8HmzOcmx2EwfamuieEgZbJrExpgi1e/49FHs2oNxIQEBSZ2v0H5V1AQwM90D0+nwkFyOJw1iLZww2XwCKv7qmjq5wbse7uWdf+rSBgBbvbWf/ga0kQzfhT5v23YnNJC4tpnpbjUxHzQVcDIN7PKQS14oCBRFhSc/zhG6IET8bG9/bfskHO9am0H17dhAUO9ETHOp7kWU/r2GlH49rr05nudpTcVouutk1jKscWeA7E7DnVC/zjjyPZ6cF1tpOqNRA0v81Xr4TBUPCYs9yiWfHeKy1aeN3HSlchZw2YBciGE0AMCJIHO0EMACy4tw6nKvV1HhjAuOjUzFeqsbDzti1b2MtAgDO/ojHouqNR1ogCpyNYSBSYoWcEaZnIDTppgMODCmuHAlX9t4BswKhLWy0LUCU2BMVszUCyciHhCyqhrTMvHtQ2XpLwIqrfZqzwp/9jre+itn7lyMwMGihZ1OOUtzou2eg+zfLhg8j2jI1BkZAbPJjBWcqE1k5tJkSVqR2uvYOKl+sy3LnipBCCwyfj5k312PdLYa+UqU3gLoYnG0Y6izqkqr3BohV8URgZOTzsREASNjtG1Y5hcEYnlzu0zHbY//hEgu2RWA81s4s8fEp4aqsAYW8B5nHo9qxqM93CEtyqUdGoATYxDFj9y9bxydQ5JXAY5UCp2O48cp0++53Yla0ejy83Gfm1IAHFEIfntkRM2Ch95EsUf2h0Voa9vcmbPkyRrIQKZCc+a3eZAMBWcN7P3/S/FLOUBhUJQzS9Z6ScJUoq6/xmTG1mjUKu2KOjSjtszwmktgqZxNoAWKFMDrZNSEBgJ0nl++c6nGXesKho5b2WR5vrvbZuNsy86khOJ5w5LkpzG3z+fSkY3FekIdOAzL2dvTg8lbD5TmPgfJF1fw9709K4O2+eccvbYJCAE98HnPzdQH3r8lwdbvHn6ccN3T6zJ5u2NU1wmWhMOJg9/p8YwpIc37weMIbPySopukoqRdJxEeTEihIYlQFQcn7wtoXhtl6X4Yb5odVzDfd57n7Y8f1eeF0BMsXBOOGf850w9PfWvJNQgY40zTnwGjMGAKO2jEMDAzEhmUvRyxsKnJFQfjsmJILfBbn07bYEsCj285hXaMeAf4aFtqzBgUyCl+0Ld17QQJQu4gqgAXNglWfnwagI9/YkT2Brv60CKu/aW3PSO3793BK8V9FoE5HVUxFWT3JsoSm8b5XqdNRhwsSN+b9MYaAKkYZ5yE3wcOqwfDo9YZGJGmzvRCBuBgdbQozyOiteq9GLWu5c1WjreW5VF48KbJUio6O78b/cjHLP5ecYNAEfomiAAAAAElFTkSuQmCC","fav_news2019":"data:image/x-icon;base64,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","fav_news2020":"data:image/x-icon;base64,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","fav_tr2010":"data:image/x-icon;base64,AAABAAEAEBAAAAAAIABVAgAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAhxJREFUeJx9k8trE2EUxX+TTmszYlpHYjFRaXxRYhdCyaZgcVsQRbA0oJtCaUA3rYL/QaGbLlypq9KF0LhQKhQXokITE1wIKljwEaslj1J14jSPaTJJxsUwk4wkntX3Oufec+/9BIBy8adBCzStaK9reoUB35BAB7j+JccTcR4/XXM8ymU+Ot60QgR4GI3ybXMTgEw2B2DvAW7OTHXimwIWMtkcft8Rh5C17wTBsvB+Y4N79x8wd2sWr0difmmNfeN3mjb2oFQpk9Yltgo6AMpkjyBaBTsTOA7Ao5UoJwIBAhenydb/Gxw5WjVcrQfXwxNksjlirxNk67Ij+owvw1wgz9HucvsaqLt5Xq3HHSQLI/sVhqUiDaPOmOwmoXQDoKk7iDW9QlbZJbQkE5u8ROGPgtfnZ0ExPQOM+DQAtvMlrvb/YIFhW9wFEFoy0z0f9RMcOo3XI/GpCGldAiDoVomnNZ5XTgIwKuto6o4p4F90dJLBu710dTUHb0zeo143+KDAutILwFTfZ/teABBvf7UnrbZ4ShDCq8bBK+MAvDj7Dq9HoqpXbZKq1bj29jCpX6ppoaGaQ9NQc7imYwZA/skzRmWdPrfIm22dSFIkkhRZ/mJmNzGQb2ZgkQCMouKwlJo/RiQpEi832/ryXAqAC7F+bLPtRHpCg+bdgUM2uVH47QjQ9psK4VXDWLksBJe/G6Wq8yMaumavt24Ehb+waeCmMz31bwAAAABJRU5ErkJggg==","fav_tr2012":"data:image/x-icon;base64,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","fav_tr2015":"data:image/x-icon;base64,AAABAAIAEBAAAAAAIABvAgAAJgAAACAgAAAAACAAZQUAAJUCAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAI2SURBVHicfZLNS5RRFMZ/933v63zpKGobNTQrP8AQLagsylpW0Er/CymQ/oT+ADNaRRs3tXBhtAhidFVE0UIsTCoT/MgBHcnRmWbmvfe0eN8ZJ6R54HDv5d7nOfec5yiAiZmdjlLWSwD4GiFEe1NyDShSA2piZqdjOxNbFwEBqlebP7wPTNUScEpZL1EhVV0IYNzIpHEj1ApdfizhppwdQHv65N2+jRfX+6LLSikBxFoLIL5vMr293U+0rxEpHGUdOW2xAu++OwiwutswPuqUiMfqEJFKgMf8/OfXzj8/AM53WoY7DSo8r+wmyOxlKRaLIfEIxWJeBwICVuBcm+XrtsO3tEt/m0UE8kaz/Msjl8uT+rB4rInaN0fCV8/aSv1dLbC06YDAmy9/2FhfRGuXqeevaGlq4M6VC4EL5RIaY4JS8HhBM72gcR1IxoK7A7eL+niCWyND1EfrGLtxmWQiFgj4RkQE9nKKqZSuuDGd0vzOgYiQNy4F1cHTuRQXB3owxscYg7UiTslERCS0TqqsJCCXBZfScdpam1ndTAc9C+zEoVCgiosNbbJVZAEyfjujw4M0JxN8WvmBiFAqlZTue9D48/3DrXuqyInq7losrXHp9TwZs8aCo1hLGwbPdAYzE3ZbD829tUMDPDrmT4hnLw/93L5xr11K0NPeCoBSwZRYa0WXa/kf+k9FZ+tjjN++2YTnqUrmYCJjWTU7+7GmwH7zQVRvmG6trQB4nifGWDEmkgW2/gJrUjMXwrnoxQAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAABSxJREFUeJzFlltsFFUYx3/nzM70sq0FtKXcyq1QQCBFsRZLaLlEDA8mEtTESyT4wIPBaHzjSR9MfFGeIT5oog8CicbEhBDUGFqBoHKXWxtKS4BKhXbb7na3M+fzYXe2OztTREriP9nuN2en5///Luf7DvzPUL6xfd/QhnRGtSBi+WvGGABEKfHt7IIWcE8ffH/a949EwPZ9QxtGUvpHAJEcR+7jP/i2+LY3NurMrao48IryJiNAA6QzqqVwUaLfDcKyS7nU1TgZ8rwARCyRce8DuI+apBXf8UgEiBjlc+VDHaWlcFHAskvffnn/eM08DGIF+xGy5T6/AcpySpaN9Ozq6Lh0aMqUmAfgOE5IezqdztuO40hn54UbW7ZsSecFGGPCHheRR6VHgIQp21NdI3sqK0rQWiO5F0Ukb8fjsfwawMqVK9NHjpydu2nTyj4duWsR+ao6w6o6E4oMQPdAGTfvDJHJuGGFE0ApVVJTU/IG+DWgtATP3bg5e6qwa4PLuxtdZlZJSJwrmot9ZQwOJshkMgFP74cxj8q8AD8FhZ/sRtDW4NF7T9FzT9HWEDzyPs+fdyoYcw1DQ8O47oNFwm9soRT4x1EEHEtYs9DQftWi46pFS70hZoVPSE8iTiIliEAymYwUURwVXfRNcR8QoGmBYFtwrEtzrEtTYsPqeSbgvQAemot95XieYIwhmUxy5mo3F6/d+NdIaAAlSqJS0NZgONurSaQgkYIzvZr1DV6A3DeyafAwJrt69nIX57quR5IWRiMW/Ua2+BZWZ739Ykcm8POMKuHmoAqo6B4o57P9R7CtNFqBP+cuXOtFKZWbIcKrG1tYOm9WUIAxpmAuZtHa4JEYhS9/jQWI3mpxWb/E8PUJK3gitMWi+laW194lFtNYlgaEVGaMwyfP0/rUMmqnTWV2zbQAT2QntLXwXL2h/Yrmt24dqI3F0zVr6z2+OWnhFs3Bfm8mInepLC9hTm01AMfOX8HRijVPLqastGTCYgygab4Qd+DoVSs0nts7LSpK4Zl5pujICtcH43TdHGD/T8cZSY0ynBrl2PkrPL1kAYjB88KTO5sCpQPC2js17Z1OKDIIdPcr3vzcCc6H3D+7KEqnriDWd4MfOn5HBOIlDmtWNACQyWRwHAetx/2esBEVX0iiumRhv/fXrtytYnNzI503bnPtVh8vrmvCjlnjIl2XwttVZAoCpBJeKvQ6ECWBnsFyTl2+hdIWKDjX1R0aZJ7n4brZK0AsvEtYR+A5irjgwUVz7nYZr7WsxnE03/5yAjGwubkRpVR+D5NrGLp4j8gUEAx3sdfFA6qiehV1059gwczpbG1r5nRnN4eOnwqMah9+J0xG34AkkjhqLBcOsL9Gp5JICkZg0ZwZvNTazKXrtxgYTkYfQ2dk4CtvbCxVSBhFOpHXxZcWF82FvnI81yAiLJ5Tyztbn2dKRXlIQAzgwEfzb2/7tOfx0f7k3GQmqXGciHiEsbQy/frwiNntGi+gTgB3yEGkFL/F2nYMEcnXQUAAwMEP6lLApQdizqF+794Pb52ZtTvfESX7Z11TJWuXl2NZOUE5cUHyCe4D/wX7du4cW74o/odWGq00Wivamh9jy4YqSstsLGu86gsRKsLJYEpV7GNQiAjrmip4oa0K27ZQSG4KRpO7BveRCPCG136ntaH12TibWyuxbY2lFUoV9Yyiwr7z98hRCA3hh8Mnew6/17i0vMbzUE6pZbQ2eSbbtg0GjAGllIgor79/+Oi2bW0/PwruSeMfi/jLyBM7+6wAAAAASUVORK5CYII=","fav_tr2015s":"data:image/x-icon;base64,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","fav_tr2017":"data:image/x-icon;base64,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","tlogo2006":"data:image/gif;base64,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","tlogo2008":"data:image/gif;base64,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","tlogo2010":"data:image/gif;base64,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","tbuttons":"data:image/gif;base64,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","glogoSvg":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3NCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDc0IDI0Ij48cGF0aCBmaWxsPSIjNDI4NUY0IiBkPSJNOS4yNCA4LjE5djIuNDZoNS44OGMtLjE4IDEuMzgtLjY0IDIuMzktMS4zNCAzLjEtLjg2Ljg2LTIuMiAxLjgtNC41NCAxLjgtMy42MiAwLTYuNDUtMi45Mi02LjQ1LTYuNTRzMi44My02LjU0IDYuNDUtNi41NGMxLjk1IDAgMy4zOC43NyA0LjQzIDEuNzZMMTUuNCAyLjVDMTMuOTQgMS4wOCAxMS45OCAwIDkuMjQgMCA0LjI4IDAgLjExIDQuMDQuMTEgOXM0LjE3IDkgOS4xMyA5YzIuNjggMCA0LjctLjg4IDYuMjgtMi41MiAxLjYyLTEuNjIgMi4xMy0zLjkxIDIuMTMtNS43NSAwLS41Ny0uMDQtMS4xLS4xMy0xLjU0SDkuMjR6Ii8+PHBhdGggZmlsbD0iI0VBNDMzNSIgZD0iTTI1IDYuMTljLTMuMjEgMC01LjgzIDIuNDQtNS44MyA1LjgxIDAgMy4zNCAyLjYyIDUuODEgNS44MyA1LjgxczUuODMtMi40NiA1LjgzLTUuODFjMC0zLjM3LTIuNjItNS44MS01LjgzLTUuODF6bTAgOS4zM2MtMS43NiAwLTMuMjgtMS40NS0zLjI4LTMuNTIgMC0yLjA5IDEuNTItMy41MiAzLjI4LTMuNTJzMy4yOCAxLjQzIDMuMjggMy41MmMwIDIuMDctMS41MiAzLjUyLTMuMjggMy41MnoiLz48cGF0aCBmaWxsPSIjNDI4NUY0IiBkPSJNNTMuNTggNy40OWgtLjA5Yy0uNTctLjY4LTEuNjctMS4zLTMuMDYtMS4zQzQ3LjUzIDYuMTkgNDUgOC43MiA0NSAxMmMwIDMuMjYgMi41MyA1LjgxIDUuNDMgNS44MSAxLjM5IDAgMi40OS0uNjIgMy4wNi0xLjMyaC4wOXYuODFjMCAyLjIyLTEuMTkgMy40MS0zLjEgMy40MS0xLjU2IDAtMi41My0xLjEyLTIuOTMtMi4wN2wtMi4yMi45MmMuNjQgMS41NCAyLjMzIDMuNDMgNS4xNSAzLjQzIDIuOTkgMCA1LjUyLTEuNzYgNS41Mi02LjA1VjYuNDloLTIuNDJ2MXptLTIuOTMgOC4wM2MtMS43NiAwLTMuMS0xLjUtMy4xLTMuNTIgMC0yLjA1IDEuMzQtMy41MiAzLjEtMy41MiAxLjc0IDAgMy4xIDEuNSAzLjEgMy41NC4wMSAyLjAzLTEuMzYgMy41LTMuMSAzLjV6Ii8+PHBhdGggZmlsbD0iI0ZCQkMwNSIgZD0iTTM4IDYuMTljLTMuMjEgMC01LjgzIDIuNDQtNS44MyA1LjgxIDAgMy4zNCAyLjYyIDUuODEgNS44MyA1LjgxczUuODMtMi40NiA1LjgzLTUuODFjMC0zLjM3LTIuNjItNS44MS01LjgzLTUuODF6bTAgOS4zM2MtMS43NiAwLTMuMjgtMS40NS0zLjI4LTMuNTIgMC0yLjA5IDEuNTItMy41MiAzLjI4LTMuNTJzMy4yOCAxLjQzIDMuMjggMy41MmMwIDIuMDctMS41MiAzLjUyLTMuMjggMy41MnoiLz48cGF0aCBmaWxsPSIjMzRBODUzIiBkPSJNNTggLjI0aDIuNTF2MTcuNTdINTh6Ii8+PHBhdGggZmlsbD0iI0VBNDMzNSIgZD0iTTY4LjI2IDE1LjUyYy0xLjMgMC0yLjIyLS41OS0yLjgyLTEuNzZsNy43Ny0zLjIxLS4yNi0uNjZjLS40OC0xLjMtMS45Ni0zLjctNC45Ny0zLjctMi45OSAwLTUuNDggMi4zNS01LjQ4IDUuODEgMCAzLjI2IDIuNDYgNS44MSA1Ljc2IDUuODEgMi42NiAwIDQuMi0xLjYzIDQuODQtMi41N2wtMS45OC0xLjMyYy0uNjYuOTYtMS41NiAxLjYtMi44NiAxLjZ6bS0uMTgtNy4xNWMxLjAzIDAgMS45MS41MyAyLjIgMS4yOGwtNS4yNSAyLjE3YzAtMi40NCAxLjczLTMuNDUgMy4wNS0zLjQ1eiIvPjwvc3ZnPg==","glogo92":"data:image/png;base64,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","translate24":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAADFUlEQVR4AWKgC0gC9E5OXW6FUQDtc41/VI89UxvvtcZVXNu2jbEV28nYNze3j+f0npV8cY271o6z9/10IZBddOILX3hcAKLgmAD5YfIIlQC5IjtuDE77rUDxCYErOiHAjwLFR0eyfivAxHEBJmcBQsG///1ARE4k3z2RoxRgg8Qy45cDTJooz1cJSOQpBcwNo3jcjy5XHwwODcFQmMHBQRgYGIjQ398fcDo96XGB/BjywjB5JKAQcMOZcexRm0XpdwP0PBkJJIrLH/HQY+dwYGQC1fZJLH/ARwI5Ii8/m8FstlOE5EScnBEJkJRR9pCH8fEJfNIawMPPeHjYzOG+e3xEThy560W1xgQOp4vJvx+ghWTQnb/o4JAtKrtzFsiWC7ju1Dh2dOrBYrGBy+X6cYBkjIHhCVS85IHk12oDMD4xgYTeOUlyArNEXnw2gU5vBpvNDpsrZJgY6OvriwZIxmAjyKYteSEIO+8Eod0yiZ+1XESeKROwsLwG1+2V4IbSo7ipTIKbK+S4tVqFW6pUmBQgGaP0QWgNHotrcOgpD3cbOaT3++7ymEUBWYi1J8fx2oOX0NrZDQ6HA6SXbuOzj7WpR5CtECCWA2Kk28bhwHBoF1WKuypWnhlGefUz7FVdxLd1jbBdcgrtdjt4vV6SxweyRGkqMuVREuUZ0iAeuuPBUuUl3FAmwfqWTnA6nbToLJI6wISMjDCJ8nSRVcdHcGupCndITuPZe4+RAoTb7Qa/3x8NpJDGIwtBYiYn0iRBPH6jFrrUeig9fgHP3XmMLODz+WIDQS6VlJHOSJATh257UaMxgt5ghNKTF/FjQ0tyIOfoSFaaNBhMl/LASIthqSREmoTHtKMBApeGWX1iFLVaI50H2k1x6zDlV6+9ez/NW1T0GhcWvSJwQeErPKRsQIPBDLSDCIr8doCuLbvqBxcWv0WiWlGPPWoDmMwWcQS2uIDH4/m9wGF5865FJW+xSl6PnZ1a0OmMYI4PsAj3W4GKipa51fJabG9Xg1qtA4NBHIHJBBaLBaxWKz0TfEODOnfK/7i+AovHxWW/Lj+SAAAAAElFTkSuQmCC","mi":{"language":" ","language_o":" ","flag":" ","flag_o":" ","business":" ","business_o":" ","memory":" ","memory_o":" ","local_movies":" ","local_movies_o":" ","directions_bike":" ","directions_bike_o":" ","science":" ","science_o":" ","fitness_center":" ","fitness_center_o":" ","view_headline":" ","view_headline_o":" ","public":" ","public_o":" ","location_on":" ","location_on_o":" ","star":" ","star_o":" ","person":" ","person_o":" ","search":" ","search_o":" ","apps":" ","apps_o":" ","settings":" ","settings_o":" ","menu":" ","menu_o":" ","edit":" ","edit_o":" ","arrow_forward":" ","arrow_forward_o":" ","expand_less":" ","expand_less_o":" ","expand_more":" ","expand_more_o":" ","history":" ","history_o":" ","mic":" ","mic_o":" ","volume_up":" ","volume_up_o":" ","content_copy":" ","content_copy_o":" ","swap_horiz":" ","swap_horiz_o":" ","translate":" ","translate_o":" ","description":" ","description_o":" ","image":" ","image_o":" ","close":" ","close_o":" ","keyboard_arrow_down":" ","keyboard_arrow_down_o":" ","chrome_reader_mode":" ","chrome_reader_mode_o":" ","article":" ","article_o":" ","star_border":" ","star_border_o":" ","person_outline":" ","person_outline_o":" ","clear":" ","clear_o":" ","thumbs_up_down":" ","thumbs_up_down_o":" ","share":" ","share_o":" ","arrow_drop_down":" ","arrow_drop_down_o":" ","check":" ","check_o":" ","notifications":" ","notifications_o":" ","view_module":" ","view_list":" ","sort_by_alpha":" ","folder":" ","folder_open":" ","more_vert":" ","add":" ","arrow_back":" "}};
}
return ugfNtArt.c;
}
function ugfNtEsc(s) {
return String(s === undefined || s === null ? "" : s).replace(/[&<>"']/g, function(c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
function ugfNtIcon(n, size) {
let svg = ugfNtArt().mi[n] || "";
if (size) {
svg = svg.replace(/(]*?)\s(width|height)="\d+"/g, "$1").replace("' + svg + "";
}
// Gplex for News / for Translate switched on (the default) in Gplex's settings
function ugfNtOn(key) {
try {
return String((typeof GM_getValue === "function" ? GM_getValue(key, null) : null) || "true") !== "false";
} catch (e) {
return true;
}
}
function ugfNtTopFrame() {
try {
return window.top === window.self;
} catch (e) {
return false;
}
}
// "53 minutes ago" (2005-2016), "57m ago" (2017-2018), "1 hour ago" (2019 on)
function ugfNtAgo(d, style) {
if (!d || isNaN(d)) {
return "";
}
const s = Math.max(0, (Date.now() - d.getTime()) / 1000);
const m = Math.round(s / 60);
const h = Math.floor(s / 3600);
const mon = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
if (style === "short") {
if (m < 60) {
return Math.max(1, m) + "m ago";
}
if (h < 24) {
return h + "h ago";
}
return Math.floor(h / 24) + "d ago";
}
if (style === "gm") {
if (m < 60) {
return Math.max(1, m) + (m === 1 ? " minute ago" : " minutes ago");
}
if (h < 24) {
return h + (h === 1 ? " hour ago" : " hours ago");
}
if (h < 48) {
return "Yesterday";
}
return Math.floor(h / 24) + " days ago";
}
if (m < 60) {
return Math.max(1, m) + (m === 1 ? " minute ago" : " minutes ago");
}
if (h < 24) {
return h + (h === 1 ? " hour ago" : " hours ago");
}
return mon[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear();
}
// ---- the Google bar, by period ----------------------------------------------------
// "classic": the blue links of 2006-2010; "dark": the black bar of 2011-2016.
// here: the product in bold ("News", "Translate")
function ugfNtGbar(kind, here, era) {
const esc = ugfNtEsc;
const who = ugfCalWho();
const signedIn = !!(who.name || who.email);
if (kind === "classic") {
let apps;
if (era === "2007") {
apps = [["Web", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Video", "https://www.youtube.com/"],
["News", "https://news.google.com/"], ["Maps", "https://www.google.com/maps"], ["Gmail", "https://mail.google.com/"],
[ugfDocsLabel(), "https://docs.google.com/document/"]];
} else if (era === "2009") {
apps = [["Web", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Video", "https://www.youtube.com/"],
["Maps", "https://www.google.com/maps"], ["News", "https://news.google.com/"], ["Shopping", "https://www.google.com/shopping"],
["Gmail", "https://mail.google.com/"], [ugfDocsLabel(), "https://docs.google.com/document/"]];
} else {
apps = [["Web", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Videos", "https://www.youtube.com/"],
["Maps", "https://www.google.com/maps"], ["News", "https://news.google.com/"], ["Shopping", "https://www.google.com/shopping"],
["Gmail", "https://mail.google.com/"], [ugfDocsLabel(), "https://docs.google.com/document/"]];
}
let left = "";
apps.forEach(function(a) {
left += a[0] === here ? "" + esc(a[0]) + " " : '' + esc(a[0]) + " ";
});
left += 'more ▼ ';
let right = "";
if (here === "Translate") {
right = 'Help ';
} else if (signedIn) {
right = '' + esc(who.email || who.name) + " | " + (era === "2010" ? 'Settings ▾ | ' : 'My Account | ') +
'Sign out ';
} else {
right = (era === "2010" ? 'Settings ▾ | ' : "") + 'Sign in ';
}
return '' + left + '
' + right + "
";
}
// the black bar
const l = String(layout || "");
const late = ["2014", "2015", "2015L", "2016", "2016C", "2016L", "2017", "2018", "2018M"].indexOf(l) > -1;
const plusBar = ugfNtPlusBar();
const apps = [["Search", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Maps", "https://www.google.com/maps"],
["Play", "https://play.google.com/"], ["YouTube", "https://www.youtube.com/"], ["News", "https://news.google.com/"],
["Gmail", "https://mail.google.com/"], [ugfDocsLabel(), "https://docs.google.com/document/"]].concat(late || plusBar || !ugfDocsInGbar() ? [["Drive", "https://drive.google.com/"]] : []).filter(ugfDvGbarKeep);
if (plusBar) {
apps.push(["Calendar", "https://calendar.google.com/"]);
}
let links = plusBar ? '+' + esc(signedIn ? ugfGmailPlusName() : "You") + " " : "";
apps.forEach(function(a) {
links += '' + esc(a[0]) + " ";
});
links += 'More ▾ ';
// the +You bar has nothing on the right: the account sits in the header
const right = plusBar ? "" : (signedIn ? '' + esc(who.first || who.name || who.email) + " "
: 'Sign in ') +
'' + ugfNtIcon("settings", 16) + " ";
return '' + links + '
' + right + "
";
}
// The Google bar arrived in 2007; in late 2012 and 2013 it was the +You bar, and 2014 on had none
// (bold links, +Name first); the legacy (old browser) layouts kept the older one
function ugfNtHasGbar() {
return ["2007", "2009", "2009L", "2010", "2010N", "2011", "2012", "2013", "2013L", "2015L", "2016L"].indexOf(String(layout || "")) > -1;
}
function ugfNtPlusBar() {
return String(layout || "") === "2013";
}
// the right of the grey header: +Name, the count, Share and the photo (late 2012 to
// 2014), the app grid, bell and photo (2015-2018 and 2016 on), or nothing (the name
// is on the bar)
function ugfNtHeadCorner() {
const l = String(layout || "");
const who = ugfCalWho();
if (l === "2013" || l === "2014") {
if (!(who.name || who.email)) {
return '";
}
return '';
}
if (ugfNtHasGbar() && !ugfNtPlusBar()) {
return "";
}
return ugfNtKCorner();
}
// 2014-2018 without the bar: the app grid, the bell and the round photo in the
// grey header (or a blue Sign in)
function ugfNtKCorner() {
const who = ugfCalWho();
return '";
}
// the corner of the Material pages: app grid and round photo (or a blue Sign in)
function ugfNtCorner() {
const who = ugfCalWho();
return '' + ugfNtIcon("apps", 24) + " " +
(who.name || who.email ? '' + ugfGmailAvatar() + " "
: 'Sign in ');
}
// the account and apps menus Gmail, Maps and Calendar already use
// Docs in the Google bar: "Documents", and "Docs" on the Late 2012-2013 +You bar
// Drive came out in April 2012: the bars of the layouts before it leave it out. From
// then until 2014 Docs lived inside Drive, and the bar of Late 2012-2013 had Drive only.
function ugfDriveYet() {
return ["2007", "2009", "2009L", "2010", "2010N", "2011", "2012"].indexOf(String(layout || "")) < 0;
}
function ugfDocsInGbar() {
return ["2013", "2013L"].indexOf(String(layout || "")) < 0;
}
function ugfDvGbarKeep(a) {
const n = typeof a === "string" ? a : (a && a[0]);
if (n === "Drive") {
return ugfDriveYet();
}
if ((n === "Docs" || n === "Documents") && !ugfDocsInGbar()) {
return false;
}
return true;
}
// the item of the bar lit on the Docs, Sheets, Slides and Forms pages
function ugfDocsHere() {
return ugfDocsInGbar() ? ugfDocsLabel() : "Drive";
}
function ugfDocsLabel() {
return String(layout || "") === "2013" ? "Docs" : "Documents";
}
function ugfMenusRounded() {
return ["2019", "2022"].indexOf(String(layout || "")) > -1;
}
function ugfNtMenus(shell, material) {
// the rounded menus came with the 2019 redesign; every earlier layout had the square ones
const chrome = ugfMenusRounded() ? "m2018" : "m2013";
shell.querySelectorAll(".me, .ugf-nt-gbar .who").forEach(function(el) {
el.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
ugfGmailAccountMenu(el, chrome);
});
});
shell.querySelectorAll(".apps").forEach(function(el) {
el.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
ugfGmailAppsMenu(el, chrome);
});
});
}
// common frame rules: Google's own page hidden underneath ours
function ugfNtBaseCss(id) {
return [
'html[gplex-nt] body > *:not(#' + id + '):not(#ugf-nt-styles):not(#ugf-gmail-accmenu):not(#ugf-gmail-appsmenu):not(#ugf-gmail-accfence):not(script):not(style) { visibility: hidden !important; pointer-events: none !important; }',
'html[gplex-nt], html[gplex-nt] body { overflow: hidden !important; background: #fff !important; }',
'html[gplex-nt] #ugf-gmail-accfence { z-index: 2147483600 !important; }',
'html[gplex-nt] #ugf-gmail-accmenu, html[gplex-nt] #ugf-gmail-appsmenu { z-index: 2147483601 !important; text-align: left; }',
'html[gplex-nt] #ugf-gmail-accmenu a, html[gplex-nt] #ugf-gmail-appsmenu a { text-decoration: none; }',
ugfMapsMenuCss(),
'#' + id + ' { position: fixed; inset: 0; z-index: 2147483000; background: #fff; color: #000; font: 13px arial, sans-serif; overflow: auto; text-align: left; visibility: visible; }',
'#' + id + ' * { box-sizing: border-box; }',
'#' + id + ' .mi { display: inline-flex; font-style: normal; } #' + id + ' .mi svg { display: block; fill: currentColor; }',
// the Google bar
'#' + id + ' .ugf-nt-gbar.classic { display: flex; justify-content: space-between; padding: 3px 8px 0 8px; height: 25px; font-size: 13px; border-bottom: 1px solid #c9d7f1; }',
'#' + id + ' .ugf-nt-gbar.classic .left > * { margin-right: 8px; } #' + id + ' .ugf-nt-gbar.classic a { color: #00c; }',
'#' + id + ' .ugf-nt-gbar.classic .more small { font-size: 9px; }',
'#' + id + ' .ugf-nt-gbar.dark { display: flex; justify-content: space-between; align-items: center; background: #2d2d2d; height: 30px; padding: 0 0 0 10px; color: #ccc; }',
'#' + id + ' .ugf-nt-gbar.dark .left, #' + id + ' .ugf-nt-gbar.dark .right { display: flex; align-items: center; height: 30px; }',
'#' + id + ' .ugf-nt-gbar.dark .left a { color: #ccc; line-height: 27px; height: 30px; border-top: 3px solid transparent; text-decoration: none; font-size: 13px; padding: 0 6px; margin-right: 0; }',
'#' + id + ' .ugf-nt-gbar.dark .left a:hover { color: #fff; background: #4c4c4c; }',
'#' + id + ' .ugf-nt-gbar.dark .left a.here { color: #fff; font-weight: bold; border-top-color: #dd4b39; }',
'#' + id + ' .ugf-nt-gbar.dark .right a { color: #ccc; text-decoration: none; font-weight: bold; padding: 0 10px; line-height: 30px; }',
'#' + id + ' .ugf-nt-gbar.dark .right .gear { display: inline-flex; align-items: center; border-left: 1px solid #555; height: 22px; } #' + id + ' .ugf-nt-gbar.dark .gear svg { fill: #ccc; }',
// the Material corner
'#' + id + ' .ib { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; color: #5f6368; }',
'#' + id + ' .ib:hover { background: rgba(60,64,67,.08); }',
'#' + id + ' .me { display: inline-flex; margin: 0 8px 0 4px; } #' + id + ' .me .pfp { width: 32px; height: 32px; border-radius: 50%; display: block; object-fit: cover; }',
'#' + id + ' .me .pfp.letter { background: #c62828; color: #fff; display: flex; align-items: center; justify-content: center; font: 16px Roboto, arial, sans-serif; text-transform: uppercase; }',
// the +You bar: bold grey links, the current one white, no red mark
'#' + id + ' .ugf-nt-gbar.dark.plus { padding-left: 4px; height: 29px; }',
'#' + id + ' .ugf-nt-gbar.dark.plus .left a { font-weight: bold; color: #bbb; border-top: 0; line-height: 29px; height: 29px; padding: 0 9px; }',
'#' + id + ' .ugf-nt-gbar.dark.plus .left a:hover { background: transparent; color: #fff; } #' + id + ' .ugf-nt-gbar.dark.plus .left a.here { color: #fff; }',
// +Name, the count, Share and the photo
'#' + id + ' .kcorner.gplus { gap: 15px; font: 13px arial, sans-serif; }',
'#' + id + ' .kcorner .plusname { color: #666 !important; text-decoration: none; }',
'#' + id + ' .kcorner .nbox { min-width: 27px; height: 27px; border: 1px solid #c6c6c6; border-radius: 2px; background: linear-gradient(#f8f8f8, #ececec); color: #999; font: bold 14px arial, sans-serif; display: inline-flex; align-items: center; justify-content: center; padding: 0 8px; }',
'#' + id + ' .kcorner .sharebtn { height: 27px; border: 1px solid #c6c6c6; border-radius: 2px; background: linear-gradient(#f8f8f8, #ececec); color: #666; display: inline-flex; align-items: center; gap: 8px; padding: 0 12px; cursor: pointer; }',
'#' + id + ' .kcorner .sharebtn b { font-size: 16px; font-weight: normal; color: #999; }',
'#' + id + ' .kcorner .pfpwrap { display: inline-flex; align-items: center; gap: 4px; margin: 0; }',
'#' + id + ' .kcorner .pfpwrap .pfp { width: 27px; height: 27px; border: 1px solid #c6c6c6; border-radius: 2px; }',
'#' + id + ' .kcorner .pfpwrap .car { font-style: normal; color: #777; font-size: 9px; }',
'#' + id + ' .ksignin.red { border-color: #b0281a; background: linear-gradient(#dd4b39, #d14836); font-size: 11px; }',
'#' + id + ' .kcorner { margin-left: auto; display: flex; align-items: center; gap: 14px; }',
'#' + id + ' .kcorner .kic { display: inline-flex; color: #666 !important; } #' + id + ' .kcorner .kic svg { width: 22px; height: 22px; }',
'#' + id + ' .kcorner .me { margin: 0; }',
'#' + id + ' .ksignin { display: inline-flex; align-items: center; height: 30px; padding: 0 12px; border: 1px solid #3079ed; border-radius: 2px; background: linear-gradient(#4d90fe, #4787ed); color: #fff !important; font: bold 13px arial, sans-serif; text-decoration: none !important; }',
'#' + id + ' .signin2 { display: inline-flex; align-items: center; height: 36px; padding: 0 24px; margin: 0 8px; border-radius: 4px; background: #1a73e8; color: #fff; font: 500 14px "Google Sans", Roboto, arial, sans-serif; text-decoration: none; }'
];
}
// ---- Google News ----------------------------------------------------------------
function ugfNewsWanted() {
if (window.location.host !== "news.google.com" || !ugfNtTopFrame()) {
return false;
}
const p = window.location.pathname || "/";
// the front page, the sections and search; stories, publishers and settings stay Google's
if (!/^\/($|home|topstories|foryou|headlines|topics\/|search)/.test(p)) {
return false;
}
return ugfNtOn("UGF_NEWS_ON");
}
function ugfNewsEra() {
const l = String(layout || "2015");
if (l === "2019" || l === "2022") {
return "n2019";
}
if (l === "2017" || l === "2018" || l === "2018M") {
return "n2017";
}
if (["2011", "2012", "2013", "2013L", "2014", "2015", "2015L", "2016", "2016C", "2016L"].indexOf(l) > -1) {
return "n2012";
}
if (l === "2010" || l === "2010N") {
return "n2010";
}
if (l === "2009" || l === "2009L") {
return "n2009";
}
if (l === "2006" || l === "2007") {
return "n2007";
}
return "n2005";
}
// the edition: Google News' own hl / gl / ceid, from the address or the U.S. one
function ugfNewsLoc() {
const q = new URLSearchParams(window.location.search);
const hl = q.get("hl") || "en-US";
const gl = q.get("gl") || "US";
const ceid = q.get("ceid") || (gl + ":" + hl.split("-")[0]);
return { hl: hl, gl: gl, ceid: ceid };
}
function ugfNewsQs() {
const l = ugfNewsLoc();
return "hl=" + encodeURIComponent(l.hl) + "&gl=" + encodeURIComponent(l.gl) + "&ceid=" + encodeURIComponent(l.ceid);
}
function ugfNewsEditions() {
return [["U.S.", "en-US", "US", "US:en"], ["U.K.", "en-GB", "GB", "GB:en"], ["Canada English", "en-CA", "CA", "CA:en"],
["Australia", "en-AU", "AU", "AU:en"], ["India", "en-IN", "IN", "IN:en"], ["Ireland", "en-IE", "IE", "IE:en"],
["New Zealand", "en-NZ", "NZ", "NZ:en"], ["South Africa", "en-ZA", "ZA", "ZA:en"]];
}
function ugfNewsEditionName() {
const l = ugfNewsLoc();
const e = ugfNewsEditions().filter(function(x) {
return x[2] === l.gl;
})[0];
return e ? e[0] : l.gl;
}
// the sections each period listed, with Google News' own section colours of 2009
function ugfNewsSections(era) {
const tech = era === "n2005" || era === "n2007" || era === "n2009" || era === "n2010" ? "Sci/Tech" : "Technology";
const s = {
top: { key: "top", label: era === "n2019" ? "Top stories" : "Top Stories", c: "#6b90da", b: "#ebeff9", icon: era === "n2019" ? "public_o" : "chrome_reader_mode_o" },
WORLD: { key: "WORLD", label: "World", c: "#ffc300", b: "#fff7db", icon: era === "n2019" ? "language_o" : "language" },
NATION: { key: "NATION", label: "U.S.", c: "#3c3ca4", b: "#eeeef9", icon: era === "n2019" ? "flag_o" : "flag" },
BUSINESS: { key: "BUSINESS", label: "Business", c: "#007300", b: "#eaf7ea", icon: era === "n2019" ? "business_o" : "business" },
TECHNOLOGY: { key: "TECHNOLOGY", label: tech, c: "#c00", b: "#ffeeee", icon: era === "n2019" ? "memory_o" : "memory" },
ENTERTAINMENT: { key: "ENTERTAINMENT", label: "Entertainment", c: "#8a60b3", b: "#f5eaff", icon: era === "n2019" ? "local_movies_o" : "local_movies" },
SPORTS: { key: "SPORTS", label: "Sports", c: "#f60", b: "#fff1ec", icon: era === "n2019" ? "directions_bike_o" : "directions_bike" },
SCIENCE: { key: "SCIENCE", label: "Science", c: "#9ac1ba", b: "#e9efee", icon: era === "n2019" ? "science_o" : "science" },
HEALTH: { key: "HEALTH", label: "Health", c: "#438988", b: "#e9f7f7", icon: era === "n2019" ? "fitness_center_o" : "fitness_center" }
};
let order;
if (era === "n2005" || era === "n2007") {
order = ["top", "WORLD", "NATION", "BUSINESS", "TECHNOLOGY", "SPORTS", "ENTERTAINMENT", "HEALTH"];
} else if (era === "n2009" || era === "n2010") {
order = ["top", "WORLD", "NATION", "BUSINESS", "TECHNOLOGY", "ENTERTAINMENT", "SPORTS", "HEALTH"];
} else if (era === "n2019") {
order = ["top", "NATION", "WORLD", "BUSINESS", "TECHNOLOGY", "ENTERTAINMENT", "SPORTS", "SCIENCE", "HEALTH"];
} else {
order = ["top", "WORLD", "NATION", "BUSINESS", "TECHNOLOGY", "ENTERTAINMENT", "SPORTS", "SCIENCE", "HEALTH"];
}
return order.map(function(k) {
return s[k];
});
}
// ---- the stories ------------------------------------------------------------------
function ugfNewsParse(xml) {
const doc = new DOMParser().parseFromString(trusted_policy.createHTML(xml), "text/xml");
const text = function(el, sel) {
const x = el.querySelector(sel);
return x ? x.textContent.trim() : "";
};
const chan = doc.querySelector("channel");
const out = { title: chan ? text(chan, "title") : "", link: chan ? text(chan, "link") : "",
built: chan && text(chan, "lastBuildDate") ? new Date(text(chan, "lastBuildDate")) : null, items: [] };
doc.querySelectorAll("item").forEach(function(it) {
const src = it.querySelector("source");
const source = src ? src.textContent.trim() : "";
let title = text(it, "title");
if (source && title.slice(-(source.length + 3)) === " - " + source) {
title = title.slice(0, -(source.length + 3));
}
const related = [];
const desc = text(it, "description");
if (desc) {
const h = new DOMParser().parseFromString(trusted_policy.createHTML(desc), "text/html");
h.querySelectorAll("li").forEach(function(li) {
const a = li.querySelector("a");
const f = li.querySelector("font");
if (a) {
related.push({ title: a.textContent.trim(), link: a.getAttribute("href"), source: f ? f.textContent.trim() : "" });
}
});
}
const link = text(it, "link");
out.items.push({ id: text(it, "guid"), title: title, link: link, source: source, sourceUrl: src ? src.getAttribute("url") : "",
date: new Date(text(it, "pubDate")), related: related.filter(function(r) {
return r.link !== link && r.title !== title;
}).slice(0, 4) });
});
return out;
}
function ugfNewsFeed(path) {
const c = ugfNewsFeed.c || (ugfNewsFeed.c = {});
if (!c[path]) {
c[path] = fetch(path, { credentials: "include" }).then(function(r) {
return r.text().then(function(t) {
const f = ugfNewsParse(t);
f.url = r.url;
return f;
});
});
c[path].catch(function() {
delete c[path];
});
}
return c[path];
}
function ugfNewsFeedPath(sec, q, topicId) {
const qs = ugfNewsQs();
if (q) {
return "/rss/search?q=" + encodeURIComponent(q) + "&" + qs;
}
if (topicId) {
return "/rss/topics/" + topicId + "?" + qs;
}
if (!sec || sec === "top") {
return "/rss?" + qs;
}
return "/rss/headlines/section/topic/" + sec + "?" + qs;
}
// the pictures: Google's own page for the same section carries each story's
// picture next to the story's id, which is the same id the feed gives
function ugfNewsPics(url) {
const c = ugfNewsPics.c || (ugfNewsPics.c = {});
if (!c[url]) {
c[url] = fetch(url, { credentials: "include" }).then(function(r) {
return r.text();
}).then(function(h) {
const map = {};
const re = /\.\/read\/(CBMi[\w-]+)|src="(\/api\/attachments\/[^"]+)"|src="(https:\/\/encrypted-tbn\d\.gstatic\.com\/faviconV2[^"]+)"/g;
let m;
let cur = "";
let at = 0;
while ((m = re.exec(h))) {
if (m[1]) {
cur = m[1];
at = m.index;
} else if (cur && m.index - at < 4000) {
const e = map[cur] || (map[cur] = {});
if (m[2] && !e.img) {
e.img = m[2].replace(/&/g, "&").replace(/=[-\w]*$/, "");
} else if (m[3] && !e.fav) {
e.fav = m[3].replace(/&/g, "&");
}
}
}
return map;
}).catch(function() {
return {};
});
}
return c[url];
}
// the front page's own section ("Top stories" / Headlines), whose page carries the
// pictures: its id is the first section link on Google's front page
function ugfNewsTopId() {
const qs = ugfNewsQs();
const c = ugfNewsTopId.c || (ugfNewsTopId.c = {});
if (!c[qs]) {
const mine = document.querySelector("a[href^='./topics/'], a[href^='/topics/']");
const m0 = mine && !mine.closest("#ugf-news") ? String(mine.getAttribute("href")).match(/topics\/([\w-]+)/) : null;
c[qs] = m0 ? Promise.resolve(m0[1]) : fetch("/?" + qs, { credentials: "include" }).then(function(r) {
return r.text();
}).then(function(h) {
const m = h.match(/href="\.\/topics\/([\w-]+)/);
return m ? m[1] : "";
}).catch(function() {
return "";
});
}
return c[qs];
}
function ugfNewsPicUrl(img, w, h) {
return img ? img + "=w" + w + "-h" + h + "-p-df" : "";
}
// "In the News": the names the headlines have most in common
function ugfNewsTopics(items, n) {
const stop = /^(The|A|An|And|Or|But|In|On|At|Of|For|To|From|With|By|As|After|Before|Over|Under|How|Why|What|Who|When|Where|Is|Are|Was|Were|Be|New|Top|More|Most|Live|Watch|Video|Photos|Update|Updates|Breaking|Report|Says|Say|Said|Will|Can|Could|Would|Should|May|It|Its|This|That|These|Those|He|She|They|We|You|I|His|Her|Their|Our|Not|No|Yes|All|Some|First|Last|Here|There|Now|Today|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday|Opinion|Analysis|Exclusive)$/;
const count = {};
items.forEach(function(it) {
const words = String(it.title).replace(/[’']s\b/g, "").replace(/[,:;!?"“”()|–—]/g, " | ").split(/\s+/);
let run = [];
const flush = function() {
while (run.length && stop.test(run[0])) {
run.shift();
}
if (run.length) {
const k = run.slice(0, 3).join(" ");
if (k.length > 2) {
count[k] = (count[k] || 0) + (run.length > 1 ? 2 : 1);
}
}
run = [];
};
words.forEach(function(w, i) {
const clean = w.replace(/^[^\w]+|[^\w.]+$/g, "");
if (w !== "|" && /^[A-Z][\w.&-]*$/.test(clean) && !(i === 0 && stop.test(clean)) && !/^(Say|Says|They|Them|Stole|Warns|Gets|Takes|Makes|Calls|Plans|Wants)$/.test(clean)) {
run.push(clean.replace(/\.$/, ""));
} else {
flush();
}
});
flush();
});
return Object.keys(count).filter(function(k) {
return count[k] >= 2 && !stop.test(k);
}).sort(function(a, b) {
return count[b] - count[a];
}).slice(0, n);
}
// The tab icon Google News really had at the time of each layout (from the Wayback
// Machine): google.com's own until 2009 (News pages named no icon of their own),
// the stack of papers from August 2009, the newspaper with the red bar in 2012 and,
// with the grey g on it, from November 2012 until mid-2017, the blue-bar newspaper
// with the blue G until the 2018 redesign, then the G-and-lines icons
function ugfNewsFav() {
const A = ugfNtArt();
const l = String(layout || "");
const pick = {
"2022": "news2020", "2019": "news2019", "2018M": "news2018", "2018": "news2017", "2017": "news2017",
"2016": "news2013", "2016C": "news2013", "2016L": "news2013", "2015": "news2013", "2015L": "news2013",
"2014": "news2013", "2013": "news2013", "2013L": "news2013", "2012": "news2012",
"2011": "news2009", "2010": "news2009", "2010N": "news2009", "2009L": "news2009", "2009": "g2009"
}[l] || "g1999";
return A["fav_" + pick];
}
// the era's tab icon on the News pages Gplex leaves to Google (stories, publishers,
// settings) too, so the tab never flips back to today's icon
function ugfNewsFavOnly() {
if (!ugfNtTopFrame() || !ugfNtOn("UGF_NEWS_ON")) {
return;
}
const fav = ugfNewsFav(ugfNewsEra());
ugfApplyFavicon(fav);
ugfKeepFavicon(function() {
return fav;
});
}
// ---- the page ---------------------------------------------------------------------
function ugfNewsMain() {
const era = ugfNewsEra();
const A = ugfNtArt();
const esc = ugfNtEsc;
const l = String(layout || "");
const material = era === "n2017" || era === "n2019";
const secs = ugfNewsSections(era);
console.log("[Gplex] News: layout " + layout + " (" + era + ")" + (UGF_VERSION ? " - Gplex " + UGF_VERSION : ""));
const style = document.createElement("style");
style.id = "ugf-nt-styles";
style.textContent = ugfNtBaseCss("ugf-news").concat(ugfNewsCss(era)).join("\n");
(document.head || document.documentElement).appendChild(style);
document.documentElement.setAttribute("gplex-nt", era);
const fav = ugfNewsFav(era);
ugfApplyFavicon(fav);
ugfKeepFavicon(function() {
return fav;
});
const shell = document.createElement("div");
shell.id = "ugf-news";
shell.setAttribute("era", era);
document.body.appendChild(shell);
// where we are: the front page, a section, or a search
const route = function() {
const p = window.location.pathname;
const q = new URLSearchParams(window.location.search).get("q");
if (/^\/search/.test(p) && q) {
return { sec: "search", q: q };
}
const m = p.match(/^\/topics\/([\w-]+)/);
if (m) {
let sec = "";
try {
sec = JSON.parse(sessionStorage.getItem("ugfNewsTopics") || "{}")[m[1]] || "";
} catch (e) {}
return { sec: sec || "topic", topic: m[1] };
}
return { sec: "top" };
};
let st = route();
const secLabel = function(k) {
const s = secs.filter(function(x) {
return x.key === k;
})[0];
return s ? s.label : "";
};
const target = material ? ' target="_blank" rel="noopener"' : "";
const storyLink = function(it, cls, text) {
return '" + esc(text || it.title) + " ";
};
const searchLink = function(t) {
return "/search?q=" + encodeURIComponent(t) + "&" + ugfNewsQs();
};
// ---- the frame of each period
const searchBox = function(big) {
return '';
};
const navHtml = function(topics) {
let h = "";
secs.forEach(function(s) {
const on = st.sec === s.key;
if (era === "n2005" || era === "n2007") {
h += '' + (on ? ">" : "") + esc(s.label) + " ";
} else if (era === "n2009") {
h += ' ' + esc(s.label) + " ";
} else if (era === "n2010") {
h += ' ' + esc(s.label) + " ";
if (s.key === "top" && topics) {
h += '";
}
} else if (era === "n2012") {
h += '' + esc(s.label) + " ";
if (s.key === "top" && topics) {
h += '";
}
} else {
h += '' + ugfNtIcon(s.icon, 24) + "" + esc(s.label) + " ";
}
});
return h;
};
const header = function() {
const edSel = '' + ugfNewsEditions().map(function(e) {
return '" + esc(e[0]) + " ";
}).join("") + " ";
if (era === "n2005") {
return '' +
'
' + searchBox() +
'
Search and browse 4,500 news sources updated continuously.
' +
'';
}
if (era === "n2007" && !ugfNtHasGbar()) {
// 2006: the BETA was gone but the Google bar had not come yet
return '' +
'
' + searchBox() +
'
Search and browse 4,500 news sources updated continuously.
' +
'';
}
if (era === "n2007") {
return ugfNtGbar("classic", "News", "2007") +
'' +
'
' + searchBox() + '
Search and browse 4,500 news sources updated continuously.
' +
'';
}
if (era === "n2009") {
return ugfNtGbar("classic", "News", "2009") +
'' +
searchBox() + '
';
}
if (era === "n2010") {
return ugfNtGbar("classic", "News", "2010") +
'' +
'
' +
'';
}
if (era === "n2012") {
return (ugfNtHasGbar() ? ugfNtGbar("dark", "News") : "") +
'" +
'";
}
if (era === "n2017") {
return '" +
'";
}
return '";
};
// ---- one story, in the period's style
const pic = function(it, w, h) {
if (!it.img) {
return "";
}
return ' ';
};
const story = function(it, opts) {
opts = opts || {};
const ago = ugfNtAgo(it.date, era === "n2017" ? "short" : (era === "n2019" ? "gm" : ""));
if (era === "n2005" || era === "n2007" || era === "n2009" || era === "n2010") {
let h = '';
if (!opts.small && it.img) {
h += '
";
}
h += '
' + storyLink(it) + "
";
h += '
' + esc(it.source) + " " + (era === "n2010" ? " - " : " - ") + esc(ago) + (era === "n2010" ? "" : " ") + "
";
if (!opts.small) {
const rel = it.related;
rel.slice(0, 2).forEach(function(r) {
h += '
";
});
if (rel.length > 2) {
h += '
";
}
h += '
";
} else if (it.related.length) {
h += '
";
}
return h + "
";
}
if (era === "n2012") {
let h = '';
if (!opts.small) {
h += '
";
}
h += '
' + storyLink(it) + '
' + esc(it.source) + " - " + esc(ago) + "
";
if (!opts.small && it.related.length) {
h += '
' + it.related.slice(0, 3).map(function(r) {
return '
";
}).join("") + "
";
}
return h + "
";
}
if (era === "n2017") {
let h = '";
return h;
}
// 2019 on
let h = '";
return h;
};
// ---- the whole page
let seq = 0;
const paint = function() {
const my = ++seq;
const isTop = st.sec === "top";
const title = st.sec === "search" ? st.q : (st.sec === "topic" ? "" : secLabel(st.sec));
document.title = material ? (st.sec === "search" ? st.q + " - Google News" : (isTop ? "Google News" : title + " - Latest - Google News")) :
(st.sec === "search" ? st.q + " - Google News" : (isTop ? "Google News" : "Google News - " + title));
let h = header();
const loading = 'Loading...
';
if (material) {
h += '';
} else if (era === "n2012") {
h += '';
} else {
const left = '' + (era === "n2009" ? '
' : "") + navHtml([]) +
'
";
h += '' + left + '
' +
(era === "n2005" || era === "n2007" ? ' ' : "") + '
' +
'
' +
'
' +
'';
}
shell.innerHTML = trusted_policy.createHTML(h);
shell.scrollTop = 0;
// the edition picker of 2005-2009 sits in the Top Stories bar
const edsel = shell.querySelector(".edsel");
if (edsel) {
edsel.innerHTML = trusted_policy.createHTML('' + ugfNewsEditions().map(function(e) {
return '" + esc(e[0]) + " ";
}).join("") + ' ');
}
if (era === "n2009") {
const ep = shell.querySelector(".cnav .edpick");
ep.innerHTML = trusted_policy.createHTML('' + ugfNewsEditions().map(function(e) {
return '" + esc(e[0]) + " ";
}).join("") + " ");
}
ugfNtMenus(shell, material);
const setTitle = function(t) {
shell.querySelectorAll(".pt").forEach(function(x) {
x.textContent = t;
});
};
setTitle(era === "n2019" && isTop ? "" : (st.sec === "search" ? (material ? st.q : "Search results for " + st.q) : (title || (isTop ? secLabel("top") : ""))));
// the stories of this page
const where = st.sec === "top" ? ugfNewsTopId() : Promise.resolve("");
where.then(function(topId) {
const path = topId ? ugfNewsFeedPath("", "", topId) : ugfNewsFeedPath(st.sec === "search" || st.sec === "topic" ? "" : st.sec, st.sec === "search" ? st.q : "", st.topic);
return ugfNewsFeed(path).then(function(f) {
f.topId = topId;
return f;
});
}).then(function(f) {
if (my !== seq) {
return;
}
// a section reached by name: remember its topic page, for Back and reloads
const tm = String(f.url || "").match(/\/rss\/topics\/([\w-]+)/);
if (tm && st.sec !== "top" && st.sec !== "search" && !f.topId) {
try {
const map = JSON.parse(sessionStorage.getItem("ugfNewsTopics") || "{}");
if (st.sec !== "topic") {
map[tm[1]] = st.sec;
}
sessionStorage.setItem("ugfNewsTopics", JSON.stringify(map));
} catch (e) {}
if (!st.topic) {
st.topic = tm[1];
try {
history.replaceState({ ugfNews: 1 }, "", "/topics/" + tm[1] + "?" + ugfNewsQs());
} catch (e) {}
}
}
if (st.sec === "topic") {
setTitle(String(f.title).replace(/ - (Latest - )?Google News$/, ""));
}
const upd = shell.querySelector(".upd");
if (upd && f.built && era !== "n2010") {
const mins = Math.max(1, Math.round((Date.now() - f.built) / 6e4));
upd.innerHTML = trusted_policy.createHTML((era === "n2005" || era === "n2007" ? "Auto-generated " : "Updated ") + "" + mins + (mins === 1 ? " minute" : " minutes") + " ago ");
}
fill(f, my);
// the pictures, from Google's own page for the same thing
let picUrl = f.topId ? "/topics/" + f.topId + "?" + ugfNewsQs() : "/?" + ugfNewsQs();
if (st.sec === "search") {
picUrl = "/search?q=" + encodeURIComponent(st.q) + "&" + ugfNewsQs();
} else if (st.topic) {
picUrl = "/topics/" + st.topic + "?" + ugfNewsQs();
}
ugfNewsPics(picUrl).then(function(map) {
if (my !== seq) {
return;
}
let any = false;
f.items.forEach(function(it) {
const p = map[it.id];
if (p && (p.img !== it.img || p.fav !== it.fav)) {
it.img = p.img;
it.fav = p.fav;
any = true;
}
});
if (any) {
fill(f, my);
}
});
}).catch(function() {
if (my === seq) {
shell.querySelector(".stories").innerHTML = trusted_policy.createHTML('' +
(material ? "Couldn't load stories. Check your connection and try again." : "Sorry, the news could not be loaded. Please try again later.") + "
");
}
});
};
// the stories, the right-hand column and (on the front page) the sections below
const fill = function(f, my) {
const isTop = st.sec === "top";
const items = f.items;
const box = shell.querySelector(".stories");
const side = shell.querySelector(".cside, .kside, .mside");
let mainN = items.length;
if (!material && era !== "n2012" && isTop) {
mainN = 3;
} else if (isTop) {
mainN = Math.min(items.length, era === "n2012" ? 10 : 12);
}
let h = "";
items.slice(0, mainN).forEach(function(it, i) {
h += story(it, { first: i === 0 });
});
if (!items.length) {
h = '' + (st.sec === "search" ? "Your search - " + esc(st.q) + " - did not match any news results." : "No stories right now.") + "
";
}
if (era === "n2019" && isTop) {
h = '' + h;
}
box.innerHTML = trusted_policy.createHTML(h);
const topics = ugfNewsTopics(items, 10);
// the keyword list under Top Stories (2010-2016)
const kws = shell.querySelector(".kws");
if (kws && isTop) {
kws.innerHTML = trusted_policy.createHTML(topics.map(function(t) {
return '' + esc(t) + " ";
}).join(""));
}
// the right-hand column
let s = "";
const rest = items.slice(mainN);
const recent = items.slice().sort(function(a, b) {
return b.date - a.date;
}).filter(function(it) {
return items.indexOf(it) >= mainN || !isTop;
}).slice(0, 5);
if (era === "n2005" || era === "n2007" || era === "n2009") {
if (isTop) {
s += '";
rest.slice(0, 7).forEach(function(it) {
s += story(it, { small: true });
});
s += '";
} else {
s += '
';
ugfNewsFeed(ugfNewsFeedPath("top")).then(function(tf) {
const t = shell.querySelector(".topl");
if (t && my === seq) {
t.innerHTML = trusted_policy.createHTML(tf.items.slice(0, 6).map(function(it) {
return story(it, { small: true });
}).join(""));
}
}).catch(function() {});
}
} else if (era === "n2010") {
s += 'Recent
' + recent.map(function(it) {
return story(it, { small: true });
}).join("") + "
";
} else if (era === "n2012") {
const who = ugfCalWho();
if (!(who.name || who.email) && l !== "2012" && l !== "2013" && l !== "2013L") {
s += '';
}
s += 'Recent
' + recent.map(function(it) {
return story(it, { small: true });
}).join("");
} else if (era === "n2017") {
if (topics.length) {
s += 'In the News
";
}
s += 'Recent
' + recent.map(function(it) {
return '
' + storyLink(it) + '
' + esc(it.source) + " · " + esc(ugfNtAgo(it.date, "short")) + "
";
}).join("") + "
";
} else {
s += 'Recent
' + recent.map(function(it) {
return '
' + storyLink(it) + '
' + esc(it.source) + "
";
}).join("") + "
";
if (topics.length) {
s += 'In the news
' + topics.slice(0, 8).map(function(t) {
return '
' + esc(t) + " ";
}).join("") + "
";
}
}
if (side) {
side.innerHTML = trusted_policy.createHTML(s);
}
// the sections below the front page (2005-2010)
const below = shell.querySelector(".csecs");
if (below && isTop) {
const list = secs.filter(function(x) {
return x.key !== "top";
});
below.innerHTML = trusted_policy.createHTML('' + list.map(function(x) {
return '
';
}).join("") + "
");
list.forEach(function(x) {
ugfNewsFeed(ugfNewsFeedPath(x.key)).then(function(sf) {
if (my !== seq) {
return;
}
const b = below.querySelector('.sec[data-k="' + x.key + '"] .secb');
b.innerHTML = trusted_policy.createHTML(sf.items.slice(0, 2).map(function(it) {
return story(it);
}).join(""));
}).catch(function() {});
});
}
};
// ---- getting around
const go = function(next, push) {
st = next;
try {
let url = "/?" + ugfNewsQs();
if (st.sec === "search") {
url = "/search?q=" + encodeURIComponent(st.q) + "&" + ugfNewsQs();
} else if (st.topic) {
url = "/topics/" + st.topic + "?" + ugfNewsQs();
} else if (st.sec !== "top") {
url = window.location.pathname + window.location.search;
}
history[push ? "pushState" : "replaceState"]({ ugfNews: 1 }, "", url);
} catch (e) {}
paint();
};
shell.addEventListener("click", function(ev) {
const a = ev.target.closest("[data-sec], [data-q], .burger, .b2, .go");
if (!a || !shell.contains(a)) {
return;
}
if (a.classList.contains("burger")) {
ev.preventDefault();
shell.classList.toggle("nonav");
return;
}
if (a.classList.contains("b2")) {
ev.preventDefault();
const q = (a.form && a.form.querySelector(".q") || {}).value || "";
window.location.href = "https://www.google.com/search?q=" + encodeURIComponent(q);
return;
}
if (a.classList.contains("go") && a.type === "button") {
ev.preventDefault();
const sel = shell.querySelector(".edsel select");
if (sel) {
sel.dispatchEvent(new Event("change", { bubbles: true }));
}
return;
}
if (ev.ctrlKey || ev.metaKey || ev.shiftKey || ev.button === 1) {
return;
}
const q = a.getAttribute("data-q");
if (q) {
ev.preventDefault();
go({ sec: "search", q: q }, true);
return;
}
const sec = a.getAttribute("data-sec");
if (sec) {
ev.preventDefault();
go({ sec: sec }, true);
}
});
shell.addEventListener("submit", function(ev) {
const f = ev.target.closest("form.nsearch");
if (!f) {
return;
}
ev.preventDefault();
const q = f.querySelector(".q").value.trim();
if (q) {
go({ sec: "search", q: q }, true);
}
});
shell.addEventListener("change", function(ev) {
const sel = ev.target.closest("select.ed");
if (!sel) {
return;
}
const v = sel.value.split("|");
window.location.href = "/?hl=" + encodeURIComponent(v[0]) + "&gl=" + encodeURIComponent(v[1]) + "&ceid=" + encodeURIComponent(v[2]);
});
window.addEventListener("popstate", function() {
st = route();
paint();
});
paint();
// fresh stories now and then, as Google News did every few minutes
setInterval(function() {
if (!document.hidden) {
ugfNewsFeed.c = {};
ugfNewsPics.c = {};
const y = shell.scrollTop;
paint();
shell.scrollTop = y;
}
}, 15 * 60 * 1000);
}
// ---- how Google News looked, period by period ------------------------------------
function ugfNewsCss(era) {
const N = "#ugf-news";
const classic = [
N + ' { font: 13px arial, sans-serif; }',
N + ' a { color: #00c; } ' + N + ' a:visited { color: #551a8b; }',
N + ' .nhead { display: flex; align-items: flex-start; }',
N + ' .nhead .logo img { display: block; border: 0; }',
N + ' .nsearch { display: flex; align-items: center; gap: 3px; flex-wrap: wrap; }',
N + ' .nsearch .q { font: 13px arial, sans-serif; padding: 2px 3px; border: 1px solid #7f9db9; }',
N + ' .nsearch input[type=submit], ' + N + ' .nsearch input[type=button] { font: 13px arial, sans-serif; padding: 1px 6px; }',
N + ' .slogan { color: #a03; font-weight: bold; font-size: 13px; margin-top: 2px; }',
N + ' .new { color: #f00; font-size: 11px; }',
N + ' .cbody { display: flex; }',
N + ' .cnav { width: 118px; flex: 0 0 118px; }',
N + ' .cnav .ni { display: block; font-weight: bold; color: #000; text-decoration: none; }',
N + ' .cnav .nl { text-align: center; margin: 22px 0; line-height: 1.3; } ' + N + ' .cnav .nl img { vertical-align: middle; }',
N + ' .cmain { flex: 1; min-width: 0; padding-left: 12px; }',
N + ' .sh { display: flex; align-items: center; gap: 8px; padding: 2px 4px; }',
N + ' .sh .pt { font-weight: bold; font-size: 17px; }',
N + ' .sh .upd { margin-left: auto; font-size: 13px; }',
N + ' .cols { display: flex; gap: 22px; } ' + N + ' .cols .stories { flex: 1 1 0; min-width: 0; } ' + N + ' .cols .cside { width: 38%; flex: 0 0 38%; }',
N + ' .st { overflow: hidden; margin: 12px 0 18px 0; }',
N + ' .st .th { float: right; width: 90px; text-align: center; margin: 0 0 6px 12px; }',
N + ' .st .th img { display: block; margin: 0 auto; width: 80px; height: 80px; object-fit: cover; border: 1px solid #00c; }',
N + ' .st .th .ts { font-size: 10px; color: #666; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }',
N + ' .st .tt a { font-size: 17px; font-weight: bold; }',
N + ' .st .src { color: #666; } ' + N + ' .st .src .sn { font-weight: bold; }',
N + ' .st .rel a { font-size: 13px; } ' + N + ' .st .rel .rs { color: #666; }',
N + ' .st .gsrc a { color: #008000; } ' + N + ' .st .all a { color: #008000; font-weight: bold; }',
N + ' .st.small { margin: 8px 0; } ' + N + ' .st.small .tt a { font-size: 13px; font-weight: bold; } ' + N + ' .st.small .src .sn { font-weight: normal; } ' + N + ' .st.small .all { display: inline; } ' + N + ' .st.small .all a { font-weight: normal; }',
N + ' .pers { border: 1px solid #36c; text-align: center; padding: 4px; font-size: 16px; font-weight: bold; }',
N + ' .itn { margin-top: 14px; border-top: 1px solid #ccc; padding-top: 8px; width: 90%; } ' + N + ' .itng { display: grid; grid-template-columns: 1fr 1fr; gap: 1px 10px; margin-top: 8px; }',
N + ' .csecs .scols { display: grid; grid-template-columns: 1fr 1fr; gap: 0 28px; margin: 18px 10px 0 10px; }',
N + ' .csecs .sech { display: flex; justify-content: space-between; border-top: 3px solid; padding: 3px 4px; }',
N + ' .csecs .sech a { color: #000; font-weight: bold; font-size: 17px; } ' + N + ' .csecs .sech .edit { color: #00c; text-decoration: underline; font-size: 13px; cursor: pointer; }',
N + ' .cfoot { clear: both; text-align: center; margin: 24px 0 16px 0; } ' + N + ' .cfoot .nsearch { justify-content: center; background: #e5ecf9; padding: 14px 0; border-top: 1px solid #36c; }',
N + ' .cfoot .fl { margin-top: 12px; font-size: 13px; }',
N + ' .loading { padding: 16px 4px; color: #666; }'
];
const css = {};
// ---- 2002-2005: the BETA page, its links beside the logo
css.n2005 = classic.concat([
N + ' .nhead { justify-content: center; padding: 8px 8px 0 8px; gap: 14px; }',
N + ' .nhead .tabs { display: flex; gap: 14px; font-size: 13px; margin: 2px 0 4px 0; align-items: baseline; } ' + N + ' .nhead .tabs .adv { font-size: 11px; margin-left: 12px; }',
N + ' .vlinks { text-align: right; padding: 4px 6px; font-size: 13px; }',
N + ' .cnav .ni { background: #efefef; border-left: 4px solid; border-bottom: 2px solid #fff; padding: 2px 6px; }',
N + ' .cnav .ni.on { background: #c03 !important; color: #fff; border-left-color: #c03 !important; }',
N + ' .sh { background: #efefef; border-top: 2px solid #c03; }',
N + ' .pers { border: 1px solid #36c; background: #fff; }'
]);
// ---- 2006-2008: the Google bar over it, the logo centred with the search
css.n2007 = css.n2005.concat([
N + ' .nhead { padding: 10px 8px 0 8px; gap: 12px; align-items: center; }',
N + ' .nhead .hc { padding-top: 0; }',
N + ' .vlinks { padding: 10px 0 4px 0; }',
N + ' .sh { border-top-color: #a03; } ' + N + ' .cnav .ni.on { background: #a03 !important; border-left-color: #a03 !important; }'
]);
// ---- late 2008-2009: "Google news" on the left, blue-grey section bars
css.n2009 = classic.concat([
N + ' .nhead { align-items: center; gap: 10px; padding: 10px 8px 14px 8px; }',
N + ' .nhead .hlinks { display: flex; flex-direction: column; font-size: 11px; margin-left: 4px; }',
N + ' .cnav { width: 118px; } ' + N + ' .cnav .edpick select { width: 118px; margin-bottom: 6px; font: 13px arial, sans-serif; }',
N + ' .cnav .ni { font-weight: normal; padding: 3px 4px; border-bottom: 1px solid #e0e6f1; display: flex; align-items: center; gap: 8px; }',
N + ' .cnav .ni i { width: 4px; height: 16px; flex: 0 0 4px; }',
N + ' .cnav .ni.on { color: #fff; font-weight: bold; } ' + N + ' .cnav .ni.on i { background: #fff !important; }',
N + ' .cnav .nl span { display: block; }',
N + ' .cmain { border-left: 1px solid #e0e6f1; padding-left: 8px; }',
N + ' .sh { background: #ebeff9; border-top: 1px solid #6b90da; } ' + N + ' .sh .pt { font-size: 16px; }',
N + ' .st .tt a { font-size: 16px; }',
N + ' .st .all a.email { margin-left: 10px; color: #77c; font-weight: normal; } ' + N + ' .st .email img { vertical-align: middle; margin-right: 3px; }',
N + ' .pers { border: 0; background: #ebeff9; font-size: 13px; padding: 4px; }',
N + ' .csecs .sech { border-top: 1px solid; } ' + N + ' .csecs .sech a { font-size: 16px; }',
N + ' .cfoot .nsearch { background: #ebeff9; }'
]);
// ---- 2010: the keyword list under Top Stories, the Recent column
css.n2010 = classic.concat([
N + ' .nhead { align-items: flex-start; gap: 10px; padding: 16px 8px 8px 8px; }',
N + ' .nhead .hc { display: flex; flex-direction: column; align-items: flex-end; }',
N + ' .nhead .nsearch .q { width: 345px; height: 32px; font-size: 17px; border: 1px solid #ccc; border-top-color: #999; }',
N + ' .nhead .nsearch input[type=submit], ' + N + ' .nhead .nsearch input[type=button] { height: 32px; font-size: 15px; }',
N + ' .nhead .adv { font-size: 11px; margin-top: 4px; }',
N + ' .vlinks { display: flex; justify-content: flex-end; gap: 14px; padding: 0 8px 6px 0; } ' + N + ' .vlinks select { font: 13px arial, sans-serif; }',
N + ' .cnav { width: 150px; flex: 0 0 150px; padding-left: 10px; }',
N + ' .cnav .ni { font-weight: normal; color: #00c; padding: 2px 0; display: flex; gap: 8px; align-items: center; }',
N + ' .cnav .ni i { width: 6px; height: 14px; flex: 0 0 6px; } ' + N + ' .cnav .ni.on { color: #000; font-weight: bold; }',
N + ' .cnav .kws a { display: block; padding: 1px 0 1px 14px; text-decoration: none; } ' + N + ' .cnav .ni { text-decoration: none; }',
N + ' .cmain { padding-left: 20px; }',
N + ' .sh { background: #ebeff9; } ' + N + ' .sh .pt { font-size: 13px; }',
N + ' .st { border-bottom: 1px solid #ebeff9; padding-bottom: 8px; margin: 6px 0 8px 0; }',
N + ' .st .src .sn { font-weight: normal; } ' + N + ' .st .all a { font-weight: normal; }',
N + ' .cols .cside { width: 320px; flex: 0 0 320px; }',
N + ' .sbox .sbh { background: #ebeff9; font-weight: bold; padding: 4px 6px; } ' + N + ' .sbox .st.small { border: 0; }',
N + ' .csecs .sech { border-top: 0; } ' + N + ' .csecs .sech a { font-size: 13px; }'
]);
// ---- 2011-2016: the grey header, the red "News", thumbnails on the left
css.n2012 = [
N + ' { font: 13px arial, sans-serif; color: #222; }',
N + ' a { color: #15c; text-decoration: none; } ' + N + ' a:hover { text-decoration: underline; }',
N + ' .nhead { display: flex; align-items: center; background: #f1f1f1; border-bottom: 1px solid #e5e5e5; height: 58px; padding: 0 28px; gap: 60px; }',
N + ' .nhead .logo img { display: block; }',
N + ' .nsearch.k { display: flex; align-items: center; gap: 16px; }',
N + ' .nsearch.k .q { width: 248px; height: 29px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 1px 8px; font: 16px arial, sans-serif; outline: none; }',
N + ' .nsearch.k .q:focus { border-color: #4d90fe; box-shadow: inset 0 1px 2px rgba(0,0,0,.3); }',
N + ' .nsearch.k .go { width: 72px; height: 29px; margin-left: -12px; border: 1px solid #3079ed; border-radius: 2px; background: linear-gradient(#4d90fe, #4787ed); color: #fff; display: flex; align-items: center; justify-content: center; cursor: pointer; }',
N + ' .kb { display: inline-flex; align-items: center; gap: 6px; height: 29px; padding: 0 8px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444 !important; font: bold 11px arial, sans-serif; cursor: pointer; position: relative; text-decoration: none !important; }',
N + ' .kb:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); } ' + N + ' .kb svg { fill: #666; }',
N + ' .kb.dd select { position: absolute; inset: 0; opacity: 0; cursor: pointer; }',
N + ' .nbar { display: flex; align-items: center; gap: 16px; height: 58px; padding: 0 28px; border-bottom: 1px solid #ebebeb; }',
N + ' .nbar .label { color: #dd4b39; font-size: 20px; width: 158px; }',
N + ' .nbar .gearb { margin-left: auto; margin-right: 22%; width: 72px; justify-content: center; }',
N + ' .kbody { display: flex; padding: 0 0 20px 0; }',
N + ' .knav { width: 186px; flex: 0 0 186px; padding: 10px 0 0 28px; }',
N + ' .knav .ni { display: block; color: #222; font-size: 13px; padding: 7px 0; } ' + N + ' .knav .ni.on { color: #dd4b39; }',
N + ' .knav .kws a { display: block; color: #222; padding: 3px 0 3px 9px; }',
N + ' .kmain { flex: 0 1 530px; min-width: 0; }',
N + ' .kmain .sh { background: #f5f5f5; border-bottom: 1px solid #ddd; padding: 6px 4px; margin-top: 4px; } ' + N + ' .kmain .sh .pt { font-size: 16px; color: #222; }',
N + ' .st { display: flex; gap: 14px; padding: 12px 0 12px 6px; border-bottom: 1px solid #ebebeb; }',
N + ' .st .th { width: 72px; flex: 0 0 72px; text-align: center; } ' + N + ' .st .th img { display: block; width: 72px; height: 72px; object-fit: cover; }',
N + ' .st .th .noimg { display: block; height: 4px; }',
N + ' .st .th .ts { font-size: 11px; color: #777; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 2px; }',
N + ' .st .th .rt { display: block; margin-top: 12px; background: #4d90fe; border: 1px solid #3079ed; border-radius: 2px; color: #fff !important; font-weight: bold; font-size: 11px; line-height: 16px; padding: 6px 4px; }',
N + ' .st .tb { flex: 1; min-width: 0; }',
N + ' .st .tt a { font-size: 17px; font-weight: bold; color: #15c; line-height: 1.25; }',
N + ' .st .src { font-size: 11px; color: #777; margin: 3px 0 6px 0; }',
N + ' .st .rels { margin-top: 6px; } ' + N + ' .st .rel { margin: 3px 0; } ' + N + ' .st .rel .rs { color: #777; font-size: 11px; }',
N + ' .st.small { display: block; padding: 6px 0; border: 0; } ' + N + ' .st.small .tt a { font-size: 13px; } ' + N + ' .st.small .src { margin: 1px 0 0 0; }',
N + ' .kside { width: 310px; flex: 0 0 310px; margin-left: 26px; padding-top: 6px; }',
N + ' .kside .sbh { font-size: 16px; color: #222; padding: 8px 0 6px 0; border-bottom: 1px solid #ebebeb; margin-bottom: 4px; }',
N + ' .signbox { background: #fff4c2; border: 1px solid #f0c36d; padding: 12px; line-height: 1.6; margin-bottom: 12px; }',
N + ' .kfoot { text-align: center; color: #777; padding: 20px 0; border-top: 1px solid #ebebeb; }',
N + ' .loading { padding: 16px 6px; color: #777; }'
];
// ---- 2017-2018: Material cards
css.n2017 = [
N + ' { font: 14px Roboto, arial, sans-serif; color: #212121; background: #f2f2f2; }',
N + ' a { color: inherit; text-decoration: none; }',
N + ' .mhead { display: flex; align-items: center; height: 64px; background: #fff; padding: 0 8px; gap: 8px; }',
N + ' .mlogo { display: flex; align-items: center; gap: 6px; width: 200px; margin-left: 8px; } ' + N + ' .mlogo span { font: 22px "Product Sans", "Google Sans", Roboto, arial, sans-serif; color: #757575; }',
N + ' .nsearch.m { flex: 0 1 602px; display: flex; align-items: center; height: 48px; background: #f1f1f1; border-radius: 2px; padding: 0 12px; gap: 12px; color: #757575; }',
N + ' .nsearch.m .q { flex: 1; border: 0; background: transparent; outline: none; font: 16px Roboto, arial, sans-serif; color: #212121; }',
N + ' .corner { margin-left: auto; display: flex; align-items: center; }',
N + ' .mtabs { display: flex; align-items: center; justify-content: center; gap: 0; height: 48px; background: #fff; box-shadow: 0 2px 2px rgba(0,0,0,.1); position: relative; }',
N + ' .mtabs a { padding: 0 24px; line-height: 45px; color: #616161; border-bottom: 3px solid transparent; } ' + N + ' .mtabs a.on { color: #4285f4; border-bottom-color: #4285f4; }',
N + ' .mtabs .sep { width: 1px; height: 20px; background: #ddd; margin: 0 8px; }',
N + ' .mtabs .edm { display: inline-flex; align-items: center; color: #616161; padding: 0 16px; position: relative; } ' + N + ' .mtabs .edm select { position: absolute; inset: 0; opacity: 0; }',
N + ' .mtabs .gearm { position: absolute; right: 16px; }',
N + ' .mbody { display: flex; gap: 24px; }',
N + ' .mnav { width: 280px; flex: 0 0 280px; background: #f2f2f2; padding: 12px 0; border-right: 1px solid transparent; }',
N + ' #ugf-news.nonav .mnav { display: none; }',
N + ' .mnav .nh { font-size: 12px; color: #616161; padding: 8px 24px; letter-spacing: .4px; }',
N + ' .mnav .ni { display: flex; align-items: center; gap: 24px; height: 40px; padding: 0 24px; color: #424242; } ' + N + ' .mnav .ni .mi { color: #757575; }',
N + ' .mnav .ni.on { background: #e0e0e0; font-weight: 500; } ' + N + ' .mnav .ni.on .mi { color: #424242; }',
N + ' .mnav .nsep { border-top: 1px solid #ddd; margin: 8px 0; }',
N + ' .mmain { flex: 0 1 444px; min-width: 0; } ' + N + ' .mmain .pt { font: 400 24px Roboto, arial, sans-serif; color: #212121; margin: 20px 0 8px 16px; }',
N + ' .card { background: #fff; border-radius: 2px; box-shadow: 0 1px 2px rgba(0,0,0,.2); margin-bottom: 8px; }',
N + ' .st { display: flex; gap: 16px; padding: 16px; }',
N + ' .st .lcol { width: 128px; flex: 0 0 128px; } ' + N + ' .st .lcol img { display: block; width: 128px; height: 128px; object-fit: cover; } ' + N + ' .st .lcol:empty { display: none; }',
N + ' .st .rcol { flex: 1; min-width: 0; }',
N + ' .st .tt a { font: 500 18px Roboto, arial, sans-serif; color: #212121; line-height: 24px; } ' + N + ' .st .tt a:hover { text-decoration: underline; }',
N + ' .st .src { font-size: 12px; color: #757575; margin: 4px 0 12px 0; }',
N + ' .st .rh { font-size: 12px; color: #616161; letter-spacing: .3px; margin: 12px 0 8px 0; }',
N + ' .st .rel { margin-bottom: 12px; } ' + N + ' .st .rel a { font-size: 14px; color: #212121; line-height: 20px; } ' + N + ' .st .rel .rs { font-size: 12px; color: #757575; }',
N + ' .st .full { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; color: #212121; margin-top: 4px; }',
N + ' .mside { width: 304px; flex: 0 0 304px; }',
N + ' .mside .sh2 { font-size: 18px; color: #212121; margin: 24px 0 12px 16px; }',
N + ' .chips { display: flex; flex-wrap: wrap; gap: 8px; padding: 16px; } ' + N + ' .chips a { border: 1px solid #ddd; border-radius: 6px; padding: 5px 8px; font-size: 14px; color: #212121; }',
N + ' .recent { padding: 16px; } ' + N + ' .recent .ri { margin-bottom: 16px; } ' + N + ' .recent .ri a { font-size: 14px; color: #212121; line-height: 20px; } ' + N + ' .recent .rs { font-size: 12px; color: #757575; }',
N + ' .loading { padding: 24px 16px; color: #757575; }'
];
// ---- 2019 on: Google Sans, the pill search, cards with lines
css.n2019 = [
N + ' { font: 14px Roboto, arial, sans-serif; color: #202124; background: #fff; }',
N + ' a { color: inherit; text-decoration: none; }',
N + ' .mhead { display: flex; align-items: center; height: 64px; background: #fff; padding: 0 8px; gap: 8px; box-shadow: 0 1px 2px rgba(60,64,67,.3), 0 2px 6px 2px rgba(60,64,67,.15); position: sticky; top: 0; z-index: 5; }',
N + ' .mlogo { display: flex; align-items: center; gap: 4px; width: 200px; margin-left: 8px; } ' + N + ' .mlogo span { font: 22px "Product Sans", "Google Sans", Roboto, arial, sans-serif; color: #5f6368; }',
N + ' .nsearch.m { flex: 0 1 720px; display: flex; align-items: center; height: 48px; background: #f1f3f4; border-radius: 8px; padding: 0 12px; gap: 12px; color: #5f6368; }',
N + ' .nsearch.m .q { flex: 1; border: 0; background: transparent; outline: none; font: 16px Roboto, arial, sans-serif; color: #202124; }',
N + ' .corner { margin-left: auto; display: flex; align-items: center; }',
N + ' .mbody { display: flex; gap: 32px; padding-top: 16px; }',
N + ' .mnav { width: 256px; flex: 0 0 256px; padding: 8px 0; }',
N + ' #ugf-news.nonav .mnav { display: none; }',
N + ' .mnav .ni { display: flex; align-items: center; gap: 20px; height: 40px; padding: 0 24px; color: #202124; border-radius: 0 20px 20px 0; font: 500 14px "Google Sans", Roboto, arial, sans-serif; } ' + N + ' .mnav .ni .mi { color: #5f6368; }',
N + ' .mnav .ni:hover { background: #f1f3f4; } ' + N + ' .mnav .ni.on { background: #e8f0fe; color: #1967d2; } ' + N + ' .mnav .ni.on .mi { color: #1967d2; }',
N + ' .mmain { flex: 0 1 482px; min-width: 0; } ' + N + ' .mmain .pt { font: 400 24px "Google Sans", Roboto, arial, sans-serif; margin: 8px 0 12px 0; } ' + N + ' .mmain .pt:empty { display: none; }',
N + ' .hh { display: flex; align-items: baseline; justify-content: space-between; margin: 8px 0 12px 0; } ' + N + ' .hh span { font: 400 22px "Google Sans", Roboto, arial, sans-serif; } ' + N + ' .hh a { color: #1a73e8; font: 500 14px "Google Sans", Roboto, arial, sans-serif; }',
N + ' .card { border: 1px solid #dadce0; border-radius: 8px; margin-bottom: 16px; }',
N + ' .st { padding: 16px; }',
N + ' .st .top { display: flex; gap: 16px; } ' + N + ' .st .tb { flex: 1; min-width: 0; }',
N + ' .st .tt a { font: 500 20px "Google Sans", Roboto, arial, sans-serif; color: #202124; line-height: 26px; } ' + N + ' .st .tt a:hover { text-decoration: underline; }',
N + ' .st .src { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #5f6368; margin-top: 8px; } ' + N + ' .st .fv { width: 16px; height: 16px; border-radius: 2px; }',
N + ' .st .im img { display: block; width: 100px; height: 100px; object-fit: cover; border-radius: 8px; }',
N + ' .st .rels { margin: 14px 0 0 0; padding: 0 0 0 16px; } ' + N + ' .st .rels li { margin-bottom: 12px; color: #1a73e8; } ' + N + ' .st .rels a { font: 500 14px Roboto, arial, sans-serif; color: #202124; } ' + N + ' .st .rels .rs { font-size: 12px; color: #5f6368; margin-top: 2px; }',
N + ' .st .full { display: inline-flex; align-items: center; gap: 8px; color: #1a73e8; font: 500 14px "Google Sans", Roboto, arial, sans-serif; margin-top: 6px; }',
N + ' .mside { width: 234px; flex: 0 0 234px; }',
N + ' .gcard { border: 1px solid #dadce0; border-radius: 8px; padding: 16px; margin-bottom: 16px; } ' + N + ' .gcard .gh { font: 400 18px "Google Sans", Roboto, arial, sans-serif; color: #5f6368; padding-bottom: 12px; border-bottom: 1px solid #dadce0; margin-bottom: 12px; }',
N + ' .gcard .ri { margin-bottom: 14px; } ' + N + ' .gcard .ri a { font: 500 14px Roboto, arial, sans-serif; color: #202124; line-height: 20px; } ' + N + ' .gcard .rs { font-size: 12px; color: #5f6368; }',
N + ' .chips { display: flex; flex-wrap: wrap; gap: 8px; } ' + N + ' .chips a { border: 1px solid #dadce0; border-radius: 16px; padding: 6px 12px; font-size: 13px; color: #3c4043; }',
N + ' .loading { padding: 24px 0; color: #5f6368; }'
];
return css[era] || css.n2012;
}
// ---- Google Translate -----------------------------------------------------------
function ugfTrWanted() {
if (window.location.host !== "translate.google.com" || !ugfNtTopFrame()) {
return false;
}
const p = window.location.pathname || "/";
// the translator itself, with its documents and websites; images, saved and history stay Google's
if (!/^\/(|m)$/.test(p)) {
return false;
}
const q = new URLSearchParams(window.location.search);
if (q.get("u") || q.get("op") === "images") {
return false;
}
return ugfNtOn("UGF_TRANSLATE_ON");
}
function ugfTrEra() {
const l = String(layout || "2015");
if (l === "2019" || l === "2022") {
return "t2019";
}
if (["2015", "2016", "2016C", "2016L", "2017", "2018", "2018M"].indexOf(l) > -1) {
return "t2015";
}
if (["2011", "2012", "2013", "2013L", "2014", "2015L"].indexOf(l) > -1) {
return "t2012";
}
if (l === "2009" || l === "2009L" || l === "2010" || l === "2010N") {
return "t2010";
}
if (l === "2007") {
return "t2008";
}
return "t2006";
}
// the languages, by Google's codes: all 249 Google Translate offers now (its own list)
function ugfTrLangs() {
return ugfTrLangs.c || (ugfTrLangs.c = [
["ab", "Abkhaz"], ["ace", "Acehnese"], ["ach", "Acholi"], ["aa", "Afar"], ["af", "Afrikaans"], ["sq", "Albanian"], ["alz", "Alur"],
["am", "Amharic"], ["ar", "Arabic"], ["hy", "Armenian"], ["as", "Assamese"], ["av", "Avar"], ["awa", "Awadhi"], ["ay", "Aymara"],
["az", "Azerbaijani"], ["ban", "Balinese"], ["bal", "Baluchi"], ["bm", "Bambara"], ["bci", "Baoulé"], ["ba", "Bashkir"], ["eu", "Basque"],
["btx", "Batak Karo"], ["bts", "Batak Simalungun"], ["bbc", "Batak Toba"], ["be", "Belarusian"], ["bem", "Bemba"], ["bn", "Bengali"],
["bew", "Betawi"], ["bho", "Bhojpuri"], ["bik", "Bikol"], ["bs", "Bosnian"], ["br", "Breton"], ["bg", "Bulgarian"], ["bua", "Buryat"],
["yue", "Cantonese"], ["ca", "Catalan"], ["ceb", "Cebuano"], ["ch", "Chamorro"], ["ce", "Chechen"], ["ny", "Chichewa"],
["zh-CN", "Chinese (Simplified)"], ["zh-TW", "Chinese (Traditional)"], ["chk", "Chuukese"], ["cv", "Chuvash"], ["co", "Corsican"],
["crh", "Crimean Tatar (Cyrillic)"], ["crh-Latn", "Crimean Tatar (Latin)"], ["hr", "Croatian"], ["cs", "Czech"], ["da", "Danish"],
["fa-AF", "Dari"], ["dv", "Dhivehi"], ["din", "Dinka"], ["doi", "Dogri"], ["dov", "Dombe"], ["nl", "Dutch"], ["dyu", "Dyula"], ["dz", "Dzongkha"],
["en", "English"], ["eo", "Esperanto"], ["et", "Estonian"], ["ee", "Ewe"], ["fo", "Faroese"], ["fj", "Fijian"], ["tl", "Filipino"],
["fi", "Finnish"], ["fon", "Fon"], ["fr", "French"], ["fr-CA", "French (Canada)"], ["fy", "Frisian"], ["fur", "Friulian"], ["ff", "Fulani"],
["gaa", "Ga"], ["gl", "Galician"], ["ka", "Georgian"], ["de", "German"], ["el", "Greek"], ["gn", "Guarani"], ["gu", "Gujarati"],
["ht", "Haitian Creole"], ["cnh", "Hakha Chin"], ["ha", "Hausa"], ["haw", "Hawaiian"], ["iw", "Hebrew"], ["hil", "Hiligaynon"], ["hi", "Hindi"],
["hmn", "Hmong"], ["hu", "Hungarian"], ["hrx", "Hunsrik"], ["iba", "Iban"], ["is", "Icelandic"], ["ig", "Igbo"], ["ilo", "Ilocano"],
["id", "Indonesian"], ["iu-Latn", "Inuktut (Latin)"], ["iu", "Inuktut (Syllabics)"], ["ga", "Irish"], ["it", "Italian"],
["jam", "Jamaican Patois"], ["ja", "Japanese"], ["jw", "Javanese"], ["kac", "Jingpo"], ["kl", "Kalaallisut"], ["kn", "Kannada"], ["kr", "Kanuri"],
["pam", "Kapampangan"], ["kk", "Kazakh"], ["kha", "Khasi"], ["km", "Khmer"], ["cgg", "Kiga"], ["kg", "Kikongo"], ["rw", "Kinyarwanda"],
["ktu", "Kituba"], ["trp", "Kokborok"], ["kv", "Komi"], ["gom", "Konkani"], ["ko", "Korean"], ["kri", "Krio"], ["ku", "Kurdish (Kurmanji)"],
["ckb", "Kurdish (Sorani)"], ["ky", "Kyrgyz"], ["lo", "Lao"], ["ltg", "Latgalian"], ["la", "Latin"], ["lv", "Latvian"], ["lij", "Ligurian"],
["li", "Limburgish"], ["ln", "Lingala"], ["lt", "Lithuanian"], ["lmo", "Lombard"], ["lg", "Luganda"], ["luo", "Luo"], ["lb", "Luxembourgish"],
["mk", "Macedonian"], ["mad", "Madurese"], ["mai", "Maithili"], ["mak", "Makassar"], ["mg", "Malagasy"], ["ms", "Malay"],
["ms-Arab", "Malay (Jawi)"], ["ml", "Malayalam"], ["mt", "Maltese"], ["mam", "Mam"], ["gv", "Manx"], ["mi", "Maori"], ["mr", "Marathi"],
["mh", "Marshallese"], ["mwr", "Marwadi"], ["mfe", "Mauritian Creole"], ["chm", "Meadow Mari"], ["mni-Mtei", "Meiteilon (Manipuri)"],
["min", "Minang"], ["lus", "Mizo"], ["mn", "Mongolian"], ["my", "Myanmar (Burmese)"], ["nhe", "Nahuatl (Eastern Huasteca)"], ["ndc-ZW", "Ndau"],
["nr", "Ndebele (South)"], ["new", "Nepalbhasa (Newari)"], ["ne", "Nepali"], ["bm-Nkoo", "NKo"], ["no", "Norwegian"], ["nus", "Nuer"],
["oc", "Occitan"], ["or", "Odia (Oriya)"], ["om", "Oromo"], ["os", "Ossetian"], ["pag", "Pangasinan"], ["pap", "Papiamento"], ["ps", "Pashto"],
["fa", "Persian"], ["pl", "Polish"], ["pt", "Portuguese (Brazil)"], ["pt-PT", "Portuguese (Portugal)"], ["pa", "Punjabi (Gurmukhi)"],
["pa-Arab", "Punjabi (Shahmukhi)"], ["qu", "Quechua"], ["kek", "Qʼeqchiʼ"], ["rom", "Romani"], ["ro", "Romanian"], ["rn", "Rundi"],
["ru", "Russian"], ["se", "Sami (North)"], ["sm", "Samoan"], ["sg", "Sango"], ["sa", "Sanskrit"], ["sat-Latn", "Santali (Latin)"],
["sat", "Santali (Ol Chiki)"], ["gd", "Scots Gaelic"], ["nso", "Sepedi"], ["sr", "Serbian"], ["st", "Sesotho"], ["crs", "Seychellois Creole"],
["shn", "Shan"], ["sn", "Shona"], ["scn", "Sicilian"], ["szl", "Silesian"], ["sd", "Sindhi"], ["si", "Sinhala"], ["sk", "Slovak"],
["sl", "Slovenian"], ["so", "Somali"], ["es", "Spanish"], ["su", "Sundanese"], ["sus", "Susu"], ["sw", "Swahili"], ["ss", "Swati"],
["sv", "Swedish"], ["ty", "Tahitian"], ["tg", "Tajik"], ["ber-Latn", "Tamazight"], ["ber", "Tamazight (Tifinagh)"], ["ta", "Tamil"],
["tt", "Tatar"], ["te", "Telugu"], ["tet", "Tetum"], ["th", "Thai"], ["bo", "Tibetan"], ["ti", "Tigrinya"], ["tiv", "Tiv"], ["tpi", "Tok Pisin"],
["to", "Tongan"], ["lua", "Tshiluba"], ["ts", "Tsonga"], ["tn", "Tswana"], ["tcy", "Tulu"], ["tum", "Tumbuka"], ["tr", "Turkish"],
["tk", "Turkmen"], ["tyv", "Tuvan"], ["ak", "Twi"], ["udm", "Udmurt"], ["uk", "Ukrainian"], ["ur", "Urdu"], ["ug", "Uyghur"], ["uz", "Uzbek"],
["ve", "Venda"], ["vec", "Venetian"], ["vi", "Vietnamese"], ["war", "Waray"], ["cy", "Welsh"], ["wo", "Wolof"], ["xh", "Xhosa"], ["sah", "Yakut"],
["yi", "Yiddish"], ["yo", "Yoruba"], ["yua", "Yucatec Maya"], ["zap", "Zapotec"], ["zu", "Zulu"]
]);
}
// every language works in every period; 2006 keeps its list of language pairs
function ugfTrLangsFor(era) {
return ugfTrLangs();
}
function ugfTrName(code) {
if (code === "auto") {
return "Detect language";
}
const x = ugfTrLangs().filter(function(l) {
return l[0] === code;
})[0];
return x ? x[1] : code;
}
// A request to Google's translation service: through the userscript manager
// (no cookies, no page rules in the way), else the page's own fetch. cb(status, text)
function ugfTrGet(url, body, cb) {
if (typeof GM_xmlhttpRequest === "function") {
try {
GM_xmlhttpRequest({ method: body ? "POST" : "GET", url: url, data: body || undefined, anonymous: true,
headers: body ? { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" } : {},
onload: function(r) {
cb(r.status, r.responseText);
}, onerror: function() {
cb(0, "");
}, ontimeout: function() {
cb(0, "");
}, timeout: 15000 });
return;
} catch (e) {}
}
fetch(url, body ? { method: "POST", body: body, credentials: "omit", headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" } } : { credentials: "omit" }).then(function(r) {
return r.text().then(function(t) {
cb(r.status, t);
});
}).catch(function() {
cb(0, "");
});
}
// Google's own translation service, the one its Chrome extension uses, with the
// one its Translate web widget uses as the second try. cb(err, text, detected)
function ugfTrTranslate(text, sl, tl, cb) {
const long = encodeURIComponent(text).length > 1800;
const q = "&sl=" + encodeURIComponent(sl) + "&tl=" + encodeURIComponent(tl);
// the widget's service: [[["Hola","Hello",...],...],null,"en",...]
const second = function(firstErr, firstOut, firstDet) {
const url = "https://translate.googleapis.com/translate_a/single?client=gtx&dt=t" + q + (long ? "" : "&q=" + encodeURIComponent(text));
ugfTrGet(url, long ? "q=" + encodeURIComponent(text) : "", function(status, txt) {
try {
if (status !== 200) {
throw new Error("HTTP " + status);
}
const j = JSON.parse(txt);
const out = (j[0] || []).map(function(x) {
return x && x[0] ? x[0] : "";
}).join("");
if (!out) {
throw new Error("empty");
}
cb(null, out, j[2] || firstDet || "");
} catch (e) {
if (firstOut !== undefined && firstOut !== null && !firstErr) {
cb(null, firstOut, firstDet);
} else {
cb(firstErr || e);
}
}
});
};
const url = "https://clients5.google.com/translate_a/t?client=dict-chrome-ex" + q + (long ? "" : "&q=" + encodeURIComponent(text));
ugfTrGet(url, long ? "q=" + encodeURIComponent(text) : "", function(status, txt) {
let out = "";
let det = "";
try {
if (status !== 200) {
throw new Error("HTTP " + status);
}
const j = JSON.parse(txt);
// [["translation","en"]] when detecting, ["translation"] otherwise
(Array.isArray(j) ? j : [j]).forEach(function(p) {
if (Array.isArray(p)) {
out += p[0];
det = det || p[1] || "";
} else if (typeof p === "string") {
out += p;
}
});
} catch (e) {
second(e);
return;
}
// nothing came back (it does that now and then), or the text came back
// unchanged when it should not have
const same = out.trim() === text.trim() && sl !== tl && !(sl === "auto" && det === tl);
if (!out.trim() && !ugfTrTranslate.retry) {
ugfTrTranslate.retry = true;
setTimeout(function() {
ugfTrTranslate(text, sl, tl, function(e, o, d) {
ugfTrTranslate.retry = false;
cb(e, o, d);
});
}, 350);
return;
}
if (!out.trim() || same) {
second(null, out, det);
return;
}
cb(null, out, det);
});
}
// The tab icon Google Translate really had at the time of each layout (from the
// Wayback Machine): google.com's own until July 2010, then the 文/A icons - the
// small one, the grey-and-blue one from November 2012, the blue A of March 2015,
// the G of September 2015 and the larger G set of 2017, which it still uses
function ugfTrFav() {
const A = ugfNtArt();
const l = String(layout || "");
const pick = {
"2022": "tr2017", "2019": "tr2017", "2018M": "tr2017", "2018": "tr2017", "2017": "tr2017",
"2016": "tr2015s", "2016C": "tr2015s", "2016L": "tr2015s", "2015L": "tr2015s", "2015": "tr2015",
"2014": "tr2012", "2013": "tr2012", "2013L": "tr2012",
"2012": "tr2010", "2011": "tr2010", "2010": "tr2010", "2010N": "tr2010", "2009L": "g2009", "2009": "g2009"
}[l] || "g1999";
return A["fav_" + pick];
}
// the era's tab icon on the Translate pages Gplex leaves to Google (documents,
// websites, images, saved) too
function ugfTrFavOnly() {
if (!ugfNtTopFrame() || !ugfNtOn("UGF_TRANSLATE_ON")) {
return;
}
const fav = ugfTrFav(ugfTrEra());
ugfApplyFavicon(fav);
ugfKeepFavicon(function() {
return fav;
});
}
function ugfTrMain() {
const era = ugfTrEra();
const A = ugfNtArt();
const esc = ugfNtEsc;
const material = era === "t2019";
const kennedy = era === "t2012" || era === "t2015";
const langs = ugfTrLangsFor(era);
const l = String(layout || "");
console.log("[Gplex] Translate: layout " + layout + " (" + era + ")" + (UGF_VERSION ? " - Gplex " + UGF_VERSION : ""));
const style = document.createElement("style");
style.id = "ugf-nt-styles";
style.textContent = ugfNtBaseCss("ugf-tr").concat(ugfTrCss(era)).join("\n");
(document.head || document.documentElement).appendChild(style);
document.documentElement.setAttribute("gplex-nt", era);
const fav = ugfTrFav(era);
ugfApplyFavicon(fav);
ugfKeepFavicon(function() {
return fav;
});
document.title = "Google Translate";
// what to translate: from the address (?sl=&tl=&text= as Google uses now, or #sl|tl|text)
const q = new URLSearchParams(window.location.search);
const hash = decodeURIComponent((window.location.hash || "").slice(1)).split("|");
const st = { sl: q.get("sl") || (hash.length > 2 ? hash[0] : "") || "auto", tl: q.get("tl") || (hash.length > 2 ? hash[1] : "") || "en",
text: q.get("text") || (hash.length > 2 ? hash.slice(2).join("|") : ""), out: "", det: "", instant: true, recentSl: ["en", "es", "fr"], recentTl: ["en", "es", "ar"],
mode: q.get("op") === "docs" ? "docs" : q.get("op") === "websites" && l === "2022" ? "web" : "text", file: null };
if (era === "t2006" || era === "t2008") {
st.sl = st.sl === "auto" ? "es" : st.sl;
}
try {
st.instant = localStorage.getItem("ugfTrInstant") !== "off";
} catch (e) {}
const shell = document.createElement("div");
shell.id = "ugf-tr";
shell.setAttribute("era", era);
document.body.appendChild(shell);
const opts = function(sel, withAuto) {
return (withAuto ? 'Detect language " : "") + langs.map(function(x) {
return '" + esc(x[1]) + " ";
}).join("");
};
// the 2006 language pairs
const pairs = [["ar", "en"], ["zh-CN", "en"], ["en", "ar"], ["en", "zh-CN"], ["en", "zh-TW"], ["en", "fr"], ["en", "de"], ["en", "it"], ["en", "ja"],
["en", "ko"], ["en", "pt"], ["en", "ru"], ["en", "es"], ["fr", "en"], ["fr", "de"], ["de", "en"], ["de", "fr"], ["it", "en"], ["ja", "en"],
["ko", "en"], ["pt", "en"], ["ru", "en"], ["es", "en"]];
// choosing a document, as each period had it
const fileIn = ' ';
const docresHtml = '
';
let h = "";
if (era === "t2006") {
h = '' +
'' +
'' +
'Translate a Document
' + fileIn + '' + pairs.map(function(p) {
return '" + esc(ugfTrName(p[0]) + " to " + ugfTrName(p[1])) + " ";
}).join("") + '
' + docresHtml + '
';
} else if (era === "t2008") {
h = '' +
'
' +
'Translate Text
Original text:
' +
'
' + opts(st.sl) + ' » ' + opts(st.tl) + '
' +
'Translate a Web Page
' +
'Translate a Document
' + docresHtml +
'';
} else if (era === "t2010") {
h = ugfNtGbar("classic", "Translate", "2010") +
'' +
'' +
'
Translate text, webpages and documents ' +
'
' + fileIn + '
' + docresHtml +
'
Languages available for translation:
' + langs.map(function(x) {
return "" + esc(x[1]) + " ";
}).join("") + "
" +
'';
} else if (kennedy) {
const group = function(side, recent) {
if (era === "t2012") {
return '";
}
return '';
};
h = (ugfNtHasGbar() ? ugfNtGbar("dark", "Translate") : "") + '' + ugfCalHeadLogo() + ugfNtHeadCorner() + "
" +
'" +
(era === "t2015" ? '' : "") +
'' + (era === "t2012" ? group("s", st.recentSl) : "") + '
' +
(era === "t2015" ? '
0/5000 ' : "") + '
× ' +
'
' + fileIn + 'Choose File No file chosen
' +
'
' +
'
' + (era === "t2012" ? group("t", st.recentTl) : "") + '
' + docresHtml +
'';
} else {
const tab = function(side, codes) {
return '";
};
h = '" +
'" +
'" +
'
" +
'
Choose a document
Upload a .docx, .pptx, .xlsx, .pdf, .odt, .rtf or .txt file.
' +
'
' + fileIn + 'Browse your computer ' +
'
' +
(l === "2022" ? '
" : "") +
"
" + docresHtml +
'' +
'";
}
shell.innerHTML = trusted_policy.createHTML(h);
ugfNtMenus(shell, material);
const $ = function(s) {
return shell.querySelector(s);
};
const src = $(".src");
src.value = st.text;
// ---- text, a document or a website
const setMode = function(m) {
st.mode = m;
shell.setAttribute("mode", m);
shell.querySelectorAll(".mt").forEach(function(a) {
a.classList.toggle("on", a.getAttribute("data-mode") === m);
});
save();
if (m === "text") {
src.focus();
} else if (m === "web" && $(".wurl")) {
$(".wurl").focus();
}
};
// Google's address for a website, translated
const webUrl = function(u, sl, tl) {
u = String(u || "").trim();
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(u)) {
u = "http://" + u;
}
return "https://translate.google.com/website?sl=" + encodeURIComponent(sl || "auto") + "&tl=" + encodeURIComponent(tl || "en") +
"&hl=en&client=webapp&u=" + encodeURIComponent(u);
};
const isUrl = function(t) {
return /^\s*((https?:\/\/)?([a-z0-9-]+\.)+[a-z]{2,}(:\d+)?(\/\S*)?|https?:\/\/\S+)\s*$/i.test(t || "") && !/\s\S/.test(String(t).trim());
};
// the document chosen
const fmtSize = function(n) {
return n < 1024 ? n + " B" : n < 1048576 ? Math.round(n / 1024) + " KB" : (n / 1048576).toFixed(1) + " MB";
};
const paintFile = function() {
shell.querySelectorAll(".fname").forEach(function(x) {
x.textContent = st.file ? st.file.name : (kennedy ? "No file chosen" : "");
});
shell.querySelectorAll(".fsize").forEach(function(x) {
x.textContent = st.file ? fmtSize(st.file.size) : "";
});
shell.classList.toggle("hasfile", !!st.file);
};
let docUrl = "";
let docSeq = 0;
const docres = $(".docres");
const runDoc = function(sl, tl) {
if (!st.file) {
docres.innerHTML = trusted_policy.createHTML('' + (material ? "Choose a document first" : "Please choose a file to translate.") + "
");
docres.style.display = "";
return;
}
sl = sl || st.sl;
tl = tl || st.tl;
const my = ++docSeq;
const file = st.file;
docres.style.display = "";
docres.innerHTML = trusted_policy.createHTML('' + (material ? "Translating…" : "Translating...") + '
');
ugfTrDoc(file, sl, tl, function(done, total) {
const pc = docres.querySelector(".pct");
if (pc && my === docSeq) {
pc.textContent = total ? Math.round(done / total * 100) + "%" : "";
}
}, function(err, r) {
if (my !== docSeq) {
return;
}
if (err) {
const why = err.message === "type" ? (material ? "This file type isn't supported" : "Sorry, this type of file cannot be translated.") :
err.message === "nopdftext" ? (material ? "No text could be found in this PDF" : "Sorry, no text could be found in this PDF.") :
err.message === "empty" ? (material ? "There's no text in this document" : "This document has no text to translate.") :
(material ? "Couldn't translate this document" : "Sorry, this document could not be translated right now.");
docres.innerHTML = trusted_policy.createHTML('' + esc(why) + "
");
return;
}
if (docUrl && /^blob:/.test(docUrl)) {
URL.revokeObjectURL(docUrl);
}
docUrl = URL.createObjectURL(r.blob);
// Firefox keeps a userscript's blob: addresses from the page, so there
// the file goes into the link itself
if (/Firefox\//.test(navigator.userAgent)) {
URL.revokeObjectURL(docUrl);
docUrl = "#";
const fr = new FileReader();
fr.onload = function() {
docUrl = String(fr.result);
const dl = docres.querySelector("a.dl");
if (dl) {
dl.setAttribute("href", docUrl);
}
};
fr.readAsDataURL(r.blob);
}
const from = sl === "auto" && r.det ? r.det : sl;
const pdf = /\.pdf$/i.test(file.name);
const slides = /\.(pptx|odp)$/i.test(file.name);
const body = function(pages) {
return pages.map(function(pg, i) {
if (!pg.length) {
return "";
}
return (pages.length > 1 && (pdf || slides) ? '' + (pdf ? "Page " : "Slide ") + (i + 1) + "
" : "") + pg.map(function(t) {
return "" + esc(t) + "
";
}).join("");
}).join("");
};
const head = esc(ugfTrName(from)) + " to " + esc(ugfTrName(tl)) + " translation";
docres.innerHTML = trusted_policy.createHTML('" +
'' + body(r.to) + "
" +
'' + body(r.from) + "
");
});
};
const chooseFile = function(f) {
if (!f) {
return;
}
st.file = f;
paintFile();
if (st.mode !== "docs" && era !== "t2006" && era !== "t2008") {
setMode("docs");
}
};
// a file dropped on the page is a document to translate
shell.addEventListener("dragover", function(ev) {
if (ev.dataTransfer && Array.prototype.indexOf.call(ev.dataTransfer.types || [], "Files") > -1) {
ev.preventDefault();
}
});
shell.addEventListener("drop", function(ev) {
const f = ev.dataTransfer && ev.dataTransfer.files && ev.dataTransfer.files[0];
if (f) {
ev.preventDefault();
chooseFile(f);
}
});
// ---- what is shown: the language buttons and the result
const paintLangs = function() {
shell.querySelectorAll("[data-qs]").forEach(function(a) {
a.classList.toggle("on", a.getAttribute("data-qs") === st.sl);
});
shell.querySelectorAll("[data-qt]").forEach(function(a) {
a.classList.toggle("on", a.getAttribute("data-qt") === st.tl);
});
// a language picked from the menu joins the quick buttons
["s", "t"].forEach(function(side) {
const cur = side === "s" ? st.sl : st.tl;
const rec = side === "s" ? st.recentSl : st.recentTl;
if (cur !== "auto" && rec.indexOf(cur) === -1) {
rec.unshift(cur);
rec.length = 3;
const holder = shell.querySelector(".quick." + side + ", .grp." + side + ", .ltabs." + side);
if (holder) {
holder.querySelectorAll("[data-q" + side + "]").forEach(function(a) {
if (a.getAttribute("data-q" + side) !== "auto") {
a.remove();
}
});
const first = side === "s" && holder.classList.contains("ltabs") ? holder.querySelector("[data-qs=auto]") : null;
rec.slice().reverse().forEach(function(c) {
const a = document.createElement("a");
a.href = "#";
if (holder.classList.contains("grp")) {
a.className = "kb";
}
a.setAttribute("data-q" + side, c);
a.textContent = material && l !== "2022" ? ugfTrName(c).toUpperCase() : ugfTrName(c);
if (first) {
first.after(a);
} else {
holder.insertBefore(a, holder.firstChild);
}
});
}
paintLangs();
}
});
const sn = $(".sln");
if (sn) {
sn.textContent = st.sl === "auto" && st.det ? ugfTrName(st.det) + " - detected" : ugfTrName(st.sl);
}
const tn = $(".tln");
if (tn) {
tn.textContent = ugfTrName(st.tl);
}
// "English - detected" on the Detect language button (2015 on)
const detBtn = shell.querySelector("[data-qs=auto]");
if (detBtn && (era === "t2015" || era === "t2019")) {
const base = era === "t2019" && l !== "2022" ? "DETECT LANGUAGE" : "Detect language";
detBtn.textContent = st.sl === "auto" && st.det ? (era === "t2019" && l !== "2022" ? ugfTrName(st.det).toUpperCase() + " - DETECTED" : ugfTrName(st.det) + " - detected") : base;
}
["sl", "tl"].forEach(function(k) {
const s = $("select." + k);
if (s && s.value !== st[k]) {
s.value = st[k];
}
});
};
const paintResult = function() {
const res = $(".res");
res.textContent = st.out;
res.classList.toggle("empty", !st.out);
const rh = $(".rh");
if (rh) {
rh.textContent = st.out ? (st.sl === "auto" && st.det ? ugfTrName(st.det) : ugfTrName(st.sl)) + " to " + ugfTrName(st.tl) + " translation" : "";
}
const resw = $(".resw");
if (resw) {
resw.style.display = st.out ? "" : "none";
}
const avail = $(".avail");
if (avail) {
avail.style.display = st.out || src.value ? "none" : "";
}
if (era === "t2006" || era === "t2008") {
res.innerHTML = trusted_policy.createHTML(st.out ? '' + esc(ugfTrName(st.sl)) + " to " + esc(ugfTrName(st.tl)) + " translation
" +
'' + esc(st.out) + "
" : "");
}
const cnt = $(".cnt");
if (cnt) {
cnt.textContent = src.value.length + (era === "t2019" ? " / 5000" : "/5000");
}
const clr = $(".clr");
if (clr) {
clr.style.visibility = src.value ? "visible" : "hidden";
}
};
// ---- translating
let seq = 0;
let timer = 0;
const save = function() {
try {
history.replaceState(history.state, "", "/?sl=" + encodeURIComponent(st.sl) + "&tl=" + encodeURIComponent(st.tl) +
(src.value && st.mode === "text" ? "&text=" + encodeURIComponent(src.value.slice(0, 1500)) : "") +
"&op=" + (st.mode === "docs" ? "docs" : st.mode === "web" ? "websites" : "translate"));
} catch (e) {}
};
const run = function() {
clearTimeout(timer);
if (st.mode !== "text") {
return;
}
const text = src.value;
save();
// a website address: a link to the website, translated
if (isUrl(text) && era !== "t2006" && era !== "t2008") {
++seq;
st.out = "";
st.det = "";
paintResult();
const res = $(".res");
const u = text.trim();
res.classList.remove("empty");
res.innerHTML = trusted_policy.createHTML('' + esc(u) + " ");
const resw = $(".resw");
if (resw) {
resw.style.display = "";
}
const avail = $(".avail");
if (avail) {
avail.style.display = "none";
}
return;
}
if (!text.trim()) {
st.out = "";
st.det = "";
paintResult();
paintLangs();
return;
}
const my = ++seq;
ugfTrTranslate(text.slice(0, 5000), st.sl, st.tl, function(err, out, det) {
if (my !== seq) {
return;
}
if (err) {
st.out = "";
$(".res").textContent = material ? "Translation error" : "Sorry, we could not translate this text right now.";
return;
}
st.out = out;
st.det = st.sl === "auto" ? det : "";
paintResult();
paintLangs();
});
};
const soon = function() {
clearTimeout(timer);
if (st.instant || material) {
timer = setTimeout(run, 400);
}
paintResult();
};
src.addEventListener("input", soon);
src.addEventListener("keydown", function(ev) {
if (ev.key === "Enter" && (ev.ctrlKey || ev.metaKey)) {
ev.preventDefault();
run();
}
});
// choosing a language: the same one on both sides swaps them, as Google did
const pick = function(side, code) {
if (side === "s") {
if (code !== "auto" && code === st.tl) {
st.tl = st.sl === "auto" ? (st.det && st.det !== code ? st.det : (code === "en" ? "es" : "en")) : st.sl;
}
st.sl = code;
} else {
if (code === st.sl) {
st.sl = st.tl;
}
st.tl = code;
}
};
// ---- the language menus (2011 on): every language in columns
let menu = null;
const closeMenu = function() {
if (menu) {
menu.remove();
menu = null;
}
};
const openMenu = function(anchor, side) {
const again = menu && menu.getAttribute("data-side") === side;
closeMenu();
if (again) {
return;
}
menu = document.createElement("div");
menu.className = "lmenu";
menu.setAttribute("data-side", side);
const cur = side === "s" ? st.sl : st.tl;
const list = (side === "s" ? [["auto", "Detect language"]] : []).concat(langs);
menu.innerHTML = trusted_policy.createHTML(list.map(function(x) {
return '' + (material && x[0] === cur ? ugfNtIcon("check", 18) : "") + esc(x[1]) + " ";
}).join(""));
// down the columns, as Google listed them
menu.style.gridTemplateRows = "repeat(" + Math.ceil(list.length / (material ? 6 : 8)) + ", auto)";
shell.appendChild(menu);
const r = anchor.getBoundingClientRect();
const sr = shell.getBoundingClientRect();
menu.style.top = (r.bottom - sr.top + shell.scrollTop + 2) + "px";
menu.style.left = Math.max(8, Math.min(material ? 16 : r.left - sr.left, sr.width - menu.offsetWidth - 16)) + "px";
menu.addEventListener("click", function(ev) {
const a = ev.target.closest("[data-pick]");
if (!a) {
return;
}
ev.preventDefault();
pick(side, a.getAttribute("data-pick"));
closeMenu();
paintLangs();
run();
});
};
document.addEventListener("mousedown", function(ev) {
if (menu && !menu.contains(ev.target) && !ev.target.closest("[data-menu]")) {
closeMenu();
}
}, true);
// ---- clicks
shell.addEventListener("click", function(ev) {
const a = ev.target.closest("a, input[type=button]");
if (!a || !shell.contains(a)) {
return;
}
const qs = a.getAttribute("data-qs");
const qt = a.getAttribute("data-qt");
if (qs || qt) {
ev.preventDefault();
if (qs) {
pick("s", qs);
} else {
pick("t", qt);
}
paintLangs();
run();
return;
}
const m = a.getAttribute("data-menu");
if (m) {
ev.preventDefault();
openMenu(a, m);
return;
}
if (a.classList.contains("mt")) {
ev.preventDefault();
setMode(a.getAttribute("data-mode"));
return;
}
if (a.classList.contains("todoc") || a.classList.contains("nodoc")) {
ev.preventDefault();
setMode(a.classList.contains("todoc") ? "docs" : "text");
return;
}
if (a.classList.contains("unpick")) {
ev.preventDefault();
st.file = null;
shell.querySelectorAll(".docfile").forEach(function(x) {
x.value = "";
});
paintFile();
return;
}
if (a.classList.contains("godoc")) {
ev.preventDefault();
if ($(".pair3")) {
const p = $(".pair3").value.split("|");
runDoc(p[0], p[1]);
} else {
runDoc($(".sl3").value, $(".tl3").value);
}
return;
}
if (a.classList.contains("vw")) {
ev.preventDefault();
const v = a.getAttribute("data-v");
docres.querySelectorAll(".vw").forEach(function(x) {
x.classList.toggle("on", x === a);
});
docres.querySelectorAll(".dbody").forEach(function(x) {
x.style.display = x.classList.contains(v) ? "" : "none";
});
return;
}
if (a.classList.contains("go") && st.mode === "docs") {
ev.preventDefault();
runDoc();
return;
}
if (a.classList.contains("goweb") && $(".wurl")) {
ev.preventDefault();
const u = $(".wurl").value.trim();
if (u) {
window.location.href = webUrl(u, st.sl, st.tl);
}
return;
}
if (a.classList.contains("go")) {
ev.preventDefault();
if (era === "t2006") {
const p = $(".pair").value.split("|");
st.sl = p[0];
st.tl = p[1];
}
run();
} else if (a.classList.contains("swap")) {
ev.preventDefault();
const from = st.sl === "auto" ? (st.det || "en") : st.sl;
st.sl = st.tl;
st.tl = from;
if (st.out) {
src.value = st.out;
}
paintLangs();
run();
} else if (a.classList.contains("clr")) {
ev.preventDefault();
src.value = "";
run();
src.focus();
} else if (a.classList.contains("instant")) {
ev.preventDefault();
st.instant = !st.instant;
try {
localStorage.setItem("ugfTrInstant", st.instant ? "on" : "off");
} catch (e) {}
a.textContent = st.instant ? "Turn off instant translation" : "Turn on instant translation";
} else if (a.classList.contains("goweb")) {
ev.preventDefault();
const u = $(".url").value.trim();
let sl = "auto";
let tl = "en";
if ($(".pair2")) {
const p = $(".pair2").value.split("|");
sl = p[0];
tl = p[1];
} else if ($(".sl2")) {
sl = $(".sl2").value;
tl = $(".tl2").value;
}
if (u && u !== "http://") {
window.location.href = webUrl(u, sl, tl);
}
} else if (a.classList.contains("listen")) {
ev.preventDefault();
const isSrc = a.classList.contains("s");
const text = isSrc ? src.value : st.out;
const lang = isSrc ? (st.sl === "auto" ? st.det || "en" : st.sl) : st.tl;
if (text) {
new Audio("/translate_tts?ie=UTF-8&client=tw-ob&tl=" + encodeURIComponent(lang) + "&q=" + encodeURIComponent(text.slice(0, 200))).play().catch(function() {});
}
} else if (a.classList.contains("copy")) {
ev.preventDefault();
if (st.out && navigator.clipboard) {
navigator.clipboard.writeText(st.out).catch(function() {});
}
}
});
shell.addEventListener("keydown", function(ev) {
if (ev.key === "Enter" && ev.target.matches && ev.target.matches(".wurl")) {
ev.preventDefault();
const u = ev.target.value.trim();
if (u) {
window.location.href = webUrl(u, st.sl, st.tl);
}
}
});
shell.addEventListener("change", function(ev) {
const s = ev.target;
if (s.matches(".docfile")) {
chooseFile(s.files && s.files[0]);
return;
}
if (s.matches("select.sl, select.tl")) {
pick(s.classList.contains("sl") ? "s" : "t", s.value);
if (st.instant && era !== "t2006" && era !== "t2008") {
run();
}
paintLangs();
} else if (s.matches("select.pair")) {
const p = s.value.split("|");
st.sl = p[0];
st.tl = p[1];
}
});
paintLangs();
paintResult();
paintFile();
setMode(st.mode);
if (st.text) {
run();
}
if (st.mode === "text") {
src.focus();
}
}
// ---- translating a document ----------------------------------------------------
// Done here, as the Translate of 2009-2019 did it: the file is read in the browser,
// its text sent to Google's translation service in batches, and the translation
// shown as a page, with the translated file to download - a Word, PowerPoint,
// Excel or OpenDocument file comes back in its own format with its formatting.
// Nothing is uploaded anywhere but the text itself, to Google's translator.
//
// Many pieces of text in one request: cb(err, [translations], detected)
function ugfTrBatch(parts, sl, tl, cb) {
const url = "https://clients5.google.com/translate_a/t?client=dict-chrome-ex&sl=" + encodeURIComponent(sl) + "&tl=" + encodeURIComponent(tl);
const body = parts.map(function(p) {
return "q=" + encodeURIComponent(p);
}).join("&");
ugfTrGet(url, body, function(status, txt) {
try {
if (status !== 200) {
throw new Error("HTTP " + status);
}
const j = JSON.parse(txt);
let det = "";
const out = (Array.isArray(j) ? j : [j]).map(function(x) {
if (Array.isArray(x)) {
det = det || x[1] || "";
return String(x[0] || "");
}
return String(x || "");
});
if (out.length !== parts.length) {
throw new Error("count");
}
cb(null, out, det);
} catch (e) {
// one at a time, then
const outs = [];
let det = "";
let i = 0;
const next = function() {
if (i >= parts.length) {
cb(null, outs, det);
return;
}
ugfTrTranslate(parts[i], sl, tl, function(err, o, d) {
if (err) {
cb(err);
return;
}
outs.push(o);
det = det || d || "";
i++;
next();
});
};
next();
}
});
}
// All the pieces, in batches of about 4000 characters. Long pieces are cut at
// sentence ends first. progress(done, total); cb(err, [translations], detected)
function ugfTrMany(texts, sl, tl, progress, cb) {
const LIMIT = 4000;
// pieces that are only spaces, numbers or marks are not sent
const worth = function(t) {
return /[^\s\d\W_]|[À-]/.test(t || "");
};
const jobs = []; // [indexInTexts, subIndex, text]
const cut = function(t) {
if (t.length <= LIMIT) {
return [t];
}
const out = [];
let rest = t;
while (rest.length > LIMIT) {
let at = -1;
const head = rest.slice(0, LIMIT);
const m = head.match(/[\s\S]*[.!?。!?]\s/);
at = m ? m[0].length : head.lastIndexOf(" ");
if (at < LIMIT / 3) {
at = LIMIT;
}
out.push(rest.slice(0, at));
rest = rest.slice(at);
}
out.push(rest);
return out;
};
texts.forEach(function(t, i) {
if (worth(t)) {
cut(t).forEach(function(p, k) {
jobs.push([i, k, p]);
});
}
});
const res = texts.map(function(t) {
return worth(t) ? [] : t;
});
const batches = [];
let cur = [];
let size = 0;
jobs.forEach(function(j) {
if (cur.length && (size + j[2].length > LIMIT || cur.length >= 90)) {
batches.push(cur);
cur = [];
size = 0;
}
cur.push(j);
size += j[2].length;
});
if (cur.length) {
batches.push(cur);
}
let done = 0;
let det = "";
let bi = 0;
const next = function() {
if (bi >= batches.length) {
cb(null, res.map(function(r) {
return Array.isArray(r) ? r.join("") : r;
}), det);
return;
}
const b = batches[bi];
ugfTrBatch(b.map(function(j) {
return j[2];
}), sl, tl, function(err, outs, d) {
if (err) {
cb(err);
return;
}
det = det || d || "";
b.forEach(function(j, k) {
// keep the spaces the piece began and ended with
const lead = (j[2].match(/^\s*/) || [""])[0];
const trail = (j[2].match(/\s*$/) || [""])[0];
res[j[0]][j[1]] = lead + String(outs[k]).trim() + trail;
});
done += b.length;
if (progress) {
progress(done, jobs.length);
}
bi++;
next();
});
};
if (progress) {
progress(0, jobs.length);
}
next();
}
// ---- ZIP files (Office and OpenDocument files are ZIP files) ----------------------
function ugfTrCrcTable() {
if (!ugfTrCrcTable.t) {
const t = new Uint32Array(256);
for (let n = 0; n < 256; n++) {
let c = n;
for (let k = 0; k < 8; k++) {
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
}
t[n] = c >>> 0;
}
ugfTrCrcTable.t = t;
}
return ugfTrCrcTable.t;
}
function ugfTrCrc(bytes) {
const t = ugfTrCrcTable();
let c = 0xffffffff;
for (let i = 0; i < bytes.length; i++) {
c = t[(c ^ bytes[i]) & 0xff] ^ (c >>> 8);
}
return (c ^ 0xffffffff) >>> 0;
}
// Deflate through the browser's own streams; where a userscript manager keeps
// those out of reach, inflating is done here and compressing is left out
function ugfTrStream(bytes, how, compress) {
const fallback = function() {
if (compress) {
return Promise.reject(new Error("nocompress"));
}
try {
return Promise.resolve(ugfTrInflate(how === "deflate" ? bytes.subarray(2) : bytes));
} catch (e) {
return Promise.reject(e);
}
};
try {
const S = compress ? CompressionStream : DecompressionStream;
const s = new Blob([bytes]).stream().pipeThrough(new S(how));
return new Response(s).arrayBuffer().then(function(b) {
return new Uint8Array(b);
}).catch(fallback);
} catch (e) {
return fallback();
}
}
// a small inflater (after zlib's "puff")
function ugfTrInflate(src) {
let pos = 0;
let bitbuf = 0;
let bitcnt = 0;
let out = new Uint8Array(Math.max(4096, src.length * 4));
let olen = 0;
const room = function(n) {
if (olen + n > out.length) {
const nb = new Uint8Array(Math.max(out.length * 2, olen + n));
nb.set(out.subarray(0, olen));
out = nb;
}
};
const bits = function(n) {
let v = 0;
for (let i = 0; i < n; i++) {
if (!bitcnt) {
if (pos >= src.length) {
throw new Error("inflate: end of data");
}
bitbuf = src[pos++];
bitcnt = 8;
}
v |= (bitbuf & 1) << i;
bitbuf >>>= 1;
bitcnt--;
}
return v;
};
const build = function(lengths) {
const count = new Uint16Array(16);
const offs = new Uint16Array(16);
for (let i = 0; i < lengths.length; i++) {
count[lengths[i]]++;
}
count[0] = 0;
for (let i = 1; i < 16; i++) {
offs[i] = offs[i - 1] + count[i - 1];
}
const symbol = new Uint16Array(lengths.length);
for (let i = 0; i < lengths.length; i++) {
if (lengths[i]) {
symbol[offs[lengths[i]]++] = i;
}
}
return { count: count, symbol: symbol };
};
const decode = function(h) {
let code = 0;
let first = 0;
let index = 0;
for (let len = 1; len < 16; len++) {
code |= bits(1);
const c = h.count[len];
if (code - c < first) {
return h.symbol[index + (code - first)];
}
index += c;
first += c;
first <<= 1;
code <<= 1;
}
throw new Error("inflate: bad code");
};
const LB = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258];
const LE = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];
const DB = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577];
const DE = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
const codes = function(lit, dist) {
for (;;) {
let sym = decode(lit);
if (sym < 256) {
room(1);
out[olen++] = sym;
} else if (sym === 256) {
return;
} else {
sym -= 257;
if (sym >= 29) {
throw new Error("inflate: bad length");
}
const len = LB[sym] + bits(LE[sym]);
const ds = decode(dist);
const d = DB[ds] + bits(DE[ds]);
if (d > olen) {
throw new Error("inflate: bad distance");
}
room(len);
for (let i = 0; i < len; i++) {
out[olen] = out[olen - d];
olen++;
}
}
}
};
let fixed = null;
let last = 0;
do {
last = bits(1);
const type = bits(2);
if (type === 0) {
bitbuf = 0;
bitcnt = 0;
const len = src[pos] | (src[pos + 1] << 8);
pos += 4;
room(len);
out.set(src.subarray(pos, pos + len), olen);
olen += len;
pos += len;
} else if (type === 1) {
if (!fixed) {
const l = new Uint8Array(288);
for (let i = 0; i < 288; i++) {
l[i] = i < 144 ? 8 : i < 256 ? 9 : i < 280 ? 7 : 8;
}
const dl = new Uint8Array(30).fill(5);
fixed = [build(l), build(dl)];
}
codes(fixed[0], fixed[1]);
} else if (type === 2) {
const nlen = bits(5) + 257;
const ndist = bits(5) + 1;
const ncode = bits(4) + 4;
const order = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
const cl = new Uint8Array(19);
for (let i = 0; i < ncode; i++) {
cl[order[i]] = bits(3);
}
const lencode = build(cl);
const lens = new Uint8Array(nlen + ndist);
for (let i = 0; i < nlen + ndist;) {
const sym = decode(lencode);
if (sym < 16) {
lens[i++] = sym;
} else {
let rep = 0;
let val = 0;
if (sym === 16) {
if (!i) {
throw new Error("inflate: bad repeat");
}
val = lens[i - 1];
rep = 3 + bits(2);
} else if (sym === 17) {
rep = 3 + bits(3);
} else {
rep = 11 + bits(7);
}
while (rep-- && i < nlen + ndist) {
lens[i++] = val;
}
}
}
codes(build(lens.subarray(0, nlen)), build(lens.subarray(nlen)));
} else {
throw new Error("inflate: bad block");
}
} while (!last);
return out.slice(0, olen);
}
// the entries of a ZIP file: [{ name, method, crc, csize, usize, data (as stored), extra }]
function ugfTrUnzip(buf) {
const u8 = new Uint8Array(buf);
const dv = new DataView(u8.buffer, u8.byteOffset, u8.byteLength);
let eocd = -1;
for (let i = u8.length - 22; i >= Math.max(0, u8.length - 70000); i--) {
if (dv.getUint32(i, true) === 0x06054b50) {
eocd = i;
break;
}
}
if (eocd < 0) {
throw new Error("not a zip");
}
const count = dv.getUint16(eocd + 10, true);
let p = dv.getUint32(eocd + 16, true);
const out = [];
const dec = new TextDecoder("utf-8");
for (let n = 0; n < count; n++) {
if (dv.getUint32(p, true) !== 0x02014b50) {
throw new Error("bad zip");
}
const method = dv.getUint16(p + 10, true);
const crc = dv.getUint32(p + 16, true);
const csize = dv.getUint32(p + 20, true);
const usize = dv.getUint32(p + 24, true);
const nl = dv.getUint16(p + 28, true);
const el = dv.getUint16(p + 30, true);
const cl = dv.getUint16(p + 32, true);
const lh = dv.getUint32(p + 42, true);
const name = dec.decode(u8.subarray(p + 46, p + 46 + nl));
const lnl = dv.getUint16(lh + 26, true);
const lel = dv.getUint16(lh + 28, true);
const start = lh + 30 + lnl + lel;
out.push({ name: name, method: method, crc: crc, csize: csize, usize: usize, data: u8.subarray(start, start + csize) });
p += 46 + nl + el + cl;
}
return out;
}
function ugfTrEntryText(e) {
const dec = new TextDecoder("utf-8");
if (e.method === 0) {
return Promise.resolve(dec.decode(e.data));
}
return ugfTrStream(e.data, "deflate-raw", false).then(function(b) {
return dec.decode(b);
});
}
// a ZIP file again: changed entries (e.text) compressed afresh, the rest as they were
function ugfTrZip(entries) {
const enc = new TextEncoder();
return Promise.all(entries.map(function(e) {
if (e.text === undefined) {
return Promise.resolve(e);
}
const raw = enc.encode(e.text);
// the mimetype entry of an OpenDocument file stays uncompressed
if (e.name === "mimetype") {
return Promise.resolve({ name: e.name, method: 0, crc: ugfTrCrc(raw), csize: raw.length, usize: raw.length, data: raw });
}
return ugfTrStream(raw, "deflate-raw", true).then(function(c) {
return { name: e.name, method: 8, crc: ugfTrCrc(raw), csize: c.length, usize: raw.length, data: c };
}, function() {
return { name: e.name, method: 0, crc: ugfTrCrc(raw), csize: raw.length, usize: raw.length, data: raw };
});
})).then(function(list) {
const parts = [];
const central = [];
let off = 0;
list.forEach(function(e) {
const nm = enc.encode(e.name);
const lh = new Uint8Array(30 + nm.length);
const lv = new DataView(lh.buffer);
lv.setUint32(0, 0x04034b50, true);
lv.setUint16(4, 20, true);
lv.setUint16(6, 0x0800, true);
lv.setUint16(8, e.method, true);
lv.setUint16(10, 0, true);
lv.setUint16(12, 0x21, true);
lv.setUint32(14, e.crc, true);
lv.setUint32(18, e.csize, true);
lv.setUint32(22, e.usize, true);
lv.setUint16(26, nm.length, true);
lh.set(nm, 30);
const ch = new Uint8Array(46 + nm.length);
const cv = new DataView(ch.buffer);
cv.setUint32(0, 0x02014b50, true);
cv.setUint16(4, 20, true);
cv.setUint16(6, 20, true);
cv.setUint16(8, 0x0800, true);
cv.setUint16(10, e.method, true);
cv.setUint16(14, 0x21, true);
cv.setUint32(16, e.crc, true);
cv.setUint32(20, e.csize, true);
cv.setUint32(24, e.usize, true);
cv.setUint16(28, nm.length, true);
cv.setUint32(42, off, true);
ch.set(nm, 46);
parts.push(lh, e.data);
central.push(ch);
off += lh.length + e.data.length;
});
let csize = 0;
central.forEach(function(c) {
csize += c.length;
});
const end = new Uint8Array(22);
const ev = new DataView(end.buffer);
ev.setUint32(0, 0x06054b50, true);
ev.setUint16(8, list.length, true);
ev.setUint16(10, list.length, true);
ev.setUint32(12, csize, true);
ev.setUint32(16, off, true);
return new Blob(parts.concat(central, [end]));
});
}
// ---- the paragraphs of an Office or OpenDocument file ----------------------------
// Which parts of the file hold text, and what a paragraph and a piece of its text
// are called in them. A paragraph's translation goes into its first piece, the
// others are emptied, so the paragraph keeps the look of its beginning.
function ugfTrOfficeKind(name) {
const ext = (name.match(/\.([a-z0-9]+)$/i) || ["", ""])[1].toLowerCase();
if (ext === "docx" || ext === "docm" || ext === "dotx") {
return { ext: ext, parts: /^word\/(document|header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/, para: "p", piece: "t", ns: "http://schemas.openxmlformats.org/wordprocessingml/2006/main", mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" };
}
if (ext === "pptx" || ext === "ppsx") {
return { ext: ext, parts: /^ppt\/(slides\/slide\d+|notesSlides\/notesSlide\d+)\.xml$/, para: "p", piece: "t", ns: "http://schemas.openxmlformats.org/drawingml/2006/main", mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation", order: /slide(\d+)\.xml$/ };
}
if (ext === "xlsx") {
return { ext: ext, parts: /^xl\/(sharedStrings|worksheets\/sheet\d+)\.xml$/, para: ["si", "is"], piece: "t", ns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main", mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", order: /(\d+)\.xml$/ };
}
if (ext === "odt" || ext === "odp" || ext === "ods") {
return { ext: ext, parts: /^content\.xml$/, odf: true, mime: { odt: "application/vnd.oasis.opendocument.text", odp: "application/vnd.oasis.opendocument.presentation", ods: "application/vnd.oasis.opendocument.spreadsheet" }[ext] };
}
return null;
}
// the paragraphs of one XML part: [{ pieces: [text node holders], text }]
function ugfTrXmlParas(doc, kind) {
const out = [];
if (kind.odf) {
const T = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
const ps = Array.prototype.filter.call(doc.getElementsByTagNameNS(T, "*"), function(e) {
return e.localName === "p" || e.localName === "h";
});
ps.forEach(function(p) {
const pieces = [];
const walk = function(n) {
for (let c = n.firstChild; c; c = c.nextSibling) {
if (c.nodeType === 3) {
pieces.push(c);
} else if (c.nodeType === 1 && !(c.namespaceURI === T && (c.localName === "p" || c.localName === "h" || c.localName === "note"))) {
walk(c);
}
}
};
walk(p);
const text = pieces.map(function(x) {
return x.nodeValue;
}).join("");
if (text.trim()) {
out.push({ pieces: pieces, text: text, set: function(v) {
pieces[0].nodeValue = v;
for (let i = 1; i < pieces.length; i++) {
pieces[i].nodeValue = "";
}
} });
}
});
return out;
}
const paraNames = [].concat(kind.para);
const ps = Array.prototype.filter.call(doc.getElementsByTagNameNS(kind.ns, "*"), function(e) {
return paraNames.indexOf(e.localName) > -1;
});
ps.forEach(function(p) {
// not the paragraphs inside this one (a text box in a paragraph has its own)
const pieces = Array.prototype.filter.call(p.getElementsByTagNameNS(kind.ns, kind.piece), function(t) {
let a = t.parentNode;
while (a && a !== p) {
if (a.namespaceURI === kind.ns && paraNames.indexOf(a.localName) > -1) {
return false;
}
a = a.parentNode;
}
return true;
});
const text = pieces.map(function(t) {
return t.textContent;
}).join("");
if (text.trim()) {
out.push({ pieces: pieces, text: text, set: function(v) {
pieces[0].textContent = v;
pieces[0].setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:space", "preserve");
for (let i = 1; i < pieces.length; i++) {
pieces[i].textContent = "";
}
} });
}
});
return out;
}
function ugfTrA85(b) {
const out = [];
let tuple = 0;
let cnt = 0;
let i = 0;
if (b[0] === 60 && b[1] === 126) {
i = 2;
}
for (; i < b.length; i++) {
const c = b[i];
if (c === 126) {
break;
}
if (c <= 32) {
continue;
}
if (c === 122 && cnt === 0) {
out.push(0, 0, 0, 0);
continue;
}
tuple = tuple * 85 + (c - 33);
cnt++;
if (cnt === 5) {
out.push((tuple >>> 24) & 255, (tuple >>> 16) & 255, (tuple >>> 8) & 255, tuple & 255);
tuple = 0;
cnt = 0;
}
}
if (cnt) {
for (let k = cnt; k < 5; k++) {
tuple = tuple * 85 + 84;
}
const bytes = [(tuple >>> 24) & 255, (tuple >>> 16) & 255, (tuple >>> 8) & 255, tuple & 255];
for (let k = 0; k < cnt - 1; k++) {
out.push(bytes[k]);
}
}
return new Uint8Array(out);
}
// the glyph names of PDF fonts that are not simply their letter
function ugfTrGlyphNames() {
if (!ugfTrGlyphNames.m) {
const m = { space: " ", exclam: "!", quotedbl: "\"", numbersign: "#", dollar: "$", percent: "%", ampersand: "&", quotesingle: "'", quoteright: "\u2019", quoteleft: "\u2018",
parenleft: "(", parenright: ")", asterisk: "*", plus: "+", comma: ",", hyphen: "-", minus: "\u2212", period: ".", slash: "/", colon: ":", semicolon: ";", less: "<", equal: "=",
greater: ">", question: "?", at: "@", bracketleft: "[", backslash: "\\", bracketright: "]", asciicircum: "^", underscore: "_", grave: "`", braceleft: "{", bar: "|",
braceright: "}", asciitilde: "~", quotedblleft: "\u201c", quotedblright: "\u201d", quotedblbase: "\u201e", quotesinglbase: "\u201a", endash: "\u2013", emdash: "\u2014",
bullet: "\u2022", ellipsis: "\u2026", fi: "fi", fl: "fl", ff: "ff", ffi: "ffi", ffl: "ffl", germandbls: "\u00df", ae: "\u00e6", AE: "\u00c6", oe: "\u0153", OE: "\u0152",
oslash: "\u00f8", Oslash: "\u00d8", dagger: "\u2020", daggerdbl: "\u2021", degree: "\u00b0", copyright: "\u00a9", registered: "\u00ae", trademark: "\u2122",
section: "\u00a7", paragraph: "\u00b6", periodcentered: "\u00b7", nbspace: "\u00a0", dotlessi: "\u0131", guillemotleft: "\u00ab", guillemotright: "\u00bb",
zero: "0", one: "1", two: "2", three: "3", four: "4", five: "5", six: "6", seven: "7", eight: "8", nine: "9", Euro: "\u20ac", sterling: "\u00a3", yen: "\u00a5", cent: "\u00a2" };
// letters with accents: aacute, Egrave, ntilde and the rest
const marks = { acute: "\u0301", grave: "\u0300", circumflex: "\u0302", dieresis: "\u0308", tilde: "\u0303", ring: "\u030a", cedilla: "\u0327", caron: "\u030c" };
"aeiouyAEIOUYncNCszSZ".split("").forEach(function(l) {
Object.keys(marks).forEach(function(k) {
const c = (l + marks[k]).normalize("NFC");
if (c.length === 1) {
m[l + k] = c;
}
});
});
ugfTrGlyphNames.m = m;
}
return ugfTrGlyphNames.m;
}
// ---- the text of a PDF ---------------------------------------------------------
// Enough of a PDF reader for its words: the objects (object streams too), Flate
// streams, each font's ToUnicode map, and the text operators of each page.
function ugfTrPdfText(buf) {
const u8 = new Uint8Array(buf);
const latin = function(a, b) {
let s = "";
for (let i = a; i < b; i += 8192) {
s += String.fromCharCode.apply(null, u8.subarray(i, Math.min(b, i + 8192)));
}
return s;
};
const all = latin(0, u8.length);
// a small parser of PDF values
const parse = function(s, pos) {
const ws = function() {
for (;;) {
while (pos < s.length && /[\s\0]/.test(s[pos])) {
pos++;
}
if (s[pos] === "%") {
while (pos < s.length && s[pos] !== "\n" && s[pos] !== "\r") {
pos++;
}
} else {
return;
}
}
};
const val = function() {
ws();
const c = s[pos];
if (c === "<" && s[pos + 1] === "<") {
pos += 2;
const d = { __dict: true };
for (;;) {
ws();
if (s[pos] === ">" && s[pos + 1] === ">") {
pos += 2;
return d;
}
if (pos >= s.length) {
return d;
}
const k = val();
const v = val();
if (k && k.name) {
d[k.name] = v;
}
}
}
if (c === "<") {
const e = s.indexOf(">", pos);
const hex = s.slice(pos + 1, e).replace(/[^0-9a-f]/gi, "");
pos = e + 1;
const bytes = [];
for (let i = 0; i < hex.length; i += 2) {
bytes.push(parseInt((hex[i] || "0") + (hex[i + 1] || "0"), 16));
}
return { str: bytes };
}
if (c === "(") {
pos++;
let depth = 1;
const bytes = [];
while (pos < s.length) {
let ch = s[pos++];
if (ch === "\\") {
ch = s[pos++];
const map = { n: 10, r: 13, t: 9, b: 8, f: 12 };
if (map[ch] !== undefined) {
bytes.push(map[ch]);
} else if (/[0-7]/.test(ch)) {
let o = ch;
while (o.length < 3 && /[0-7]/.test(s[pos])) {
o += s[pos++];
}
bytes.push(parseInt(o, 8) & 255);
} else if (ch === "\r") {
if (s[pos] === "\n") {
pos++;
}
} else if (ch !== "\n") {
bytes.push(ch.charCodeAt(0));
}
continue;
}
if (ch === "(") {
depth++;
} else if (ch === ")") {
depth--;
if (!depth) {
break;
}
}
bytes.push(ch.charCodeAt(0));
}
return { str: bytes };
}
if (c === "[") {
pos++;
const a = [];
for (;;) {
ws();
if (s[pos] === "]" || pos >= s.length) {
pos++;
return a;
}
a.push(val());
}
}
if (c === "/") {
const m = /^\/([^\s\/\[\]()<>{}%]*)/.exec(s.slice(pos, pos + 128));
pos += m[0].length;
return { name: m[1].replace(/#([0-9a-f]{2})/gi, function(x, h) {
return String.fromCharCode(parseInt(h, 16));
}) };
}
const m = /^([+-]?(\d+\.?\d*|\.\d+))(\s+(\d+)\s+R(?![A-Za-z]))?/.exec(s.slice(pos, pos + 40));
if (m) {
pos += m[0].length;
return m[3] ? { ref: +m[1] } : +m[1];
}
const w = /^[A-Za-z'"*]+/.exec(s.slice(pos, pos + 32));
if (w) {
pos += w[0].length;
return { op: w[0] };
}
pos++;
return null;
};
return { val: val, at: function() {
return pos;
}, set: function(p) {
pos = p;
}, ws: ws };
};
// every object: its dictionary and, for a stream, where its bytes are
const objs = {};
const re = /(\d+)\s+(\d+)\s+obj\b/g;
let m;
while ((m = re.exec(all))) {
const p = parse(all, m.index + m[0].length);
let v = null;
try {
v = p.val();
} catch (e) {
continue;
}
const o = { v: v };
p.ws();
const after = p.at();
if (all.slice(after, after + 6) === "stream") {
let s0 = after + 6;
if (all[s0] === "\r") {
s0++;
}
if (all[s0] === "\n") {
s0++;
}
let len = v && typeof v.Length === "number" ? v.Length : -1;
let e0 = len >= 0 ? s0 + len : all.indexOf("endstream", s0);
if (all.slice(e0, e0 + 20).indexOf("endstream") < 0) {
e0 = all.indexOf("endstream", s0);
}
o.s = [s0, e0];
o.lenRef = v && v.Length && v.Length.ref;
}
objs[+m[1]] = o;
}
const decode = function(o) {
if (!o || !o.s) {
return Promise.resolve(null);
}
if (o.bytes) {
return Promise.resolve(o.bytes);
}
let [s0, e0] = o.s;
if (o.lenRef && objs[o.lenRef] && typeof objs[o.lenRef].v === "number") {
e0 = s0 + objs[o.lenRef].v;
}
let raw = u8.subarray(s0, e0);
let f = o.v.Filter;
f = Array.isArray(f) ? f.map(function(x) {
return x.name;
}) : f ? [f.name] : [];
if (!f.length) {
o.bytes = raw;
return Promise.resolve(raw);
}
// ASCII85 (ReportLab writes it) before Flate
if (f[0] === "ASCII85Decode" || f[0] === "A85") {
raw = ugfTrA85(raw);
f = f.slice(1);
if (!f.length) {
o.bytes = raw;
return Promise.resolve(raw);
}
}
if (f.length === 1 && (f[0] === "FlateDecode" || f[0] === "Fl")) {
return ugfTrStream(raw, "deflate", false).catch(function() {
return ugfTrStream(raw.subarray(2), "deflate-raw", false);
}).then(function(b) {
const pr = o.v.DecodeParms;
if (pr && pr.Predictor >= 10) {
const cols = (pr.Columns || 1) + 1;
const rows = Math.floor(b.length / cols);
const outp = new Uint8Array(rows * (cols - 1));
const prev = new Uint8Array(cols - 1);
for (let r = 0; r < rows; r++) {
const t = b[r * cols];
for (let c = 0; c < cols - 1; c++) {
let x = b[r * cols + 1 + c];
if (t === 2) {
x = (x + prev[c]) & 255;
}
prev[c] = x;
outp[r * (cols - 1) + c] = x;
}
}
b = outp;
}
o.bytes = b;
return b;
}).catch(function() {
return null;
});
}
return Promise.resolve(null);
};
const str = function(b) {
let s = "";
for (let i = 0; i < b.length; i += 8192) {
s += String.fromCharCode.apply(null, b.subarray(i, Math.min(b.length, i + 8192)));
}
return s;
};
// objects kept in object streams
const objStreams = Object.keys(objs).filter(function(k) {
const v = objs[k].v;
return v && v.Type && v.Type.name === "ObjStm";
});
return Promise.all(objStreams.map(function(k) {
return decode(objs[k]).then(function(b) {
if (!b) {
return;
}
const s = str(b);
const v = objs[k].v;
const head = parse(s, 0);
const nums = [];
for (let i = 0; i < v.N; i++) {
nums.push([head.val(), head.val()]);
}
nums.forEach(function(x) {
if (objs[x[0]] && objs[x[0]].s) {
return;
}
const p = parse(s, v.First + x[1]);
try {
objs[x[0]] = { v: p.val() };
} catch (e) {}
});
});
})).then(function() {
const get = function(v) {
let n = 0;
while (v && v.ref !== undefined && n++ < 20) {
v = objs[v.ref] ? objs[v.ref].v : null;
}
return v;
};
// the pages, in order
let root = null;
Object.keys(objs).forEach(function(k) {
const v = objs[k].v;
if (v && v.Type && v.Type.name === "Catalog") {
root = v;
}
});
const pages = [];
const seen = {};
const walk = function(node, inherited, id) {
if (!node || (id && seen[id])) {
return;
}
if (id) {
seen[id] = true;
}
const res = node.Resources ? get(node.Resources) : inherited;
if (node.Kids) {
(get(node.Kids) || []).forEach(function(k) {
walk(get(k), res, k.ref);
});
} else if (node.Contents !== undefined) {
pages.push({ node: node, res: res });
}
};
if (root) {
walk(get(root.Pages), null, 0);
}
if (!pages.length) {
Object.keys(objs).forEach(function(k) {
const v = objs[k].v;
if (v && v.Type && v.Type.name === "Page") {
pages.push({ node: v, res: get(v.Resources) });
}
});
}
// a font's map from codes to text
const cmaps = {};
const fontMap = function(fref) {
const key = fref && fref.ref !== undefined ? "r" + fref.ref : null;
if (key && cmaps[key]) {
return Promise.resolve(cmaps[key]);
}
const font = get(fref);
const fm = { bytes: font && font.Subtype && font.Subtype.name === "Type0" ? 2 : 1, map: null };
// how wide each character is, to know where the next one goes
const widths = {};
let dw = 0.5;
try {
if (font && font.Subtype && font.Subtype.name === "Type0") {
const dfs = get(font.DescendantFonts);
const df = get(Array.isArray(dfs) ? dfs[0] : dfs);
if (df) {
dw = typeof df.DW === "number" ? df.DW / 1000 : 1;
const W = get(df.W) || [];
for (let i = 0; i < W.length;) {
const c = get(W[i]);
const nx = get(W[i + 1]);
if (Array.isArray(nx)) {
nx.forEach(function(w, k) {
widths[c + k] = get(w) / 1000;
});
i += 2;
} else {
const w = get(W[i + 2]) / 1000;
for (let k = c; k <= nx && k - c < 65536; k++) {
widths[k] = w;
}
i += 3;
}
}
}
} else if (font) {
const fc = get(font.FirstChar) || 0;
(get(font.Widths) || []).forEach(function(w, k) {
widths[fc + k] = get(w) / 1000;
});
dw = /Courier/.test((font.BaseFont && font.BaseFont.name) || "") ? 0.6 : 0.5;
if (!Object.keys(widths).length) {
widths[32] = dw === 0.6 ? 0.6 : 0.278;
}
}
} catch (e) {}
// simple fonts: MacRoman, and the Differences of the font's own encoding
try {
const enc = font && get(font.Encoding);
if (enc && (enc.name === "MacRomanEncoding" || (enc.BaseEncoding && enc.BaseEncoding.name === "MacRomanEncoding"))) {
fm.mac = true;
}
const dif = enc && get(enc.Differences);
if (Array.isArray(dif)) {
const names = ugfTrGlyphNames();
let code = 0;
fm.diff = {};
dif.forEach(function(x) {
x = get(x);
if (typeof x === "number") {
code = x;
} else if (x && x.name) {
const nm = x.name;
let ch = names[nm];
if (ch === undefined) {
const u = /^uni([0-9A-F]{4})/i.exec(nm) || /^u([0-9A-F]{4,6})$/i.exec(nm);
ch = u ? String.fromCodePoint(parseInt(u[1], 16)) : nm.length === 1 ? nm : /^[A-Za-z]\.\w+$/.test(nm) ? nm[0] : undefined;
}
if (ch !== undefined) {
fm.diff[code] = ch;
}
code++;
}
});
}
} catch (e) {}
fm.w = function(c) {
const v = widths[c];
return typeof v === "number" && v > 0 ? v : dw;
};
const tu = font && font.ToUnicode;
if (!tu || tu.ref === undefined || !objs[tu.ref]) {
if (key) {
cmaps[key] = fm;
}
return Promise.resolve(fm);
}
return decode(objs[tu.ref]).then(function(b) {
if (b) {
const s = str(b);
const map = {};
const hex = function(h) {
return parseInt(h, 16);
};
const uni = function(h) {
let o = "";
for (let i = 0; i + 3 < h.length + 1; i += 4) {
o += String.fromCharCode(hex(h.substr(i, 4)));
}
return o;
};
const cs = /<([0-9a-f]+)>\s*<([0-9a-f]+)>/i.exec((s.match(/begincodespacerange([\s\S]*?)endcodespacerange/) || ["", ""])[1]);
if (cs) {
fm.bytes = Math.max(1, Math.ceil(cs[1].length / 2));
}
(s.match(/beginbfchar([\s\S]*?)endbfchar/g) || []).forEach(function(blk) {
const r2 = /<([0-9a-f]+)>\s*<([0-9a-f]*)>/gi;
let x;
while ((x = r2.exec(blk))) {
map[hex(x[1])] = uni(x[2]);
}
});
(s.match(/beginbfrange([\s\S]*?)endbfrange/g) || []).forEach(function(blk) {
const r3 = /<([0-9a-f]+)>\s*<([0-9a-f]+)>\s*(<([0-9a-f]*)>|\[([^\]]*)\])/gi;
let x;
while ((x = r3.exec(blk))) {
const a = hex(x[1]);
const z = hex(x[2]);
if (x[4] !== undefined) {
const base = x[4];
const last = hex(base.slice(-4) || "0");
for (let c = a; c <= z && c - a < 65536; c++) {
map[c] = uni(base.slice(0, -4)) + String.fromCharCode(last + (c - a));
}
} else {
const list = x[5].match(/<([0-9a-f]*)>/gi) || [];
list.forEach(function(h, i) {
map[a + i] = uni(h.replace(/[<>]/g, ""));
});
}
}
});
fm.map = map;
}
if (key) {
cmaps[key] = fm;
}
return fm;
});
};
const mac = "\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5\u00fa\u00f9\u00fb\u00fc\u2020\u00b0\u00a2\u00a3\u00a7\u2022\u00b6\u00df\u00ae\u00a9\u2122\u00b4\u00a8\u2260\u00c6\u00d8\u221e\u00b1\u2264\u2265\u00a5\u00b5\u2202\u2211\u220f\u03c0\u222b\u00aa\u00ba\u03a9\u00e6\u00f8\u00bf\u00a1\u00ac\u221a\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u00c0\u00c3\u00d5\u0152\u0153\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca\u00ff\u0178\u2044\u20ac\u2039\u203a\ufb01\ufb02\u2021\u00b7\u201a\u201e\u2030\u00c2\u00ca\u00c1\u00cb\u00c8\u00cd\u00ce\u00cf\u00cc\u00d3\u00d4\uf8ff\u00d2\u00da\u00db\u00d9\u0131\u02c6\u02dc\u00af\u02d8\u02d9\u02da\u00b8\u02dd\u02db\u02c7";
const win = "€\u0081‚ƒ„…†‡ˆ‰Š‹Œ\u008dŽ\u008f\u0090‘’“”•–—˜™š›œ\u009džŸ";
// the characters of a string: [[text, width in ems], ...]
const glyphs = function(bytes, fm) {
const out = [];
const nb = fm ? fm.bytes : 1;
for (let i = 0; i < bytes.length; i += nb) {
let c = 0;
for (let k = 0; k < nb; k++) {
c = c * 256 + (bytes[i + k] || 0);
}
let t = "";
if (fm && fm.map) {
t = fm.map[c] !== undefined ? fm.map[c] : "";
} else if (nb === 1) {
t = fm && fm.diff && fm.diff[c] !== undefined ? fm.diff[c] :
fm && fm.mac && c >= 128 ? mac[c - 128] :
c >= 128 && c < 160 ? win[c - 128] : String.fromCharCode(c);
}
out.push([t, fm && fm.w ? fm.w(c) : 0.5, c]);
}
return out;
};
// one page's lines
const readPage = function(pg) {
let cont = pg.node.Contents;
cont = Array.isArray(get(cont)) ? get(cont) : [cont];
const fonts = pg.res && get(pg.res.Font) ? get(pg.res.Font) : {};
const names = Object.keys(fonts).filter(function(k) {
return k !== "__dict";
});
const fms = {};
return Promise.all(names.map(function(n) {
return fontMap(fonts[n]).then(function(fm) {
fms[n] = fm;
});
})).then(function() {
return Promise.all(cont.map(function(c) {
return c && c.ref !== undefined ? decode(objs[c.ref]) : null;
}));
}).then(function(bufs) {
const s = bufs.filter(Boolean).map(str).join("\n");
const p = parse(s, 0);
const lines = [];
let line = "";
let chunks = []; // the pieces of the line being read, by where they start
let y = null; // the y of the line being read
let ly = 0; // the text line's y, as the operators move it
let lx = 0; // and its x
let tx = 0; // how far along the line the text has gone
let tc = 0;
let tw = 0;
let lead = 0;
let fm = null;
let fsize = 12;
let scale = 1;
let stack = [];
const size = function() {
return fsize * scale;
};
// a string drawn: its characters go where the widths put them
const show = function(bytes) {
glyphs(bytes, fm).forEach(function(g) {
const x = lx + tx;
const w = g[1] * size();
const c = chunks[chunks.length - 1];
// a character with no text but a space's width is a space
const t = g[0] || (g[1] >= 0.2 && g[1] <= 0.6 ? " " : "");
if (c && Math.abs(x - c.end) < 0.3 * size()) {
c.t += (x - c.end > 0.15 * size() && !/\s$/.test(c.t) && t !== " " ? " " : "") + t;
c.end = x + w;
} else {
chunks.push({ x: x, end: x + w, t: t, i: chunks.length });
}
tx += w + tc * scale + (g[2] === 32 && fm && fm.bytes === 1 ? tw * scale : 0);
});
};
// the pieces left to right (they are not always drawn in that order),
// with spaces between words but not before a comma or inside a word
const join = function() {
const cs = chunks.filter(function(c) {
return c.t;
}).sort(function(a, b) {
return a.x - b.x || a.i - b.i;
});
let out = "";
let end = null;
cs.forEach(function(c) {
// a space drawn over text already placed says nothing new
if (end !== null && !c.t.trim() && c.x < end) {
return;
}
if (end !== null && c.x - end > 0.15 * size() && !/\s$/.test(out) && !/^\s/.test(c.t)) {
out += " ";
}
out += c.t;
end = end === null ? c.end : Math.max(end, c.end);
});
chunks = [];
return out;
};
const brk = function() {
line = join().replace(/[\ufb00-\ufb06]/g, function(x) {
return x.normalize("NFKC");
});
if (line.trim()) {
lines.push({ t: line.replace(/\s+/g, " ").trim(), y: y, size: size() });
}
line = "";
};
// the text moves to a new y: the same line, or a new one
const moveTo = function(ny) {
if (y === null) {
y = ny;
} else if (Math.abs(ny - y) >= size() * 0.5) {
brk();
y = ny;
}
};
let guard = 0;
while (p.at() < s.length && guard++ < 2000000) {
const v = p.val();
if (v === null || v === undefined) {
continue;
}
if (!v.op) {
stack.push(v);
continue;
}
const op = v.op;
const n = function(i) {
const x = stack[stack.length - i];
return typeof x === "number" ? x : 0;
};
if (op === "BT") {
ly = 0;
lx = 0;
tx = 0;
scale = 1;
} else if (op === "Tc") {
tc = n(1);
} else if (op === "Tw") {
tw = n(1);
} else if (op === "Tf") {
const f = stack[stack.length - 2];
fsize = Math.abs(n(1)) || fsize;
fm = f && f.name ? fms[f.name] : null;
} else if (op === "Tj" || op === "'" || op === '"') {
if (op !== "Tj") {
ly -= lead || size();
lx = 0;
tx = 0;
moveTo(ly);
}
const a = stack[stack.length - 1];
if (a && a.str) {
if (y === null) {
y = ly;
}
show(a.str);
}
} else if (op === "TJ") {
const a = stack[stack.length - 1];
if (y === null) {
y = ly;
}
(Array.isArray(a) ? a : []).forEach(function(x) {
if (x && x.str) {
show(x.str);
} else if (typeof x === "number") {
tx -= x / 1000 * size();
}
});
} else if (op === "Td" || op === "TD") {
if (op === "TD") {
lead = -n(1);
}
ly += n(1) * scale;
lx += n(2) * scale;
tx = 0;
moveTo(ly);
} else if (op === "Tm") {
scale = Math.abs(n(3)) || 1;
if (scale > 0.2 && fsize > 2) {
scale = 1;
}
ly = n(1);
lx = n(2);
tx = 0;
moveTo(ly);
} else if (op === "T*") {
ly -= lead || size();
lx = 0;
tx = 0;
moveTo(ly);
} else if (op === "TL") {
lead = n(1) || lead;
} else if (op === "BI") {
const e = s.indexOf("EI", p.at());
p.set(e < 0 ? s.length : e + 2);
}
stack = [];
}
brk(null);
// lines into paragraphs: a new one after a wider gap, a short line
// or a change of size
const gaps = [];
for (let i = 1; i < lines.length; i++) {
gaps.push(Math.abs(lines[i - 1].y - lines[i].y));
}
const sorted = gaps.filter(function(g) {
return g > 0;
}).sort(function(a, b) {
return a - b;
});
const usual = sorted.length ? sorted[Math.floor(sorted.length / 2)] : 14;
const longest = Math.max.apply(null, lines.map(function(l) {
return l.t.length;
}).concat([1]));
// which way the lines run (down the page, mostly; some files count y downwards)
let down = 0;
for (let i = 1; i < lines.length; i++) {
down += lines[i - 1].y > lines[i].y ? 1 : lines[i - 1].y < lines[i].y ? -1 : 0;
}
const dir = down < 0 ? -1 : 1;
const paras = [];
let cur = "";
lines.forEach(function(l, i) {
const prev = lines[i - 1];
if (i && (Math.abs(prev.y - l.y) > usual * 1.45 || Math.abs(prev.size - l.size) > 1.5 ||
prev.t.length < longest * 0.6 || (prev.y - l.y) * dir < 0 ||
(/[.!?:;\u3002]["'\u201d\u2019)]?$/.test(prev.t) && /^["'\u201c\u2018(]?[A-Z0-9\u00c0-\u00de\u0391-\u03a9\u0410-\u042f]/.test(l.t)))) {
paras.push(cur);
cur = "";
}
cur = cur ? (/-$/.test(cur) ? cur.slice(0, -1) + l.t : cur + " " + l.t) : l.t;
});
if (cur) {
paras.push(cur);
}
return paras;
});
};
const out = [];
let chain = Promise.resolve();
pages.forEach(function(pg, i) {
chain = chain.then(function() {
return readPage(pg).then(function(paras) {
out.push(paras);
}).catch(function() {
out.push([]);
});
});
});
return chain.then(function() {
return out;
});
});
}
// ---- a document, start to finish -------------------------------------------------
// cb(err, { name, from: [[paragraph, ...] per page or part], to: [[...]], blob, det })
function ugfTrDoc(file, sl, tl, progress, cb) {
const name = file.name || "document";
const ext = (name.match(/\.([a-z0-9]+)$/i) || ["", ""])[1].toLowerCase();
const base = name.replace(/\.[^.]+$/, "");
const outName = base + " (" + ugfTrName(tl) + ")." + (ext === "pdf" ? "txt" : ext || "txt");
const fail = function(e) {
cb(e instanceof Error ? e : new Error(String(e)));
};
const kind = ugfTrOfficeKind(name);
const readBuf = function() {
return file.arrayBuffer ? file.arrayBuffer() : new Response(file).arrayBuffer();
};
if (kind) {
readBuf().then(function(buf) {
const entries = ugfTrUnzip(buf);
let targets = entries.filter(function(e) {
return kind.parts.test(e.name);
});
if (kind.order) {
targets = targets.slice().sort(function(a, b) {
const na = /notesSlide/.test(a.name) ? 1e6 : 0;
const nb = /notesSlide/.test(b.name) ? 1e6 : 0;
return na + +((a.name.match(/(\d+)\.xml$/) || [0, 0])[1]) - nb - +((b.name.match(/(\d+)\.xml$/) || [0, 0])[1]);
});
}
// the document itself before its headers and footers
targets.sort(function(a, b) {
return (/document\.xml$|content\.xml$/.test(b.name) ? 1 : 0) - (/document\.xml$|content\.xml$/.test(a.name) ? 1 : 0);
});
if (!targets.length) {
throw new Error("empty");
}
return Promise.all(targets.map(ugfTrEntryText)).then(function(texts) {
const docs = texts.map(function(t) {
return new DOMParser().parseFromString(trusted_policy.createHTML(t), "application/xml");
});
const groups = docs.map(function(d) {
return ugfTrXmlParas(d, kind);
});
const flat = [];
groups.forEach(function(g) {
g.forEach(function(p) {
flat.push(p.text);
});
});
if (!flat.length) {
throw new Error("empty");
}
ugfTrMany(flat, sl, tl, progress, function(err, outs, det) {
if (err) {
fail(err);
return;
}
let i = 0;
const to = [];
groups.forEach(function(g) {
const page = [];
g.forEach(function(p) {
p.set(outs[i]);
page.push(outs[i]);
i++;
});
to.push(page);
});
const ser = new XMLSerializer();
targets.forEach(function(t, k) {
let x = ser.serializeToString(docs[k]);
if (!/^<\?xml/.test(x)) {
x = '\r\n' + x;
}
t.text = x;
});
ugfTrZip(entries).then(function(blob) {
cb(null, { name: outName, from: groups.map(function(g) {
return g.map(function(p) {
return p.text;
});
}), to: to, blob: new Blob([blob], { type: kind.mime }), det: det });
}).catch(fail);
});
});
}).catch(fail);
return;
}
if (ext === "pdf") {
readBuf().then(ugfTrPdfText).then(function(pages) {
const flat = [];
pages.forEach(function(p) {
p.forEach(function(x) {
flat.push(x);
});
});
if (!flat.join("").trim()) {
throw new Error("nopdftext");
}
ugfTrMany(flat, sl, tl, progress, function(err, outs, det) {
if (err) {
fail(err);
return;
}
let i = 0;
const to = pages.map(function(p) {
return p.map(function() {
return outs[i++];
});
});
const txt = to.map(function(p) {
return p.join("\r\n\r\n");
}).join("\r\n\r\n\f\r\n");
cb(null, { name: outName, from: pages, to: to, blob: new Blob([txt], { type: "text/plain;charset=utf-8" }), det: det });
});
}).catch(fail);
return;
}
if (ext === "htm" || ext === "html" || ext === "xhtml") {
file.text().then(function(t) {
const d = new DOMParser().parseFromString(trusted_policy.createHTML(t), "text/html");
const nodes = [];
const tw = d.createTreeWalker(d.body || d.documentElement, NodeFilter.SHOW_TEXT);
let n;
while ((n = tw.nextNode())) {
if (n.nodeValue.trim() && !n.parentNode.closest("script, style, noscript, code, pre")) {
nodes.push(n);
}
}
const tn = d.querySelector("title");
const texts = nodes.map(function(x) {
return x.nodeValue;
}).concat(tn ? [tn.textContent] : []);
// for showing: the text of each block (heading, paragraph, cell...) together
const blockOf = function(x) {
return x.parentNode.closest("p, h1, h2, h3, h4, h5, h6, li, td, th, dt, dd, blockquote, pre, figcaption, caption, div, section, article, body") || d.body;
};
const grouped = function(list) {
const out = [];
let last = null;
nodes.forEach(function(x, i) {
const b = blockOf(x);
if (b !== last || !out.length) {
out.push("");
last = b;
}
out[out.length - 1] += list[i];
});
return out.map(function(t) {
return t.replace(/\s+/g, " ").trim();
}).filter(Boolean);
};
ugfTrMany(texts, sl, tl, progress, function(err, outs, det) {
if (err) {
fail(err);
return;
}
const fromShown = grouped(texts);
const toShown = grouped(outs);
nodes.forEach(function(x, i) {
x.nodeValue = outs[i];
});
if (tn) {
tn.textContent = outs[outs.length - 1];
}
if (d.documentElement) {
d.documentElement.setAttribute("lang", tl);
}
if (d.head && !d.querySelector("meta[charset]")) {
const mc = d.createElement("meta");
mc.setAttribute("charset", "utf-8");
d.head.insertBefore(mc, d.head.firstChild);
}
const html = "\n" + d.documentElement.outerHTML;
cb(null, { name: outName, from: [fromShown], to: [toShown], blob: new Blob([html], { type: "text/html;charset=utf-8" }), det: det, html: true });
});
}).catch(fail);
return;
}
if (/^(txt|text|md|markdown|csv|tsv|srt|vtt|log|ini|json|xml|rtf)$/.test(ext) || /^text\//.test(file.type || "")) {
file.text().then(function(t) {
if (ext === "rtf") {
// the words of a rich-text file, without its formatting
t = t.replace(/\\par[d]?/g, "\n").replace(/\{\\\*[^{}]*\}/g, "").replace(/\\'([0-9a-f]{2})/gi, function(x, h) {
return String.fromCharCode(parseInt(h, 16));
}).replace(/\\u(-?\d+)\??/g, function(x, c) {
return String.fromCharCode((+c + 65536) % 65536);
}).replace(/\\[a-z]+-?\d* ?/gi, "").replace(/[{}]/g, "").replace(/\n{3,}/g, "\n\n").trim();
}
const lines = t.split(/\r?\n/);
ugfTrMany(lines, sl, tl, progress, function(err, outs, det) {
if (err) {
fail(err);
return;
}
const paras = function(ls) {
return ls.join("\n").split(/\n\s*\n/).filter(function(x) {
return x.trim();
});
};
cb(null, { name: ext === "rtf" ? base + " (" + ugfTrName(tl) + ").txt" : outName, from: [paras(lines)], to: [paras(outs)],
blob: new Blob([outs.join(/\r\n/.test(t) ? "\r\n" : "\n")], { type: "text/plain;charset=utf-8" }), det: det });
});
}).catch(fail);
return;
}
fail(new Error("type"));
}
// the kinds of file Gplex translates
function ugfTrDocTypes() {
return ".docx,.pptx,.xlsx,.odt,.odp,.ods,.pdf,.txt,.rtf,.htm,.html,.srt,.csv";
}
// ---- a website, translated ------------------------------------------------------
// Google shows a translated website at .translate.goog with its bar across the
// top, which is a frame of translate.google.com - so Gplex draws the bar of the
// period inside that frame, over Google's own: the languages, Translation or
// Original, and the way back to the website itself.
function ugfTrWebBarWanted() {
return window.location.host === "translate.google.com" && /^\/websitetranslationui\/?$/.test(window.location.pathname || "") &&
!ugfNtTopFrame() && ugfNtOn("UGF_TRANSLATE_ON");
}
function ugfTrWebBar() {
const era = ugfTrEra();
const A = ugfNtArt();
const esc = ugfNtEsc;
const l = String(layout || "");
const q = new URLSearchParams(window.location.search);
const u = q.get("u") || "";
// the page shown untranslated ("Original") carries op=true
const st = { sl: q.get("sl") || "auto", tl: q.get("tl") || "en", view: q.get("op") === "true" ? "from" : "to" };
const langs = ugfTrLangsFor(era);
const opts = function(sel, auto) {
return (auto ? 'Detect language " : "") + langs.map(function(x) {
return '" + esc(x[1]) + " ";
}).join("");
};
const T = "#ugf-trw";
const css = [
"html, body { background: transparent !important; overflow: hidden !important; }",
"body > *:not(#ugf-trw):not(script):not(style) { visibility: hidden !important; }",
T + " { position: fixed; left: 0; top: 0; right: 0; height: 57px; z-index: 2147483647; display: flex; align-items: center; gap: 12px; padding: 0 12px; visibility: visible; box-sizing: border-box; white-space: nowrap; overflow: hidden; }",
T + " * { box-sizing: border-box; } " + T + " img { display: block; } " + T + " .sp { flex: 1; }",
T + " select { max-width: 170px; }",
T + " .src { overflow: hidden; text-overflow: ellipsis; min-width: 0; }"
];
let h = "";
const src = 'Translated version of ' + esc(u.replace(/^https?:\/\//, "").replace(/\/$/, "")) + " ";
if (era === "t2006" || era === "t2008" || era === "t2010") {
const logo = era === "t2010" ? ' ' :
' ';
h = logo + '" +
'Remove frame ';
css.push(
T + " { background: #fff; border-bottom: 1px solid #c9d7f1; font: 13px arial, sans-serif; color: #000; padding-left: 8px; }",
T + " a { color: #00c; } " + T + " .mid { display: flex; flex-direction: column; gap: 4px; min-width: 0; }",
T + " .r2 { display: flex; align-items: center; gap: 5px; } " + T + " select, " + T + " input { font: 13px arial, sans-serif; }",
T + " .view { margin-left: 14px; } " + T + " .view label { margin-left: 4px; } " + T + " .rm { font-size: 12px; }"
);
if (era !== "t2010") {
css.push(T + " { background: #e5ecf9; border-bottom-color: #36c; }");
}
} else if (era === "t2012" || era === "t2015") {
h = '' + ugfCalHeadLogo() + ' Translate ' +
'From: ' + opts(st.sl, true) + ' To: ' + opts(st.tl) + " " +
'Translation Original ' +
' ' + src + '× ';
css.push(
T + " { background: #f1f1f1; border-bottom: 1px solid #e5e5e5; font: 13px arial, sans-serif; color: #222; gap: 14px; padding: 0 16px; }",
T + " a { color: #15c; text-decoration: none; } " + T + " .logo img { width: 70px !important; height: auto !important; }",
T + " .lbl { color: #dd4b39; font-size: 18px; margin-right: 8px; }",
T + " .kb { display: inline-flex; align-items: center; gap: 4px; height: 29px; padding: 0 8px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444 !important; font: bold 11px arial, sans-serif; cursor: default; }",
T + " .kb:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); }",
T + " .kb select { border: 0; background: transparent; font: bold 11px arial, sans-serif; color: #222; outline: none; cursor: pointer; }",
T + " .grp { display: inline-flex; } " + T + " .grp .kb { border-radius: 0; margin-left: -1px; } " + T + " .grp .kb:first-child { border-radius: 2px 0 0 2px; margin-left: 0; } " + T + " .grp .kb:last-child { border-radius: 0 2px 2px 0; }",
T + " .kb.on { background: #eee; box-shadow: inset 0 1px 2px rgba(0,0,0,.1); border-color: #ccc; color: #222 !important; }",
T + " .src { color: #666; font-size: 12px; } " + T + " .x { color: #777 !important; font-size: 22px; padding: 0 4px; }"
);
} else {
h = 'Translate ' +
'' + opts(st.sl, true) + ' ' + ugfNtIcon("arrow_forward", 20) + ' ' + opts(st.tl) + " " +
'Original Translation ' +
'' + ugfNtIcon("close", 24) + " ";
css.push(
T + " { background: #fff; border-bottom: 1px solid #dadce0; font: 14px Roboto, arial, sans-serif; color: #3c4043; gap: 16px; padding: 0 12px 0 16px; }",
T + " a { color: inherit; text-decoration: none; }",
T + " .logo { display: flex; align-items: center; gap: 4px; margin-right: 24px; } " + T + " .logo span { font: 22px \"Product Sans\", \"Google Sans\", Roboto, arial, sans-serif; color: #5f6368; }",
T + " .lang { display: flex; align-items: center; gap: 8px; } " + T + " .arr { color: #5f6368; display: inline-flex; }",
T + " select { height: 36px; border: 1px solid #dadce0; border-radius: 4px; background: #fff; padding: 0 8px; font: 500 14px \"Google Sans\", Roboto, arial, sans-serif; color: #1a73e8; outline: none; cursor: pointer; }",
T + " .tabs { display: flex; height: 57px; } " + T + " .tabs a { display: inline-flex; align-items: center; padding: 0 16px; font: 500 14px \"Google Sans\", Roboto, arial, sans-serif; color: #5f6368; border-bottom: 3px solid transparent; }",
T + " .tabs a.on { color: #1a73e8; border-bottom-color: #1a73e8; }",
T + " .x { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; color: #5f6368; } " + T + " .x:hover { background: rgba(60,64,67,.08); }"
);
if (l !== "2022") {
css.push(T + " .tabs a { text-transform: uppercase; }");
}
}
const style = document.createElement("style");
style.id = "ugf-trw-styles";
style.textContent = css.join("\n");
(document.head || document.documentElement).appendChild(style);
const bar = document.createElement("div");
bar.id = "ugf-trw";
bar.setAttribute("era", era);
bar.innerHTML = trusted_policy.createHTML(h);
document.body.appendChild(bar);
// other languages, or the original: the page again, from Google's address for it
// (anno=2 is Google's page untranslated, under the same bar)
const reload = function() {
const url = "https://translate.google.com/website?sl=" + encodeURIComponent(st.sl) + "&tl=" + encodeURIComponent(st.tl) +
"&hl=en&client=webapp&u=" + encodeURIComponent(u) + (st.view === "from" ? "&anno=2" : "");
try {
window.top.location.href = url;
} catch (e) {
window.open(url, "_top");
}
};
const view = function(v) {
if (v === st.view) {
return;
}
st.view = v;
bar.querySelectorAll("[data-v]").forEach(function(a) {
a.classList.toggle("on", a.getAttribute("data-v") === v);
});
reload();
};
bar.addEventListener("change", function(ev) {
const s = ev.target;
if (s.matches("select.sl")) {
st.sl = s.value;
reload();
} else if (s.matches("select.tl")) {
st.tl = s.value;
reload();
} else if (s.matches("input[name=v]")) {
view(s.value);
}
});
bar.addEventListener("click", function(ev) {
const a = ev.target.closest("[data-v]");
if (a) {
ev.preventDefault();
view(a.getAttribute("data-v"));
}
});
}
// ---- how Google Translate looked, period by period -------------------------------
function ugfTrCss(era) {
const T = "#ugf-tr";
const early = [
T + ' { font: 13px arial, sans-serif; padding: 8px; }',
T + ' a { color: #00c; }',
T + ' .new { color: #f00; font-size: 11px; }',
T + ' textarea, ' + T + ' select, ' + T + ' input { font: 13px arial, sans-serif; }',
T + ' .io { display: flex; gap: 12px; align-items: flex-start; }',
T + ' .src { width: 525px; height: 36px; resize: both; }',
T + ' .res { flex: 1; min-width: 0; } ' + T + ' .res .rlab { font-weight: bold; margin-bottom: 4px; } ' + T + ' .res .rtext { white-space: pre-wrap; font-size: 15px; }',
T + ' .tfoot { text-align: center; margin-top: 50px; }',
// a document, translated
T + ' .docres { margin: 12px 0 0 0; padding: 8px 9px; border: 1px solid #c9d7f1; }',
T + ' .docres .dt { font-weight: bold; }',
T + ' .weblink { color: #00c; text-decoration: underline; }'
];
const docs = [
T + ' .docres:empty { display: none; }',
T + ' .dhead { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; margin-bottom: 12px; }',
T + ' .dhead .dn { color: #676767; } ' + T + ' .dhead .dl { margin-left: auto; }',
T + ' .dhead .vw.on { font-weight: bold; color: inherit !important; text-decoration: none; cursor: default; }',
T + ' .dbody p { margin: 0 0 10px 0; white-space: pre-wrap; line-height: 1.4; }',
T + ' .dpg { color: #676767; font-size: 11px; margin: 16px 0 6px 0; border-top: 1px solid #e5e5e5; padding-top: 4px; }',
T + ' .dmsg.err { color: #c00; }'
];
const css = {};
// ---- 2006: the small logo, the blue "Translate" bar, language pairs
css.t2006 = early.concat(docs, [
T + ' .thead { display: flex; align-items: flex-end; } ' + T + ' .thead img { display: block; }',
T + ' .tbar { flex: 1; display: flex; justify-content: space-between; align-items: center; background: #e5ecf9; border-top: 1px solid #36c; padding: 2px 4px; margin-bottom: 14px; }',
T + ' .tbar b { font-size: 19px; }',
T + ' .tsec { margin: 24px 0 0 0; } ' + T + ' .tsh { font-weight: bold; font-size: 16px; padding: 0 9px 3px 9px; }',
T + ' .tbox { border: 4px solid #e5ecf9; padding: 8px 8px 8px 8px; }',
T + ' .tbox .io { margin: 4px 0 90px 0; } ' + T + ' .ctl { display: flex; gap: 3px; } ' + T + ' .ctl .pair { width: 440px; }',
T + ' .tbox.row { display: flex; gap: 4px; } ' + T + ' .tbox.row .url { flex: 1; }'
]);
// ---- 2007-2008: the BETA logo and its tabs
css.t2008 = early.concat(docs, [
T + ' .tsh + .tbox .docfile { margin: 4px 0; }',
T + ' .help { text-align: right; }',
T + ' .thead { display: flex; align-items: flex-end; gap: 12px; margin-top: -4px; }',
T + ' .ttabs { flex: 1; display: flex; gap: 0; background: #e5ecf9; border-bottom: 1px solid #36c; height: 30px; padding-left: 4px; align-items: flex-end; }',
T + ' .ttabs a, ' + T + ' .ttabs span { padding: 6px 17px; font-weight: bold; } ' + T + ' .ttabs .on { background: #fff; border: 1px solid #36c; border-bottom-color: #fff; margin-bottom: -1px; }',
T + ' .tsh { background: #e5ecf9; font-weight: bold; font-size: 17px; padding: 6px; margin: 46px 0 14px 0; }',
T + ' .tsh + .tbox { padding: 0 3px; } ' + T + ' .tbox .io { margin: 4px 0 90px 0; }',
T + ' .ctl { display: flex; align-items: center; gap: 5px; margin-top: 4px; } ' + T + ' .ctl select { width: 120px; } ' + T + ' .ctl .go, ' + T + ' .ctl .goweb { margin-left: 10px; }',
T + ' .url.wide { width: 100%; }',
T + ' .tfoot { border-top: 1px solid #ccc; padding-top: 12px; margin-top: 70px; }'
]);
// ---- 2009-2010: "Google translate", a column of links, instant translation
css.t2010 = [
T + ' { font: 13px arial, sans-serif; }',
T + ' a { color: #00c; }',
T + ' .thead { padding: 14px 8px 6px 8px; } ' + T + ' .thead img { display: block; }',
T + ' .tbody { display: flex; padding: 8px; }',
T + ' .tnav { width: 130px; flex: 0 0 130px; border-right: 1px solid #c9d7f1; display: flex; flex-direction: column; gap: 14px; padding-right: 8px; }',
T + ' .tmain { padding-left: 18px; max-width: 540px; } ' + T + ' .tmain h2 { font-size: 16px; margin: 0 0 8px 0; } ' + T + ' .hint { margin-bottom: 8px; }',
T + ' .src { width: 520px; height: 60px; font: 13px arial, sans-serif; border: 1px solid #aaa; }',
T + ' .ctl { display: flex; justify-content: space-between; align-items: flex-start; width: 520px; } ' + T + ' .ctl td { padding: 2px 4px; } ' + T + ' .ctl select { width: 154px; font: 13px arial, sans-serif; }',
T + ' .ctl .swap { display: block; width: 18px; height: 18px; background: url("' + ugfNtArt().tbuttons + '") -72px 0 no-repeat; margin-left: 4px; }',
T + ' .thead { display: flex; justify-content: space-between; align-items: flex-start; } ' + T + ' .thead .lay { display: flex; gap: 2px; } ' + T + ' .thead .lay i { width: 18px; height: 18px; background: url("' + ugfNtArt().tbuttons + '") no-repeat; }',
T + ' .ctl .go { font: bold 13px arial, sans-serif; padding: 2px 8px; margin-top: 4px; }',
T + ' .resw { margin-top: 16px; } ' + T + ' .rh { font-weight: bold; color: #676767; font-size: 13px; margin-bottom: 6px; } ' + T + ' .res { white-space: pre-wrap; font-size: 16px; line-height: 1.4; }',
T + ' .avail { margin-top: 56px; } ' + T + ' .avail .grid { display: grid; grid-template-columns: repeat(6, auto); gap: 1px 14px; margin-top: 18px; justify-content: start; grid-auto-flow: column; grid-template-rows: repeat(42, auto); }',
T + ' .tfoot { text-align: center; margin-top: 50px; }',
T + ' .docw { display: none; padding: 20px 0 22px 0; } ' + T + ' .hint .dx { display: none; }',
T + '[mode=docs] .src, ' + T + '[mode=docs] .resw, ' + T + '[mode=docs] .avail, ' + T + '[mode=docs] .hint .tx { display: none !important; }',
T + '[mode=docs] .docw { display: block; } ' + T + '[mode=docs] .hint .dx { display: inline; }',
T + ' .docres { margin-top: 16px; } ' + T + ' .docres .dt { font-weight: bold; color: #676767; } ' + T + ' .dbody { font-size: 16px; }',
T + ' .weblink { color: #00c; text-decoration: underline; }'
].concat(docs);
// ---- 2011-2014: the grey header, the red "Translate", From / To buttons
const kennedy = [
T + ' { font: 13px arial, sans-serif; color: #222; }',
T + ' a { color: #15c; text-decoration: none; }',
T + ' .khead { background: #f1f1f1; height: 71px; display: flex; align-items: center; padding: 0 28px; border-bottom: 1px solid #e5e5e5; }',
T + ' .kbar { display: flex; align-items: center; gap: 16px; height: 58px; padding: 0 28px; border-bottom: 1px solid #ebebeb; }',
T + ' .kbar .label { color: #dd4b39; font-size: 20px; width: 160px; }',
T + ' .kb { display: inline-flex; align-items: center; gap: 4px; height: 29px; padding: 0 8px; border: 1px solid rgba(0,0,0,.1); background: linear-gradient(#f5f5f5, #f1f1f1); color: #444 !important; font: bold 11px arial, sans-serif; border-radius: 2px; cursor: pointer; }',
T + ' .kb:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); } ' + T + ' .kb svg { fill: #777; } ' + T + ' .kb small { font-size: 9px; color: #777; }',
T + ' .kb.on { background: #eee; box-shadow: inset 0 1px 2px rgba(0,0,0,.1); border-color: #ccc; color: #222 !important; }',
T + ' .kb.swap { width: 36px; justify-content: center; background: #fff; }',
T + ' .blue { display: inline-flex; align-items: center; height: 29px; padding: 0 16px; border: 1px solid #3079ed; border-radius: 2px; background: linear-gradient(#4d90fe, #4787ed); color: #fff !important; font: bold 11px arial, sans-serif; }',
T + ' .panes { display: flex; gap: 16px; padding: 12px 28px 0 28px; } ' + T + ' .pane { flex: 1 1 0; min-width: 0; }',
T + ' .phead { height: 28px; }',
T + ' .quick { display: flex; gap: 2px; } ' + T + ' .quick a { color: #444; font-weight: bold; font-size: 11px; padding: 3px 8px; border: 1px solid transparent; border-radius: 2px; }',
T + ' .quick a.on { background: #eee; border-color: #ccc; box-shadow: inset 0 1px 2px rgba(0,0,0,.1); color: #222; }',
T + ' .srcw { position: relative; } ' + T + ' .src { width: 100%; height: 133px; border: 1px solid #ccc; border-top-color: #b9b9b9; padding: 6px 28px 6px 8px; font: 16px arial, sans-serif; resize: none; outline: none; }',
T + ' .src:focus { border-color: #4d90fe; }',
T + ' .clr { position: absolute; right: 8px; top: 4px; color: #999; font-size: 20px; }',
T + ' .res { min-height: 133px; background: #f5f5f5; border: 1px solid #f5f5f5; padding: 6px 8px; font: 16px arial, sans-serif; white-space: pre-wrap; }',
T + ' .rtools { padding: 4px 0; } ' + T + ' .rtools .listen { color: #777; display: inline-flex; }',
T + ' .hint { color: #666; margin-top: 8px; }',
T + ' .kfoot { position: fixed; left: 0; right: 0; bottom: 0; background: #f5f5f5; border-top: 1px solid #ebebeb; display: flex; align-items: center; height: 29px; padding: 0 28px; }',
T + ' .kfoot a, ' + T + ' .kfoot b { margin-right: 26px; } ' + T + ' .kfoot .fr { margin-left: auto; display: flex; } ' + T + ' .kfoot b { color: #444; margin-right: 0; }',
T + ' .lmenu { position: absolute; z-index: 20; background: #fff; border: 1px solid rgba(0,0,0,.2); box-shadow: 0 2px 4px rgba(0,0,0,.2); padding: 8px 0; display: grid; grid-auto-flow: column; max-width: calc(100% - 32px); overflow: auto; }',
T + ' .lmenu { max-height: 70vh; } ' + T + ' .lmenu a { color: #222; padding: 3px 18px 3px 12px; white-space: nowrap; } ' + T + ' .lmenu a:hover { background: #eee; } ' + T + ' .lmenu a.on { font-weight: bold; }',
// a document to translate, in place of the text box
T + ' .docw { display: none; } ' + T + ' .hint .dx { display: none; } ' + T + ' .kb.pick input { display: none; }',
T + '[mode=docs] .srcw, ' + T + '[mode=docs] .hint .tx { display: none !important; } ' + T + '[mode=docs] .hint .dx { display: inline; }',
T + '[mode=docs] .docw { display: flex; align-items: center; gap: 10px; height: 133px; padding: 0 12px; border: 1px solid #ccc; border-top-color: #b9b9b9; }',
T + ' .docw .fname { color: #666; }',
T + '[mode=docs] .pane + .pane .res, ' + T + '[mode=docs] .pane + .pane .rtools { visibility: hidden; }',
T + ' .docres { margin: 16px 28px 70px 28px; font-size: 13px; } ' + T + ' .docres .dt { font-weight: bold; }',
T + ' .dbody { font: 16px arial, sans-serif; } ' + T + ' .dhead .dl { font-weight: bold; }',
T + ' .weblink { color: #15c !important; text-decoration: underline !important; }'
].concat(docs);
css.t2012 = kennedy;
// ---- 2015-2018: the flat logo, the language button groups, a counter
css.t2015 = kennedy.concat([
T + ' .kbar .sp { flex: 1; } ' + T + ' .kbar .plain { color: #666; margin-right: 8px; }',
T + ' .kbar .star { width: 36px; justify-content: center; margin-right: 0; }',
T + ' .krow { display: flex; align-items: center; gap: 16px; padding: 14px 28px 0 28px; }',
T + ' .grp { display: inline-flex; } ' + T + ' .grp .kb { border-radius: 0; margin-left: -1px; font-size: 13px; background: #f8f8f8; } ' + T + ' .grp .kb:first-child { border-radius: 2px 0 0 2px; margin-left: 0; } ' + T + ' .grp .kb:last-child { border-radius: 0 2px 2px 0; }',
T + ' .grp .kb.arrow { width: 22px; justify-content: center; }',
T + ' .krow .swap { margin-left: auto; }',
T + ' .krow .grp.t { margin-right: 0; }',
T + ' .phead { display: none; } ' + T + ' .panes { padding-top: 12px; }',
T + ' .src { border-color: #4d90fe; height: 130px; }',
T + ' .cnt { position: absolute; right: 10px; bottom: 8px; color: #777; font-size: 12px; }',
T + ' .res { background: #f5f5f5; min-height: 130px; }',
T + ' .kfoot { height: 48px; } ' + T + ' .kfoot a { color: #666; }'
]);
// ---- 2019 on: Material, one card with tabs of languages
css.t2019 = [
T + ' { font: 14px Roboto, arial, sans-serif; color: #202124; }',
T + ' a { color: inherit; text-decoration: none; }',
T + ' .mhead { display: flex; align-items: center; height: 64px; padding: 0 8px 0 12px; border-bottom: 1px solid #dadce0; gap: 8px; }',
T + ' .mlogo { display: flex; align-items: center; gap: 4px; margin-left: 8px; } ' + T + ' .mlogo span { font: 22px "Product Sans", "Google Sans", Roboto, arial, sans-serif; color: #5f6368; }',
T + ' .corner { margin-left: auto; display: flex; align-items: center; }',
T + ' .mtypes { display: flex; gap: 8px; padding: 10px 12px; background: #fafafa; border-bottom: 1px solid #dadce0; }',
T + ' .mtypes a { display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 12px; border: 1px solid #dadce0; border-radius: 4px; color: #1967d2; font: 500 14px "Google Sans", Roboto, arial, sans-serif; background: #fff; }',
T + ' .mtypes a.on { background: #e8f0fe; border-color: #d2e3fc; }',
T + ' .mcard { border-bottom: 1px solid #dadce0; box-shadow: 0 1px 1px rgba(0,0,0,.1); }',
T + ' .lrow { display: flex; align-items: center; height: 48px; border-bottom: 1px solid #dadce0; }',
T + ' .ltabs { flex: 1 1 0; display: flex; align-items: stretch; height: 48px; min-width: 0; overflow: hidden; }',
T + ' .ltabs a { display: inline-flex; align-items: center; padding: 0 16px; font: 500 14px "Google Sans", Roboto, arial, sans-serif; color: #5f6368; border-bottom: 2px solid transparent; letter-spacing: .25px; white-space: nowrap; }',
T + ' .ltabs a.on { color: #1a73e8; border-bottom-color: #1a73e8; } ' + T + ' .ltabs a:hover { background: #f8f9fa; }',
T + ' .ltabs .more { padding: 0 12px; margin-left: auto; color: #5f6368; }',
T + ' .lrow .swap { margin: 0 12px; color: #5f6368; }',
T + ' .panes { display: flex; } ' + T + ' .pane { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; min-height: 170px; } ' + T + ' .pane.out { border-left: 1px solid #dadce0; background: #fff; }',
T + ' .srcw { position: relative; flex: 1; } ' + T + ' .src { width: 100%; min-height: 120px; border: 0; outline: none; resize: none; padding: 16px 56px 8px 24px; font: 24px Roboto, arial, sans-serif; color: #202124; background: transparent; }',
T + ' .clr { position: absolute; right: 8px; top: 8px; }',
T + ' .res { flex: 1; padding: 16px 24px 8px 24px; font: 24px Roboto, arial, sans-serif; white-space: pre-wrap; color: #202124; } ' + T + ' .res.empty:before { content: attr(data-ph); color: #5f6368; }',
T + ' .ptools { display: flex; align-items: center; padding: 4px 12px 8px 12px; color: #5f6368; } ' + T + ' .ptools .sp { flex: 1; } ' + T + ' .cnt { margin-left: auto; font-size: 12px; color: #5f6368; padding-right: 12px; }',
T + ' .fb { text-align: right; padding: 8px 12px; font-style: italic; font-size: 12px; color: #5f6368; }',
T + ' .circles { display: flex; justify-content: center; gap: 62px; margin-top: 60px; } ' + T + ' .circles a { display: flex; flex-direction: column; align-items: center; gap: 10px; color: #5f6368; font-family: Roboto, arial, sans-serif; }',
T + ' .circles span { display: flex; align-items: center; justify-content: center; width: 72px; height: 72px; border: 1px solid #dadce0; border-radius: 50%; }',
T + ' .lmenu { position: absolute; z-index: 20; background: #fff; box-shadow: 0 1px 3px rgba(60,64,67,.3), 0 4px 8px 3px rgba(60,64,67,.15); padding: 8px 0; display: grid; grid-auto-flow: column; max-height: 60vh; overflow: auto; width: calc(100% - 32px); }',
T + ' .lmenu a { display: flex; align-items: center; gap: 8px; padding: 8px 16px; color: #3c4043; white-space: nowrap; } ' + T + ' .lmenu a:hover { background: #f1f3f4; } ' + T + ' .lmenu a.on { color: #1a73e8; }',
// Documents and Websites
T + ' .mdoc, ' + T + ' .mweb { display: none; }',
T + '[mode=docs] .panes, ' + T + '[mode=web] .panes { display: none; } ' + T + '[mode=docs] .mdoc { display: block; } ' + T + '[mode=web] .mweb { display: flex; }',
T + ' .pickw { display: flex; flex-direction: column; align-items: center; padding: 40px 16px 36px 16px; }',
T + ' .pickw .ph { font: 22px "Google Sans", Roboto, arial, sans-serif; color: #202124; } ' + T + ' .pickw .sub { color: #5f6368; margin: 8px 0 24px 0; }',
T + ' .browse { display: inline-flex; align-items: center; height: 36px; padding: 0 24px; border: 1px solid #dadce0; border-radius: 4px; color: #1a73e8; font: 500 14px "Google Sans", Roboto, arial, sans-serif; cursor: pointer; } ' + T + ' .browse:hover { background: #f6fafe; } ' + T + ' .browse input { display: none; }',
T + ' .chosen { display: none; align-items: center; gap: 16px; padding: 24px; } ' + T + '.hasfile .pickw { display: none; } ' + T + '.hasfile .chosen { display: flex; }',
T + ' .chosen .fic { color: #1a73e8; display: inline-flex; } ' + T + ' .chosen .fn { flex: 1; display: flex; flex-direction: column; min-width: 0; }',
T + ' .chosen .fname { font: 500 16px "Google Sans", Roboto, arial, sans-serif; color: #202124; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } ' + T + ' .chosen .fsize { color: #5f6368; font-size: 12px; }',
T + ' .blue2, ' + T + ' .dhead .dl { display: inline-flex; align-items: center; height: 36px; padding: 0 24px; border-radius: 4px; background: #1a73e8; color: #fff !important; font: 500 14px "Google Sans", Roboto, arial, sans-serif; }',
T + ' .mweb { align-items: center; gap: 8px; padding: 24px; } ' + T + ' .wurl { flex: 1; max-width: 600px; height: 48px; border: 1px solid #dadce0; border-radius: 4px; padding: 0 16px; font: 16px Roboto, arial, sans-serif; color: #202124; outline: none; } ' + T + ' .wurl:focus { border: 2px solid #1a73e8; padding: 0 15px; }',
T + ' .mweb .goweb { color: #1a73e8; }',
T + ' .docres { margin: 16px 12px; border: 1px solid #dadce0; border-radius: 8px; padding: 16px 24px; }',
T + ' .dhead { align-items: center !important; } ' + T + ' .dhead .dt { font: 500 16px "Google Sans", Roboto, arial, sans-serif; color: #202124; } ' + T + ' .dhead .dn { color: #5f6368 !important; }',
T + ' .dhead .dv a { color: #1a73e8; font: 500 14px "Google Sans", Roboto, arial, sans-serif; margin-right: 12px; padding: 6px 0; } ' + T + ' .dhead .dv a.vw.on { color: #1a73e8 !important; font-weight: 500; border-bottom: 2px solid #1a73e8; }',
T + ' .dbody { font: 16px/1.5 Roboto, arial, sans-serif; color: #202124; } ' + T + ' .dpg { color: #5f6368 !important; border-top-color: #dadce0 !important; }',
T + ' .dmsg { color: #5f6368; } ' + T + ' .weblink { color: #1a73e8 !important; text-decoration: underline !important; font-size: 18px; }'
].concat(docs);
return css[era] || css.t2015;
}
// ---- end Gplex for Google News and Google Translate ----
// ---- Gplex for Google Calendar (4.2) ---------------------------------------
// Like Gmail and Maps: Google's own Calendar keeps running underneath, hidden, and
// Gplex draws the Calendar of the layout's period on top, with your events read
// out of Google's page. Adding and editing events goes to Google's own editor.
function ugfCalArt() {
if (!ugfCalArt.c) {
ugfCalArt.c = {"logoBeta":"data:image/gif;base64,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","logoSm":"data:image/gif;base64,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","fav2006":"data:image/x-icon;base64,AAABAAEAEBAAAAAAIAAiAgAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAAQAAAAEAgGAAAAH/P/YQAAAelJREFUeJx1kz9oFEEUxn/75zzuYsJanBe4UzQipxFBwUq0sNCACFp4VRoR7C0t7Exha6uFpEh1YJUmkCKFomAjYpMYMUQ9xeC5F3Rnd+fmxmJu/9zGfDAw78187/veG8YCKC8ITQ7DKDAbGaJVDEqiZYSjAgZSgQzQMkQv3bDshKx6Xxis3kduvmJf+OtYHxfRMjRxu6Pt5Mz+8QYAa6uTqhehuqPi/fU05yYba7ZNqz6gX2rxc5TL2wc4dOIKh6cCNqMzyP6O4ZUXhE57TjBS369/wMwgFrhF8oXa33T/ditTrx0ccGxyyOtPZDPIt4AMmTvS5+nN7EGW3g15sAKP56B9ugLAzCNTUMfCzA4Zppa/+orri0Paz3t83hHMnzMzvtgwpFjKMXUAW6uYZH34VabpOdw673G8VuH99h8cFXD5ic/ahkhJibppQcnsQEbcntnl2lmPODKqA6nGFPNk40BGJAvg7guL5sPvrG0ITtVLuCUnvSxERBGuo7JXmG1UaXoe4HFyOiCWcuQsBCp7yABu3uLVepd7l7w0fvbSR/YlOhb89h2YnthTwLLvrI59JDfuMlU5wK6IieW4qiW20ZWj4w4A3Opklqm26EkFE2BTgNfAyoVD/5uJrfllXbxbnPZ/0Wlb/wAGpALj26udjwAAAABJRU5ErkJggg==","fav2011":"data:image/x-icon;base64,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","logo2013":"data:image/png;base64,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","fav2014":["data:image/x-icon;base64,AAABAAIAEBAAAAAAIACrAQAAJgAAACAgAAAAACAAVAMAANEBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAFySURBVHicpZE9TltREIW/c+YmfljJy5OCKLIBCwkWQBEUGigRC2ABWUWIRMNCsgA6REOeLEUp0iUIUfNTgQwGgR0TQfHsxCCbiGSaK82Z+c7MHQGUZfkBWONpsQZ8VFmWALeDbGN6FoD9ve/3qsfkpdnVbzvAuye6D+Kzgfl/bAaYN9D+D0DbwOE49WU9WH77+jHAUQJ2gZmHyvuVN6wuTfGiHmw2T8cBfhj4Mko5Pumy8engMXeArwa2RymbzVOOT37+DbCVJhsNOmdtOuete4plUjYBQPaqQA4URg4cgW1S/TkJWMyKHIDOeQvJCIGN5QoWgZz+AJKRjfBSAuYAsiJHQPeyDQpsQVQApYRtiOpVCDtAmksMXaBW5OCgd3WJHSiiP8EA4H7eYIE0o4X1ixZQDO/fu7rm5rqLwxCBw7/Hl1WtZgGcJSB/+LXP6hMozG3vV9+1aiaEJZAGpbmB5qj7pFqNyGo4JRTV2LaHmwGad2pISOEeCfoJAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAADG0lEQVR4nMWWv09TURTHP+e0lUprS/mNSNq4kJgYB4nGMHQ0Lv4BJg4G4+5/4KKrfwETg4Obg04mdnAwOghNwITIZiARfwAtFNqCw7v3vdvXAq8S7UmavPa+c7+f+z3n3lvBRKlUugPMAxP821gH5orF4hsAdQY6ihcKBWZnZ5mcnKRarUZSOCVnwmgRBui48qmpKWKxGPl8nkqlEgkiQo6vpeGRcKytrdFoNFhdXQWIBNFNjtiHUql01OmF45LT6TSpVKrjpFFyisWiAMjV+5/+V/OFYx2Y0x6JYzTnFacMPQhVoNxDgCUFFnsNsNRDgMUzO3CvmOPujczfpi/FgRWgDiSiZl2/fJ7bNweYLqQYzCZ4++EnsN2teB1Y1vLCTB1Yjpr19MElnjwqcOvaAHu1ZreibqyUF2bq9iiO3AfVWpNX777z+PlXXr//cRaARYB4twDPXqz7z1fyybMAlCG4jHqxFT+7AL3YimUwJRient6u/d6mtvXr1CwRNWe3kMulyF/sZ3Rkn+SFLKiAKCKCiIAKgoIKKmIOXkFVQGs7EDgwlhzIkMzmThRXK+5M5qEYMVHUF1cPVq2gAVHzrsbHXYARgOMgvImNoF2lGiGLoN5vqCIaM9+9DxJDVVFVM66IxIb9ElgACwH45XAt98QlsNgCiPceqggSwKmCWPtNrl+WVoBRd8UW4mB7ywgbs3xxQNyb3HPAq7knggFSCyr44mZ8zAUYCtueHMggAvs7O0ZA/FrbRvMggp5ob7SQY8YhFBAdcgHG2woP9GUzIMpBZce3XHzxoARiBcU0Gu2Wizo5AoqMuwDDnQAA+jJpUKFe2UUUf+UiysuPNUpfNtisHplGM8KhPvB3jnUDQGXw2B5og0inUIT63l5bo23u4tgfbjRxLLfOeJ5ZzbZdcFwk0v2gSmO/1kWj2VUTgAR/QUcilaAFoj+JqNA8qBOt0cyuEIItG0QLwFgUAIB4sg8R4bDeiNJo4VW70bINt4D+qBCxvnOIKofN5mmNdtI0WxAcxQ+BjagAAJqIo4m4Y7n4l47oqeLfgDmAPxV+uaYIpmLLAAAAAElFTkSuQmCC","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,AAABAAIAEBAAAAAAIADWAQAAJgAAACAgAAAAACAAwgMAAPwBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAGdSURBVHicpZGxa5NRFMV/99zXfl8K+UyrECMKDkKsNEuLYJdEF4UsKs4lHRwER3FOBAf/E/8ERRANBVFx1D2IDoo0MS0msW3qEL9SNAlUL7zhnXPuuefdZwDNZrMONDhaNSqVygOllxQtLpYoLpb+Uo/BGwBWWnv3Arh8xOlpvRRQ/sdmgLKA7n8YdAV8mqa4dytPdSU7if4s4MMktrqSpXb9NBcvTDR4L+DVJPZ+7Sy9/t60gK8D8GwcU187xbf2z2nNAE/DiWKRfqdL/3v7AD1fmKVaznP7UYv6egHNxGTmj2MuTI7ckUSYm0XA1TiXEB+bB8BM3L2ZH6VYL3DmZERlOculcxnkYXSCY8ExdC0AqwBxLsGAwXaXx887PHmzBebcubHAxy+7tDb3sRCQhLkhOZitBmApjR7lEpDztrWNNAQfUhvA186Qzb6QC8kxF8jAbMmuPNxqA7nDm9n50WO3N0AucEeug/ebDNlvA+gEIPlztTNzGczF/s4euEax5eCGzMAslSYCNsb9T4giPI5QCJiPYks63Ayw8QsqIlW6eSVceQAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAAA4lJREFUeJzFlk9oHHUUxz/vzW52sztuNsnsJm0ICfaQU3sqCAa6Sg9tLRU9FKRFPESLiAcFr4IHvXkVRKiXgvRSqCe9SNl7D00CLSUaaEFW+oea3c1mk9kkHuY3s7N/0p0d1H2ngZn3+37e973f/H6CiXK5fAG4Dhzjv40KsFIqlX4B0NCLvuKLi4ssLy8zNzfH9vZ2JIUBOceMFt0AfSufn5/HsiwWFhao1+uRICLkBFra/aY7Njc3abVabGxsAESCGCZH/IdyuXzY74Ojkm3bJpvN9l00Sk6pVBIAOfn+3f9r+LqjAqzoiMQxmteVUBtGEKrA+ggB1hRYHTXA2ggBVv8VBz467/DZuzNxUtcUeAC4ccWvlCZ5+40CZ1+bwrGtYVJd4L6u3zjtAvfjiDu2xTtvFtlpHsRJf7B+47Tr/4pjzcHnl73fx72H1Tjpq9A+C4YGuFKa5NTSK9y+84RGPAfWwwBDDaJjW5x7fZrfHzf4qfwijjjAvTDAUA5cu1RkPGXx3a1KXHEwDiQAnKWlavPvKs2twdVcPZPnvQvHufnrUx7XxxjLpigWsiwcz5DJT5BOgIggIqCCoKCCipgfr6AqoM0atB2YSedzpCcmXyo+O5Hkg4tFHlWafPvzCxBBVBBznIgoGogrIoqoL2hA1IBpYjZwACgApPM5gB4nRBQBPrnk4Ewmebrp8tXVQiD86lwKgI/fygPC17eqnogPIxoIg4EWywH+6ADoB+GLg2BnLB5VdsmOW5w6kTHnqJBJe0aePDFuBGqBC4hvv4QcU1DLCTtQDFfsQ+xVtwAxjVK++PGJqQoQ9Z5V+PLyFBeXc3z6/TOe1Q8R9apGvZYgAkIgbt7PhAGmu/udzucQgd1arW0bfiXaMWgeEagoYnmuBJZLqBWqZg1AdDoMMNsNAJCayIEoe3VjqYjXEr8qNSD+nUYV9BCl13LxQY0binQModMPACCVs0EFt95AlGCoRDQYtG9u1/jhtx2eN0DNVhMNV00g7gEDKlNHzkAPhJ1FEdydncDGsAAiPG8c9hk0CVkuxhmvRb5mzy44KpJ2BlRp7TYDgMGD5ldNG6R9BS1EakEHRCaNqLC/5xJt0DwHvF3Tc/ftAIh8nUmkU4gIB24ryqB1Vx2Ojm24BWSiQlipMUSVg/39QYP2smW2oH0WfAj8FRUAQJMJNJkIWS7BoSM6UPxPYAXgH1bE3vqvdy1qAAAAAElFTkSuQmCC","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,AAABAAIAEBAAAAAAIADTAQAAJgAAACAgAAAAACAArwMAAPkBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAGaSURBVHicpZI7T5NxFMZ/5zkH37bD2wJaB90bDSw6EQXFwQu7cTAMLn4NIdEv4eoXYFLjIq9NjIkYBxWjbkRcNBZaA8WqOLTVtika9IzPeW7/iwFkWXYDWGB/swAsWpZlALtdtHJsEoA3r1/0sffAzSbnVx4CZ/eZ3p1lATP/KAaYEVD/D4N6AO+BUi96/EjC5XPjfcynqw3uPmsMGqwLePW3mLnpMkfLybDVywAeA1d60dX1HRbvfADgVKXA3HSZ2/c+DTN4IuDBn9KvXjzMo5XPe63vx8FKheZGneZmrW8jE4eKI5w+Ocb8rTXyo+OYC5MjdyQRhQMEcD5XSgFobtYwE4aBxPVLY7xda/Lu4w/k8dsghEkYuiBgCiBXSskXRzEZuCMXZ06kLFUbWERbFIHCMRdyB7OpACa6tZNSCnJaW1+4NlsEM5aef0UeSAIXUtsAGZhN2OzNRo2Bf9Da2ubb9g5y/WrTrW8yZB0D2AggHbzakUIec7Hb+t5JbYtxQ2Zg1qWmAqrD3ieSBM8lKALzzrmlXjFA9SdE51hBaYrqDAAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAAA3ZJREFUeJzFlk1rG1cUhp/3jFxJliorjhzbCGM3UEILwQRCA7ZBlBBoCw10WUhWbnf9Ef0dgazSP9Buuim0KoRS40Iig7NwUUshpBDT1ra+Ysl2F3NnNFLG9iih1QHBzNx7z/uc9565GuGiWq1+CNwH5vlv4xmwXqlUvgWwyECs+NLSEqurq5TLZZrNZiKFc9bMOy2GAWIrX1hYwPM8FhcXaTQaiSASrAm1bHhkOOr1Or1ej52dHYBEEKOsUXBRrVZP4iactjifz5PL5WKTJllTqVQEoKt3N/+v5huOZ8C6jUkcp3nfiGzDGMIM2BojQM2Ax+MGqI0R4HGKERy4/V6By+XsmXPqT9t8s7GfNGUtBTwBusDEebMvl7PcvDF99qSf/wISAXSBbQFcvbv5CFhOsqqU92Kf37lV4uaNab689zu/1NtJUtW2HlxfTgU3SQF2G0exUCvLRX79o5VUHNzWB/8Fr9WIn6xdIJsxvt/8e5RlW1GA13oV16751Y/QfACPogCv7MDnH5SYnppgu57sWyESWwApgNKVK/udf/bp7J1voWTu7BaYuP3+HLms8eBhl8xUEWRIQvLHhYEJk9zBK8wE1jmAvgOzmWKBzNSFM8UtEHfJPl0rsDif5ruNfV9MhoXi5sNaIOhAzIFZai4KMANwGoSf2MKqcYk/WinS6hzz1Q8NZP4zzJB57t7/IQ8zw8zcuCF5pZcA4iCGLQ/Fr+V4560sG9tNnjdPkAzM61ct+eJmYdVIyFMwtxT2AHApWnGmWADgcH/PCTtWZ68EH69MAfD1w4b/zFks5DshJy5fGIFcT7jx2SjAxWHbM8UCErw4OACXVM6FlbezXH83x+aTFj/91kXmndJoikC77QkKkl2MAszFNV16qgAyDhsHfgL59t25VQTgx1rbt1zRqoURER+ouu+GobkoQCkOACBdyIOJbqOFDCTxxb1dLr2Z4nnrxDWULx5WHTgWVk0oLsm/N02f2gMvQeRzGKLbboc27rZO+pYrsH+wasJt8wEs7CeFmgHATLx0Pybyk2BG70VnhEYLqqYP0v8EnUm0BQMQkxlk4uiwS7JGc2+F/OuhGACYTQIAkMqkkcRxt5ek0YarjsbAa7gHTCaF8NJvIDOOj47Oa7Sz0uxB/yT8DPgzKQCATaSwiVTEcoVngexc8afAOsC/AADd38jKxzQAAAAASUVORK5CYII=","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,AAABAAIAEBAAAAAAIAC8AQAAJgAAACAgAAAAACAA1AMAAOIBAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAGDSURBVHicpZG9ilNRFIW/tfbJjxO5XEFEsBGboEweYJqgjb6CjZ1PYeMIdnZ2lnYW1kFsxuuAWJhKRewstM5M4jgZJnItbm5IRoOMru4s1v7OOvsIoCiK+8A2p9M28EBFUQCUtdu92gPg86f3K+k1vtS7824HuH7K22u9MtD/x2GAvoHxfwDGBr6edG/3z3HtUuuvHvDNwMfl0M7jHvfuXuHyxeZab0kfDLxZ9DmY8ejpl9WOBzOePP+tZK23Bl7Wp8FwwmA4WUkMhhOevR6tA7xI57tdpntjpvuroWi0aXZKZCMbgMbZnM6FDo7ANmmjSQJutvMMgOn+CKkKI2MHOHBobgWOEqcKKnwrAVsA7TxDwNH38TwsFFEFU1RQB04lClVwaSsBm3XtVp6BY3GbUsI2ilhAHYHCYIG0qRsPJyMgX37/8Y9DZodHOAwROIzCFdTCmgNgLwHZydU2Ns6gMOXxTwhXLRwQwhJIdTQzsPun/0mtFtFu4ZSqXcxBS8MAu78AaIJWehVtgY0AAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAObSURBVHicxZe/bxtlGMc/z3Pn2LFdOz/OcUiIHKFWkYqAAakdUafC0pEBCYmq8Ad0ZENIdGVjq2in7gx0qoQHBiQGmkgUEojSoU2jKAEnduPYTspw73v31jnb14H6me7ee9/3+3m+z3Pv2YKJer3+EXAbeIP/N7aBG8B9AKnX6/bB0yTx5eVlFhcX2draYn19nUKhMFIhxZptYAFAncHEzJeWlvA8j1qtRrPZpNVqjQRIsSbS0v4n/bG5uUmv12NjYwMgFcSrrHFL8CJpwqDFxWJxYDlSrhEAeefTX19X8/XHNnBDxySO0bytGCvGFKrA2hgBVhV4OG6A1TECPHwlBz75YJprl0pD5wRFjy8+DDhfnUiz5aoPPAK6QCZpxvtvTXL18hQrywVmyhke/LIPHJyZd+1Sictvl7hQKzCZU3b2O/y10xkm3gV+9+0F8F7/jG+uv8m7K+cAeLLThnIiI3e/PM9MOcNR+5T9RofFXG6YsI1HQNcexYl90Gqf8MNPu9z89m9+/Hlv4E77jS737j/j46/+5I+t52nEwZTeHwZw6952dH2xNjirm989TivqxhrEH6NxvIq/uQDjeBXXwJQgWFk5aP97QLvxz8DZU+VJagt55maPmJjMAwIqgCAqiLmvVs5RW8gzE0yTD7IICiqoiDl4BVUBbR8CaHmpAlDNTZXIlafTsdvNxIhLKC6i8ZdFwntRK2hA1MxVf17UR0V9gArAIAgRDUWsuN1Y1Ih6iIZjlkBEzFj4XFVRVTBjIl4g4uGLeBGAhQCicoio3dLixFlbGLEuhK64AIi1X2LHUFAvCHtAPYA5N2ML0TlomFoTbYwVs8JRH4QWC45TqqG4CAiRuKiAaBXAF1GA2X7bc1MlROD48DCEEMcH9Zyspa/RYgC1WTsOSZSQzhoHFGD+TOGBbLkEonSah86vFomz0th+k5XbOC9ZLirRWMgg8wBy5esGqH4PfJYEAXDcbNFtPqdaVnabL4z9xnKnJLbDg4Kyd4STtQMkpkgqd4Dr1oG5QeIA2WIBRdhtHoX2u42Y0Gh7bWJAp4fUXocIc2EJwqgkS8eRKeZBld5xOwJAdESj2ayJQeJiVlyAYBQAQCafQ1Q46XSJT7RhjRY6IEL8FsXxEkA1DQCAn8siIpx2e2fe7YRG68/ajaoL0ADyaSG87ASiyunJyahGG7ZNA+Kv4efAs7QAAJrx0YzvWC7RWSA6UvwJ4V90/gMkF9mCEqQXlwAAAABJRU5ErkJggg==","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,AAABAAIAEBAAAAAAIAAFAgAAJgAAACAgAAAAACAAHwQAACsCAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAHMSURBVHicpZK7bhNREIa/mTlkbRNtbEAGQoGoFlBcpIyQLC4CKkQRIUGRB0CiggdILFHCC6RJkQ66KFIiCmAViCig4RJkOgQOErKxY4QvCWCK3UV2lBSB080/838zc84RgDAMp4EZ9nZmgJKEYQjQS9TgVAGA8vs3A9W76CKFqZdPgLN77J6cpwoU/9EMUFSg+R+ApgM+A9lEOewbV8/kmF2qcvqYx7XzBwccDx/XWKt0k7CiwLskmp4aZeFegVs3ju/YbvLiUXLD1i+9VWA1ib5UN7l9/8Pf7FqlS2l+ndL8OuWPbWqNTZ6XW/2AFw54lESzS9Vdl528kGcx/LpdXnaHgoBOo0lnoz6QGUpnQBVR5eSoR3BimDtzDfbnj6BmqCouM4QDLqWyPgCdjToiGhE0KkKNm1cOsPq6xbe2RmYXgQW9rMAEQCrrkx7JISqxXxEz8iOO8SDDg2c/EOdQZ4hFIEQmHDCWjO1lfVCLAQ7MuF70qTV/8+pTDzVFNQKgAiJjcu7u9zp9/wBgq9XmZ7uLmoJZPI0iaogKKjEAGg7wt1/tvkwaMaW39QtMUY3MmKAiIJKU+gqs7PRszvOwlIc6h1i8t2q/GWDlD6ysaysuzKF/AAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAD5klEQVR4nMWV32tbZRjHP89zkvbkR5MuS9eW2LVWcUwcRR2OroOgRVhBFGEXgu5C6i68Ev8DL8S/QZR5I7sWvdELpUQF2dbB1pZNrAQnzAnr1rVN0qxNGi/ec05O0pP0CNM8EEjy/vh+nuf5vu8rOFEoFOaAi8Ao/23cBebz+fy3AOobCBSfmJhgZmaGXC5HuVwOpXDAmlFHi3aAwMzHxsawLIvx8XFKpVIoiBBrPC1tH2mPYrFIrVZjdXUVIBTEv1kj7pdCodAImtBpcTKZJJFIBG4aZk0+nxcAOXF+8f8yX3vcBea1R+I4mhcVXxt6EKrAcg8BlhS40WuApR4C3IgQsgIvTsZ44ZkEn3+35v33+kspJnOxruuKd7b55spmp+GlCHAL2AWiQTMunM3y7GSCp4/GAfjq53XWSnUAJnMxZk9lupNffgAEAuwCNwXgxPnF68CUf/Tl5xK8f+4JYrbyYGMXgEw6yrsf/+YBAGSTVqDuO69mmT2V4aPP/uBacTtoytLylyenIu6PdgCA1dtlvr+6zsJKmU8/fBLS+4vkh/FDnZ4a5Pc/K53EwWm9H6AlFlbKLKyEe/3a480zh4jZysLierdpy9B8jB7rUTzzvMm+i/kArvsBHttRvHA2SyYd5WbxwOotg9OC7LFjm9WHm1Q3OpcsNxJnfNTGTsTpq9cBARVAEBXE+f3GK6PEbeXSFYhnhxAUVFAR5+IVVAW0ugXNCgzbgyns9KFwabqbiSMuRvyt0wMcHenjh8USqCKiiLqCDoiauaKRET/AEEAnCBFtFXc3FiOCWIgqc9MpKtU9Lv1YQVS9D2KhqqiqAVNFxMruAwiCENHW59IRd7M2GwpzUwmOT9hcvbXNWqWBihhxVS9rRBBLDLQaAPcYHvFr2IMpAHY2N5xeg/tqiygiDQPitACE16YHAPj6l4r5TxxxEadqOF5Rd3zYD3C4vez2YAoReLS1BcZibgFALSPuVGH6KZuTx2Nc+7XK5dt1p+S+rL256pgVED3sBxjZ13igP50CUXZKWy0tUWl4RhQR3p412f+0UjVGwyfeknWzGoqM+AGyQQAA/akkqHDuk78YTiv3yg3P4The+OCLhwwNlLhfaRij4T8djofEVw0AlUxHD+yDSCZQhHulbVP+NgFEuF9p7Msa734wANrqpyN+gKFg6WZEk3FQpfao6gEcbDQ3a5ogzTM1FKoFLRBxG1GhvrNL80brZjRTARHzvS1aAIbDAABE7H5EhL3dWhijtWftj5ZjuAHEw0JY/X2IKnv1+kFG67bNBjRvwveAv8MCAGg0gkYjvpKL9+iYu6Kr+B1gHuAf+aME27rlIzoAAAAASUVORK5CYII=","data:image/x-icon;base64,AAABAAIAEBAAAAAAIAAUAgAAJgAAACAgAAAAACAAtAQAADoCAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAHbSURBVHicpZHNa1NREMV/M3Pty4c+nxhMSRf1C0IkVZcWoehCRdwoXbmo7rrqyvwBbaGLgggKrvoHiEt3igj2WRAFXalIVXBRFZVg6ktpUtsYF8krSYqL6sDAPXPPOTNzrwCEYTgJTLG9mAKmJQxDgGZczReGAFh8+6qL/Ze6yNDYi8fAqW12j2NegZF/FAOMKBD9h0GkwKfe6vj5zOY56xul0SyTYzmyvvVSPyvwJkal0SzP544zcXlwk3G7dJgTRwMODqS4O3Ok1+C1Ak9jVF1tcO3Guy5G/sBObt5Z4ursB/YGfb1TPHPAwxjN3S9vWXLx4wrjl3Jc/PGLWr3Bt6jRef3AZfJ56ssR9Z+VLmFfMgWqlKMmhf1pBgfSLH3fIL2vHzVDVXGpPhQ4mwh8Erv3ACCiLQc1CrkEJ4/t4sr1L1yY/komcJwpplBniDMEPeeAYYBE4CPA2krU1iuVWsvrUL9Hpg5JTxFrpaqByLADivHYXuCDWtvAUa4r955UuTWRBeDRyxrz73+j5kAFRIpyeqZaAYLO/ddXa2zU1lBTMEPbXUUNUUFFWwaw7AC/9+V3pJKIKc31Bpii2hJjgoqASEz1FVjY8neA8zws4aHOIWbtvbVTDLDwB/UlbVTRfTYcAAAAAElFTkSuQmCCiVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAEe0lEQVR4nMWWXWibZRTHf+ckad4mr03Xpktq1g9KaaVY1LWI0EHmldWLgaIi4lCpk+GdN+KNILIpgmwXeie72QoyQfy6UNnFDEz0omV2LWtdZzeLddbNbmmSJWua1ov3TfomfZvGgfZAIOT5OL/nf/7PcyLYkUgkHgdOAK38t3ENGInH498AqGPANXlnZydDQ0PEYjEymUxNGbZZ02rnohLA9eRtbW14PB46OjpIp9M1QdSwppRLK0cqY25ujtXVVWZnZwFqgvg3a6T4JZFIrLtN2GqxaZoEg0HXTWtZE4/HBUD6D479X+arjGvAiO5QcuycJxRHGXYgVIHJHQS4oMDETgNc2EGACS81KjDQVc/eniAff3tj01jY9PDkvl30dQWp9yvj0yk+P3eTG+nCdttekP6DYz4gA/jcZhwaDtPXFaS7PQDAy0culW0cNj0cOdROLGKwsJgDIBYxyObWeP/kPONz2a2S54GgTp4azAMXK0cfvT/Ip2/3cmB/C00hH0vJvOsurz/TSixi8NX31zl8/AqHj1/h2Og89YbywvDuaqefnjw1mC8+xa4+mP0tw7HReV587zLZnLuce6IGS8l8WWnOTmVYWMzR3R4gbHq2ApgA8G4FcHYqw9mp2rrfXcYkbDSju76K52dSNIV8HHi4ofTbQFc9TaE6Ls/frmbEn6GKArXG6JkbtDT6OPRUjCeGmgFoCtWxlFzh6Mnfqy2dLAGEe3uXc7eWySVvbjk7Fg3Q0WpgBAPUFQqAgAqG6aU1EqTj3gCiHkBoj9YxfTWHGQ6TNQAVVMR+eAVVAc2lnApEjEZLwmoQpRABURB456UIg30mxz5Z5PSPtxERhh8I8MbzYT56LcJzH/yFqD1fBbXBRb1R4NeiB1oAjMYGjNAul3y6KbmosK+nnsE+k7GLGU7/dNtKpMp3Uyt8/UOa9qiPZx8JgnhQVVQVVBFVRDxhpwItxf0rlRDR8nYpiugaIkJ7pA6AxZurFqQqgiAqpHPW/5t7AmpLLiDWmKCg5QBlL0YRYmU5iVVrKHZtEUVkHUSZuGo9Tl0xP6KWxEWAB7v9ACwsrVu1F0rJ7ZJEnADNlbIbjQ2IwJ1UCpCSCqKAehARflkskDifJv6QyYevhjk3mQMRevb4GOg1mJnPc2YmbyW2TSjFA4k2OwGimwoP+EMNIMpKOuWwgKKybnlBlTdHb/FWFvbvDTB4X31p3vilOxz5LF1x6uIHFIk6AcJuAAD+BhNUePrdP4iElOsZS1KxXS0iHP0ixdEvMzzW76choCRm8vydBRGxDGeRWx4QW02VJidA1a7hN4MowvV01pLfrnNRVsS652em8xtGkw1PWJIXryDYftrtBGhxT70RPjMAqqzeyZUAsJ2vDmndJLeGys1czLltCcogAgaiQmElz8aL5pB2k9HsWyHW94ooA4jUAgDgNfyICGv51U1328Volad2Rtk1TAKBWiE8/jpElbVCwXFq3IxWbZskbLTjV4A/awUAUJ8X9Xkdkkup6VhvRdXkC8AIwD+tD0U7XkmkPQAAAABJRU5ErkJggg==","data:image/x-icon;base64,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","data:image/x-icon;base64,AAABAAIAEBAAAAAAIABIAgAAJgAAACAgAAAAACAA1gQAAG4CAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAIPSURBVHicpZI7aNNRFMZ/59xrHqVJU41GrYQKaYOShkItUoRi8FFaB0cdtAhiBgcdsgqt4FAQQSSLzh0cxLGIETQWRNBO1UoFwUcEC41JE2ySPoxD/YdYcKie7Xx83+9+B64AZLPZMWCcrc04cF2y2SxA3VGjB3oAmH83+4f7L7pIz/nXT4GjW3zdmWcKDP5jGGBQgdJ/AEoWyAEBR0kOB9kTdPFqrszUTBmAkN9w7kQQgMnMIguldcf+VYG3znYzGeZ0YhetXsvE1W5G+nwApFMR4l0+4l0+0qlIc4M3FngBnAE4FGvj7oMc958X6Ozw0n/Qx8dvK0T3txIfnSHkN2TSvc2AlxZ47GyJK7ONysF2F/OfKnTudpEvrgA0qo/0+ZzzHtlgNEq1WKK6VGhgxy7uI7+0xsOZVYZ6W8mXfuJt34EYBcDVFqStI4BtcWGBk56AH4DqUoFrZ0N07vVw6VYOVYOIoTvsQY1tAL4UQaxB0CEFBgA8AT/JUx0MH9nOxOQC+eU6YgxP5moAHI64OR5roVKr8+F7HTUGRAYsEHOqH+v34XUr6VQYgPefa1y4s8hkpsztyzsBuDf1AzUWVEAkJokb5ULzPwBYXa6wVqmhRsEY1ChiFFGDqKCiGwAoWsDPptnW4kWMUl9dB6OoboQxgoqAiGP1KzC9GQBg3W6Mx41aixiD/AY1hQGmfwGm3ooseaNVGQAAAABJRU5ErkJggolQTkcNChoKAAAADUlIRFIAAAAgAAAAIAgGAAAAc3p69AAABJ1JREFUeJzFlk1sVFUUx3/nvM70zQfTlun0dRjpjNik4aN2IRs+dHBhIoaYuFMUjansFRcm7kiUYKIxxsQYCQtlIQmJiUQR0oV2oaYEIi1qVZoGMbVAi/RrPuhMOy7em5k300cZFtqT3GTevHvv/3f+59w7IzgxODi4FzgOxPlvYxLoT6fT3wCo64WneCqVYteuXSQSCTKZTEMK91gTd7SoB/DMfOPGjRiGQTKZZGFhoSGIBtZUtLT+TX2Mj49TLBa5cuUKQEMQ97NGyh8GBwdLXhPutjgcDhMKhTw3bWRNOp0WAOk9cOH/ar76mAT6dY3EcTSPK64yrEGoApfXEGBEgeG1BhhZQ4DhJhpwYH+6ja2bQkRbfdyaKXB1Ms+xs9M1c9rDBs/sbmPLphCBZuW3q1m++uE2YzcWV9t6RHoPXPABGcDnNePN5+Ls6Gvln9kCufwSAdNgfYuPH4dnOPL5ZEX8rYNdJCyTiRt5ABKWSS6/zDufXePieM5r6wIQEoDeAxcuAX31Mw4+2c7Te2I1YgBvv/wAD/es4/R3Uxw7O12BLD8DPL4txKEXuhi7luW1j/70zP7yie195avYsw8e2byOXH65Rhxg6Jc5AEIBA4CeVIiJG7Vl+fbnDCO/z9PdFaTb8nttPwzQtBrAxdF5r69rotvys77Fx8j1/Ip3UzMFALYkTa9euOwG8GzE+kYrx6ZEAIDxiRxbkmaN2H3EJaj+GjZ8FLstPzv7Whm7luX0+bn7FXVH1YH2np65/Mwc+dnbq66wIgbvH0oRa/Nx5MRN/KEwbW1hkhuCWLFFzJY7IIqIICJYVoTkhiDRjijrrJBz8QqqApqfh6oDltkawWxpW1X849dTJOMmRz/9m1+vF0HEHk6IKOqIl8UARJ1nLYsLok2dboAYwN0gRJQ3nu0kGTc5eW6KM5dyiAoqyl9TxfKkipCogajthB2Kqj3s94qI0b4CwAtCRHnvYJw921s5eW6ad7+8jWg5S2Hs5hIAvQ8FQA1E1IGTyjGdy5dAbbfEEEQUtBagw51xGUJFOfy8VSvu1NiutTKdKTF6NU9Xp5/NcZ8N5zix9UE/07NLDIwWKw4J6iSgFlSPYbTedrM1wqt7w+x7LEI2v0w4ZHB4f9koccornPp+gbNDWTanTA6/GGXgYo75bIlHe03aWwzODOVcjimC2GmLRt0AnSsKD+zoDQMQNJV9u70b9I+JIqfO50jE5ti3M0z/UxEAsndKnBnKcfTrbKUslaYVUKTTDdDutflLn2SJBoVCJksxm0UUOwNRe6gwnSkhqnxwLseHA3me2NZMJKB88dOifRzVcMxyekDEflZZ7wbo8AIAuJUtgQQolEoUFnL2EQJES/aeqiB206HCwGihXGNnbtlyQcufbYQON0DMU90VvnAQVCneySM4jSb2sVKXte5Gq2ZNFaT6FzR2zxKsgAiaiApLiwWqN5rL2hWNZjsgQs2F5QVgNQIA0GQ2IyIsF4pVcY+snUarz9odNcdwFgg2CmE0+xFVlpeWXFnj1WirbTML1YvoFeB6owAA6mtCfU0uy+2hIojeU3wC6Af4F3O0aHpDqa2vAAAAAElFTkSuQmCC","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,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","data:image/x-icon;base64,AAABAAIAEBAAAAAAIABAAgAAJgAAACAgAAAAACAA+AQAAGYCAACJUE5HDQoaCgAAAA1JSERSAAAAEAAAABAIBgAAAB/z/2EAAAIHSURBVHicpZJNSJRRFIafc+7VmW9wfoTRsKIgiWHEaSMEQowJmViQIAgFSUGgy4Sa2gQzgYugNoVBuWzVItoEFW3KBAlsaNMMEQXhDwkpzg+MDo7aYvpksjbW2b0v5zz3nJcrAJOTk0kgxe4q1dXVdVNd4bqRaIxINPZH91/8FIDEht6/Bo7v8nW33igQ/8dhgLgChf8AFCwwD4RcZ7gvTEu4nplskefpIgB7AobzPWGKpQ0mXizVAhYUyLgqObSXc30tNDiW5EgrZ+ONADwea+PIYT/93c3cHj5QC/iowLSrjsZCPHwyT2JilnQmT+Sgw6kOPwAXbn0hcfcrvceaagHvLPDKVaevZbdXjrY28PZD7reDswvlnRm8tOFIhLVcgbX8yrabvLSf5XyFp+l1mgMWn2N5dCMKCAD+ln2oKtZXjwInvaEA3mD13tEzTbQd8nH5/ndUDUsl5fqDRb4tVviR3wRArUGsQdBeC3QCeEMBBjq8DPaESIzPs1zaQoxBVJmZ20TrylwdbGQ6U0aMompApNMC7e7q/fEgjkcZv1JN+vNsmYv3ljjR7jA6EOTTXIU7z1ZRY0EFRNqle6y4UvsPANZLq1RWy6hRMAY1ihhF1CAqqGgVADkLBHZGW+dzEKNsrW+AUVSrwxhBRUDEbQ0oMLUTAGA9HozXg1pbzeIXqGYYYOonj+N/1rNeSkcAAAAASUVORK5CYIKJUE5HDQoaCgAAAA1JSERSAAAAIAAAACAIBgAAAHN6evQAAAS/SURBVHicxZZdbFNlGMd/z3vWrZ+z27p1zRxdJsmcZiw6LpwQixdEMWCiiWZi0OjkxivEGBIvjMaAXmjgyi/ChWIEo4lKDB8XxO3CEMyMG1MIAxdA5jZaYB39Gu1aL85pd9qejnqhe5KTtHmf5/3/n//zf99zBCOGh4c3AQeAAP9tTAODoVDoGIAyLViCd3R0sG7dOtra2ojH41Uh3KEmYGBRSsCy8/b2djRNIxgMEovFqiJRRU0BS5WulMbk5CSZTIYLFy4AVEXi39RI/sfw8HDOKqFSsdvtxuVyWW5aTU0oFBIA6dk28n+ZrzSmgUG1QuAYmAcUpjGsQCgFjK8ggTMKGFtpAmdWkMBYDVUosDXUwP2dLpq8Nq7Ppbk0nWL/8UhRjs+t8dT6Bvq6PSQXspydjJflWMQZ6dk2YgPigM0q483nAvT3erkRTZNMLeKwazTeZePU2Bx7Dk0D0NfpYNcLq3DYFVOzqULOxSsJXvvociXwNOASgJ5tI6NAb2nG9sd9PLmhuQgMYPdLd7Omy8ORoTD7j0fY+2qQthY7H397lZ9+jxcRP3n6Bvu+m7Xsfvzg2t78VWzpg75uD8lUtggc4PQf8wC4HBp9nQ5Wr3Iyen6+AA6w59A0N6JpHrjXU0mBMYCa5Qj8eu5WpeJCtPn0yYVvpsvWrs6kWNPlYbW/louzt0uXx80ELI1YyUSdbQ4AJqeSy5ILz+mk7gvarQiMwtLbsOqjuNpfy8O9Xi5eSXDkl3mmIjpIR8BeltvstfR1PpYU8HV1zafm5klFby4L7q/X2Luzg+YGG3sOXqPW5WZ8VkgswJZH/cQzNr4cukWTW+Plx7yEHnQDYPM04PG7jItXUEpApW4VCAB+u7ceoCIJf73GJ693EAzYeevTvzg7kwERRIT3vwrz7mArAxsbGdjYCEBkLsO5Swt0d9Tx2+WMDq4EhYASRNW0An/mCTQDVCIhotg10EowYOfwiTBHR5OIEgQBEc7NZHnmvb/ZucWL26ERS+XYdyzG12+0EIkuEo7nuxZA9FrRfGUErEiIKD7cHmDDWi+HT0T44IebxgY6OKIQQ4m9R2OIAdB/Ty2r/DaGR5NL4GKAo0BpPvMIWswd50ncno/y9vP+YnBRiLAEXOhKl1gQWuo1djztJbGQ44uhpC6/UAAXJSDKbybQVDpzu7eeHZvcbH6knkQqi9ul8c7WvFBifEUI3/wc4/xMlmcfctLVXou/sYbuYB0I/HgqwUQku6SYUvrYFCCqyUyg1cp4/T26i512xeb1DVYpTExlmLiWpKu9lif63USii4ycT/H5UJKJcLak6/wDCmk1E/BZbf7iZwmanEI6niCTSCAKw3hKf5QQiecQpdj9fZz9J1NEkjnyRlNKGV1TABcR/b+SxooeMMf1RA7EQTqXIx1LGnMGUTnDgwpEUCI6eJHRxCR5/ggaIzQwy05BpbC5naAUmYVUwem6CgplktZKcn2pCLyAuewIykg47YgSFm+nWbrRTNKWGU1XQD81Zd++RQT81RAAqLHXISJk05mys21htNKuzVF0DKOAs1oSWl0tohTZxUVT11gZbbltorD0NnwFmKmWAICy1aBsNSbJ9UeJIOqO4FPAIMA/1RmR/MH3zeYAAAAASUVORK5CYII=","data:image/x-icon;base64,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","data:image/x-icon;base64,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"],"fav2020":["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABH0lEQVR42mN0aPsez/T/zwQGBkYBBhqC64/uoQsd+M/4N5GJ6f/fBlpbjgM4MP5nns/EwMCgwDBwwIGJYYDBqANYcEnsreKmqkV/9hqNRgH1HfD47S+G4L57DObVNxievP1F3TRACBy/9ZUhccZDhk/f/tImEeIDvVteMvRuecXAwMDAwMfFTJEjyIqCVcffM8gKszKsKVJi4Odkon8IeOjzMxT7iDHwcTHTrhzABxrDJEez4agDRh0wAtoDxAJtGU4GWWE2Bj5O5oFxwLxM+dE0QFkauPbbBauE6Uppqlq0bbYhhtj//4yNAxYC//8zNorvO9XANJCWD0gaQLacgYGBgek/w/8PA2U5AwMDA9M/hn+ODAwMDwbCcgYGBgYAlONWltps4XoAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB20lEQVR42u2WP0gbYRjGf/elKUkK19KIGZprS2lLwQhRcHGKVGiHjJ2VQpdu0mxtoTq0WySjEEpx9HAMIorB7dDJoX8gQyleEBSvpldiJPHydQiKrVow5u6WPOP7Dc/zfs/zvrxK6kNtXMjDHCg3cBHfNr//W1qVivNcCOlMuk1+DlKKDHwSwF38Q0rgM7oCrpz3sPL6WkeJDlcGuxZczIL/IVvYZnHDxq45qOEAfVqYTLoXLXrVfQETsya6UTlRafClfIBRqrL85j5qJOCeBbqxh25U0KJB5l/dY2umn6W3D9CiQUyrTr64624GFjdsADLpGMMPW1OSiId48bgHgM/mgbsW5MbjbP5scPtm8K+6Gm59+++a464ANRIgcYbHZasOQF885M8YHoXySfK69wKyhW1Mq04iHjrOhWcC8sVdsoUd1Ijg48s73i2io86zhZ1WOMe0tpZQ2wLe6VvkixZqRJAb03iaVL1ZxaZVZ2K2jFGqHi+jdjtvS4Bu7GGUqgD8qjV5Nn3q0GTt/SNvMmDvO9j7zqVH+EICMukYmXSsexN29iD52hg982Fo7lZHiRbyA6dqUipTvv2AlMpUrLg+Kfwk9yUDJ8kBhERW/CIHEE2aI8APP8gB/gDHhKHZ1k2fbAAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACJUlEQVR42u2WP2gTYRjGf3cxR5NAarliUXNYA8ahDio4xCn+KTh0q2YV0YJukm46tBnq1uDmEP/g2JCxSEESnDzopEMUQqnFOwqKR9tgeiHX67nE0LQWuZrLIfTZ7vmG5/2e73nfe4XUE/O26Gw9BeEoHuLz1+Xd1DtHsO+IomNPey2+D1KCE3glAsP4h5SIzzgs4Mh+B6VHka4KbZUu/mcO/A26YfG++hMARZZIJiK9K2CqsEq+bHRwiixRzJxGkSVvQzg7/4182SAaFpm4Osjk2DEUOYhmNHn4WvfegYK6DsDbx2fat00nBxidWUKt1tGNJjEXLrguoJiJs2HaHVYrskR/SKS2aXvvgCIHUQh2cJrRRDMsFDno6vb/1AW1TZt8+QeaYbHwsUY0LJK9daJ3bbhh2szOf29/JxMRRpS+3o3i/lCAYibOy/unSCcHUKt1bua+uM7BgR2IhgNcbg2fG+ejaEYTtVpnTl1j4tqgdw5U9AYLH2p7+N/FVPSGdw5UNJPRmSWioQCLibNEw4EdnWC1nkb0LgMjSghFDlIzbcZzy63BYzFVWKWgrgFwz4X9B8rAiwfD3H22QkVvMJ7rXDQnx4Zc/wtcF3Au1kcxE+d5yaCimwDEZIl0cqCdA8+7QJElsunjhzthdzaiT9b1Px5cmjvZVaE3+Qt7OMcRsr454DhCdqi8OC36Ke5LBnaKA4gOzrpf4gDiNttXgBU/xAF+AW1SvtSqaznJAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABdUlEQVR42u2Wv0tCURzFP+9WktlvQ5F80CRBQRQ02GTU6Fiu0tAfEG5NGtRmtTtEY83SprRJ7RY0VPSapIcV4QPteZuU6BclvveGPOM9wzn3nO/9oUR2jLiQr/ugDGMhLu+uPy6dSsVcE0KaSavFv0FEkV0HApjAOUQEDqNjoPs7IrfpaavQa26uU8HfKvgtNL1KOlsCIBH1oXpd9iaQzpY4LpQ5LpTR9Jq9FTSEHZmB54rZjH6wr8t+A5n8A5peJRH1M+QW9hpoDJ7q7SER9dlfwcruDQB7cdX+e6ARfSw8wkLIY6+Bdkbf0kWUzpZ4rpioo67mCQB4MupNvjgzwPrSmDUGNL0KQPHeoHhvfOILVy8oSOsMbK0Gmrt9j41DDU2vkYoFCIf6ratgSnX/zAfdTAd7/9lrCHC2Pdn5E7ZewUVt+Uti/mi8rUInmdlPa1IqKccSkFJJ+fPnSeGkuCMz8F4cQEjko1PiAKJOfRG4dUIc4A1c35KYrGO8IQAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACAElEQVR42u2Wv2sTcRjGP/eNCb0GrtYTJJjz11CECqmCYjtFqhD/ANuxFnRwk44ipDfULdhREBHHxI5BcKg4merkYBWDiJrDYvCIHiRXkl7OIXjUmgwt+fYo9B3fd3iee5/nfb6npO+5M8LfWATlIBLrw7fPW1svfcWbFcL35mWD96i04kceC+AE4VVaEHLtEzjQa7B8J95XoI3lc3tsA73KaXg4brvrTFMF2mBELoH8So1sYa3rbGIkztLcKbkErJ9NAEaTAwxt+drRpCpfgordAuD+dYMzyYHdP8PfrgfAsUPRcEy4aq2jqZ3VF0o1AAw9xvhIfPeuQFMjXLj7EafhBX1Dj7E0dxJDj8mTwGl4GHoUx/UYUgXmVAJzKoGhR6nYTW4/seRuQBuM8HrhNPlSjaspLbj5TErjysInSuU6r8p1JrYhx46ScHp8+J/AMfQYmZTW8UjFlSvB87cO76zeII7rySOQX6kx++Br1yQsleudMDJUeQSmLw4HYLniD1atdSy7RbbwnYrdxNCjgRTSTGheS5B9ukauWCVXrG6aCR7dOi4/B25OHiYzppErVrHsZvAG3JjUt50BOyLw1/WLM8n9f8L+PEbvW5e7Ds7nj/YV6NnDs//1fF8xQ9uA7yvmkRdv5kWY4KF4YDM4gPDxf4UFDiDatC8BX8IAB/gDQ4ywJknehTEAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB/ElEQVR42u2WPWgTcRiHn7uzIU0kMVxRgnf4MQQhglUQvUzRCnVwU84xKHZwrZsuvUE322wOEZ0rHUXikODUoJMZopihSi+L0CNy2qRccz0XE6q1StpcrkN/4/sfnvfj9753QvZROyd6nTwIh/BRH5eX/gy98QT3lih67ozf8G2UFTzpuQgcJzhlRQLWfgIHtnso3Y8OFNQpndsfweATsFsuj19+ZbG+OngP/E+m5XD7yTK1RhtVbvL24anhJWBaDjdmP2NaDplUlLmcMtwOdOG6liC/C/iOPFAor2BaDmklvGv4jjrwtGQB8OzuMSr1VUzLQZVDaKmo/wl0gWkl3DNgV6ocYmH6BKoc8m8Ei/UfANQaa9jtDoaexNCTqPJIz5h2y/WvA6a1/qvaERamT/aqvXkxwfXZJWqNNeYrTaYmxvw9RFrq4G+tjkUkro7HAGhYjn8jSKvhf15F39cwrYwCUHxvY26q1LQcitXvAEyOx/3zQCYVRdcSvKg0ufDgE5NnYsQjEsWqjd1y0bUEmT7Xse87kM8pxEclCuUVXlftXnzq8hj3rh0ezik29CR3JuTeVpxWwsQi0nC/hqoc6vvo7M1/wg/rV/76cH7+6EBBrwpnt8Q8TzAC64DnCcaR8rsZMUh4IB7YDAcQPbxvQcEBxA02LgFfgoAD/ASjE7z5V5DH1QAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABg0lEQVR42u2WvUvDQBjGn1xtsUbUElDQRlzMIg4KDulU0dFR7Vgc/AvcHKRd3KqOgoOzdS3FpeJkwc1BBQcRUxQKoTZgI7HpOdT61Q9ovm7pMx3vHTy/u+de7rjorh4ntHoAcCNwUXdPD/9LF5QzNwihZsJt8zaKctR3TABMgZ2iBIzVA+hrN5Hb5h01qubmexF0F0EraRUTO6cvHdfE5BBkiXcHoKybSOdLHddEJB4yXAIYDvqwHw831QuqgVSmCAAICwH3Ihga8CEmh/7UFNXA6l7dPLk2jojEe3sJU5kiFNXAuhzC5pLgbRcoqoF0vgRR8GNrZdT7NmzkLkuDELvM3jaAVvnpCKu7twVwef8GAJgR+y3v3hbA2bVW7/tpe2+GZYAb5d1S3zsHUNC/Igh6D6BVzO/xpOD3HqCsm2xew4ZEIYDnw9nen9CZCG4/lltOLJxMOGqUPZprqlHKJZmdAKVccuz8KkFYmjO5A7/NAYBQ0FdW5gBAaqgtAnhkYQ4AnzxdeRMrtuRKAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACGUlEQVR42u2WMWgTYRiGn/tjgiYSLBcSqg2KQxzUQcEhnaKxkxltHUUwg5s0m4NpwLpFHIUi4pjGMUgdWpw8dLJgFVIpYoLB4tH2IJeS9HIObY5gjXKYn3Pot/3fP7zv/37v994pqYetm8LeeQzKMSTWp69rv7Ze24p1SwjbmpENPqBSiu17JoBTeFcpgcd1QODQoIvFe6GhAu0sXjwYgbsR/KkM02Ju6Qfz2gYAY2qAG8kRppIj8gkYpsXE7Gdqetvp1fQOWrXJlmmRTUfkjmBh2aCmt4mrft7OnuHbk/MUJkcByJcbGKYll0BpT/bC1HHiagCAbDpCMrG7NW9Wm3IJ9EAHvTR8xCeXQM9oxco6K/Vtx5BatUlc9TOeCMk14XgiRGFylHy5wcSD1T5l/LyYPi0/B2p6m3ltc1fuoHBeXNM7zlpKVeB+ucFKvUUuEyOXiTqkrj9ao1hZJ5k46moMwm0GvHpvADjgPWNOZ2IArlVwRWCrZf3V6fW+gBo6gbgaIBz0YbSsfS/tnc+OHZbrgdy1KPlyg7vP65S0DeJqgIVlA8O0CAcFt11GsWsC2XQEo9WlWPmOVm2i0XTW8Omdk05QSf0a5jJRsldUPtS399bRxzmX0v8TgR6o29T7P39IPnau/vbiUunEUIFezl3Y17NtpeCZAratFGJL72aEl+CeeKAfHEDY2JtegQOILt3LwBcvwAF+AhZZzKchyRNHAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB/klEQVR42u2WP0gbYRjGf3dXQ6KQVq5UpHdYQusSO1TokE6p6OYoOoYWOrjGrS3FQHWLdasg6Nxqt1CkojgZ6KSDCmmxfyItSoNykESi59ch5ky0FtLmyzn4Tsf7fvA83/s+7/OdEh7NR1RxOA7KNSTGxvfN06klodiPVFXYw7LBz4mwIrRpFbiFexFWcTkuCVw5r7DwtKmmQIcLnZcjqG4EfwsrZzO5+Iu3yV0ADN3DQKiZ/lCzfALpTIG+sS+kM4Wy3AHJVJa5FYupwTa5I4gndkhnCgQNLx+e3+HHxF1mowFMvYG5VYt4YlsugVLbpwbb6DC8ADxob+JVxDyu78kjUGq736dh6p6Kmqk3OGesnC2HwFWfVhRh3q7QAEAylT0RaV4SAX+jRqi9aFCPX39jbWvfAY8ndpxzxqnu1HQLxiMGfWObrG3t0/PyUwU5gKDplbuGpu5hNhpgOZVlJrmLv1EjaPiON2Tb+ZZqRKbuYSBUNJ9ybwAY6r1RXyu2crZjTEO9LWe2QyqBdKZAz8hnx5iqvf0/j6BkSC9mfmLlbIKGl3fRQP0eI8BZxydd14n1t9b3NSwJcf7Z7apnXlMN/C/4xfghWT/o/mPh/pubNQV6P3nvTE4IJeZaB4RQYi2LH4dVN8Fd0UA5OIAqEHtugQOoRxw9BL66AQ7wGxgvuiJCAcHaAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACL0lEQVR42u2WPWgTcRjGf7kzIYmSGi80iHdUBV3SQQWHOMVE0SGjxM0gNKBbaTaH2oC4VbMHKh2b6lbEpcGpJ04ORiGISu+wUDwiwXyQNj0HQ2i+sM0HB9JnfN8Xnof/8378baGn1bhg7qbBdpIx4vPm187QW9PWuC8IZmNh3OR9ELKZ4gsBOIt1CAlYjCMBx/ol1h8dHynR7vqVIwsOZ0EvqIUymlEnFvS2xUuVBivvipQqDaZlF7cueUYv4HH2B5mcAdAmIKsWmV/dolRptGKK5ODl3DkUyTG8BZpR5+aTLy3yztzssg6YJKN+nsdlYkEvmlHnzrNvbaIGFjC7rJPXqyTCPhTJ3pUDSN9TSEYnuRv0ko7LJMI+NKNOJvdzeAETLpGlB1OkYqe7fFcLZQKKk9sdniejkwBsFMrD98DSw6me8bxeA+Dahe594XGLKJId9QACBh7DTaPeIusFudmAerPu/7sFEy7xQHWef9QNLCCgOAH4qNX69ogi2ftaNLQARXLgcYuohXLXvGfVv1sxePHEeG9BIixRqjaYX91CazabZtRZXNsGYCbiG+0t6Bbg482HElm1SFYtokh2NGOnuQv8TMvO0QqYifjantvjFnk1d57FtW02Cr/J6zUCspNY8BSJiDT6a5gI+3ounc4tefQnPNSH5NPOjZ6JqytnRkr0OnO5K2aatpRlL2CatpQ/935BsJLckh7YTw4gmJi/rCIHEPbYuw58t4Ic4A/Ems/0tWkBMAAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABbklEQVR42u2Wv0sCYRzGn3uvhDM4izuSKLGhP6CChjbToMXZNQoF2wS3CNKlua1BUGzLPyAsUNoOmlwscIjwjrajONAD83xbTd+j5a53uWf8fobn4f3+4BUSV/YxoeNrQFiGj3rtv82WnqjgnBBCnZLf5i5KCFSsEQCb4KcEAWcFARbcQOt8yVOjcWs3aIE3AZodCw8di8m03gAN7dObGZiVNXRQuDXQ7FiIKSEcbcu/+GXjA5W2CQDI7K94G0DrDVCoG9DN0RzTzRFOb/roGrZ/LSjUdejmCLmkymAGuoaNXFJFTFn0J8CGEsLjxRayKWWORSQR1Xwc5cyat3dgWrV8HHJYZLagehb3fwvksBjcgSBAEOD//wMsRSQRxfQqZIm9ltmUCmvo+BdADosopqOunHWqgxn4swUv34dMsHe37qnRfWVnrkapUOb2ApQK5Wj7uUR4mnOZgWlzACAU9IuXOQCQCSYHAN55mAPADxmdd7QupFXbAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB8ElEQVR42u2WP2gTYRjGf3cxRXNwKFdS/HMggrc4iIKIN8XWQdBVHUuF7GI3C9oMuh12U8ggjq26HaJIgpMFpw5W0UG0OZSGHtVDe5L08rmYI/YaG8ldbsk7Pu/we/i+53v4pMIdf1IWm3Mg7SXBebfycav0UkjBlCyLYDZpeJcpSCLzQAYOk94UZFKeoYFd3RaVG0qsoM3KyeEVJGvAcZs4bjO+DGydmtvg2kMHgCfXj4T68yWPm4++UnMboVacGKV0aX98BsrVNSy7jrcRoGsjf5mauv8ZANNQUHMZni15lCtrAD2Z2NHArYUvlKsuai56W5Zd/wM6QHFCC02dnnnP/Kt1pi/kUXOZ/jLwxvmFaSi8mDka2enaCKahhPC2pmtZPD/A84P+T2D64himoXTZ5YF8RP/utwBQ92T6fwXd4P8Kq7cRcEzfvePxJ9ID7VwUx0cHX0SWvcrC4jq6luXymX2DNWDZq1h2HV3L8rijJ2Irol6eahve2RWJGqi5Da7eW2HZ8TENhbuTh/4L3rcBy66z7PgACAirurOSzx9Xk78CgMUPPyPalR6CKI3f/iEG8yHJDj8k22fgbfPctotT8wdjBT0tn4hoQkil1E5ACKk0Vn09K6cJTyUDnXAAWSC+pQUHkFu0zgKf0oAD/Aag+rShJtqb+wAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACN0lEQVR42u2WT2iScRjHP+/7pkwNa7wyqZRFMAm8rKBAT2ZFO3gLvI4iYbdq3tpg82C3xW4dhIVHreOIwVA69VKnguyPRFR7KaqJIXOOOfd20ElON6y97r34PT7PC98vz/f7e95HCNyvjIva1jwIx+kh3n39tLv0TBNqN0RRq832mnwPBARNeiQCpzEOARGD0RdwZK9G5p5NV6KtzPm+Bf9mQSco+TKl9RrXRu1t9ZRSBOCYReLWZRm3bNZPQGm9xtziDxLZAm7Z3CJgJv2NRLbQ8n0iu8rCxDBju4T+lwVv1ApX4x/bSADSSrEhysSTyTO8iJ8lGnICcCep6pOBmfR3VgqbRIKOtp7dIuH32IiFT+L32HDLJqKhIbwuC6VKDbWweXAL3LKZ6KQTv8dGIrva0hsbte87ZrtFOriA+XFXV6NUC9W6/5lf5NQKkaADu1XS9xXsh9vJFZR8GQCva4BY+MTh7oEdO9yyiZy6oV8Iu0Uk6GBhYpjlqRF8HhtppcjS61LvBex43wyeVSLsG6wvqA9rvRVw8+EXLk6953nD++biqtSaYnoqwOseAOBuUkXJl1ELVZR8mbnFnwD4PEd7+woiQQdLr0rk1A2uP2g9OqOh+u7QVUA0NNSyXOxWieXpEVJKkceNn5FLNhP2DXZFDiAE42va4Rwkpv5B0jkDb6tXOjYupE7pSvQ0ca6tpmlCzLAJaJoQc2ZfzopGkhuSgb/JAUQN7bdR5ADiNtuXgM9GkAP8ASk0yIbEtxW8AAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABqklEQVR42u2WPUgjURSFvxk1IEIwzGIwOrBYaOkPLKJVFEGLlGvasIhgbTotdArtRuy2UNh6B8thYYuI3aCVoKhsoZIIYnCIBjQQTZ6dBGOc6E4yCDnlfYc539x33+NJ4dVcTBaP6yC1U0MdJ09flnaEVPghy6KwXOvwCgpLoumXDHzFO4VlPFYDoLnSQmKhzdWgx8RQYwv+H8D6d8ff/eybnpSdx7Ayjj7HGShV9r6Abl6xsW2jKj4mB/wVvbqZxrAyjr6qAQ4vcsz8TJKy844fM6wMhpVxdwuWjEtSdp7Z8S+OrdfNNKrS4i6AqvjYmu9Bi3a+6dPNNCk7TzwSdBdgPdbNaG9bVYMXHQkQHQnU/xh+XzsDIB7pqP89oJtXz61XFV99AUoH7yN/X/U9UEmbiWsAbnNFhhdPyuCGF0/QoiGm+v21AUDi3cfOVQBtOoQ2HSqrh+YOUBUfuyt9n/g98JrikQ78rU2u+T4AEHTV13iQADQfPUy8uvDtd5erQX82BstqQkiaZx0QQtKC23vLspfhnsxAaTiALBA3XoUDyEWKY8C5F+EAT2lXm5pagT61AAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACI0lEQVR42u2WPWgTcRjGf7mYcCZ6qAkEMWelYBCJEAWHZorWIUNXXUWx0LG0mw5th7oF3BQClY6NdgtCkQSnHDoptAo3iCZHhZAjTeR6JR89h0po8yFqc5xCn/F9uHve//N+/P+uxGPzrmC1noDrFDbiU/Fzd+iN5WrfEwSrPW+3+AAkXJb7uQBcwDkkBBzGUQLHBhG5h/6hCrVy145K8J/1QDdKeoPpZQ2A1ZnRTvz+069saGbfb1ZnRgkHvIdPIJ2vkMqWqW+3kbt+WNKblPQmcsBjjwNzmU3SeR3J179aG5pJPOLn5T5XhtoD69oO8Yif148u9nD17TYAJ4+77euB2YkQ8Yh/wOl3AIjKIopqsK6ZnD/j5bIs9pTqrxMYJA5Q++lARtkilS0f4BZun2VyPGjvGIaDXuSAh5rZYnYixNLUCJM390TnXnyjoBrDG8N+iIZF3i5eoqQ3OpYnYxKSTyCVLbP2vvZLB4e2iLrrHY+cAKCoN+0tQUapMr2soemNvvx3s21vAgXVIKNUSef1A/EVpQrAnbHT9vbAg/HgXgK5CsVKg6gsUlANFNVADngYi/jtdSAaFlmaGkEOeFj7UCeVLaOoRmcz/s4u+CMHNp9d6YklYxLJmNQZOcnnJhoWh38bHmZh/dvvgY/NW32J6yvnhir0Kn21J2ZZrgXHHLAs10Io/25ecFLckR7YLw4gWFhbTokDCLvs3gC+OCEO8AMLAcBQWMuQsAAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACJElEQVR42u2WP2gTYRjGf3fXBpPAmXJikCYoQbvYQQXBZIpFcOlo4xhEHJyEdLODjaBbaDeHIuLYmDFoSmlxO3AyUBQyFGkC0sIRe9iLXHs9Bw1JzR9PcvGWPHDLvR/f7+X5nu/lE5LPG2nRPloGIcQQ9Xln+89f723BuieKtrU4bHgPJQVbeiUCF/BOSRGPNWpgrFdh43HQVdDRxrXREQzegFo5YO2j3re+VfvhTgbapRsWueIuK5saUcXH7Styx5pccZdccY+o4mN94SJyQHKnga1ag/svdqhqZs81Lfg4S+mIY7ijI3iS/0pVM3kwc+av8EImRmIq6G4GooqPQiZGNnWuo1bVzBPwqOJzbw40tZyO9LF+D4D52TA17RC1csBpv9Q1IwOFsF/qZb/EqlpHrRyccO3lw/NMR04Nbw7ohkVVM9EbFjXNZCkdoZCJkYpPUNVM7uS20Q1reA7sN1qbt59/YiqIbliUyjqlsk4qPjHcSRhVfB3ha2ag39UduIGo4kMOSOwbVofVzTw4uRUDOXD3Rgi9YfHode1XHgyLvFonr9aRAyJxBzNhoFswPxumVNZZ+/216+ncpCMHxv4NeBbZ3xqzckBifeES78o6b9Q6AJcjfuYSIaYjfkd7CjPPvtv/50EyPnqQdM/Ap8NbXQvXVyddBb1dudrxz7aFrGcO2LaQDW9+WBS9hHuSgXY4gGhjf/MKDiAec3wT+OIFHOAn4h/cPp8lgs4AAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABp0lEQVR42u2WvUtCURjGf/eWEQpWOETlhQhyiYiCBp0MGhpac436C6K2GtKGtqCtwCEak9oiglCaCtqCPsAh+hADSQopjfJ6GkLpw0tXvXoJfMf3nMPznOd5z/seybucmZRFdhWkVqoYl7dXP1OHQlKnZFmo/mqDa4RXEg0bMtCNeeGVMTnqBBq1FsLzNkOBsuGhugX/rAZ+xl3yjZnNGAA7sz0ATK/dcB7LaJ4J+DoZG7BXTiAYeWBlN0EqraI4mgp5u7VBg+w7AKm0WrkCi6E4wUgSu/W3W6uTzqJkF0P3KA7Ln7fXVQNnsVc8LhsHC726bFrZTaA4LGzP9mgqVJICc+PteFz6ekLepqWJjm9WVaSAXvDzuwyh40cUhwWfu632zzAYSRYUM6UP7J+mAHC7bLUncBx9IZVW6VOadXtvKIGj6PNnvfSWPsAMIZBvPM4Sb28ggTcAWnS8+6oOo3IUaCxlc3y9v2g+P5zq/4Gy/gMX76NFF4a3ugwF2gsO/soJIQVMU0AIKdAeOfHLZoKbUgNfwQFkgXgyCxxAzpEbAa7NAAf4AO/Di5iwh+rbAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACOElEQVR42u2WMWgTcRTGf3cxwRhJDVeUogcSMItDquCQTDG1tIOr6VhEs9e4iWADtlugm0MHydiYMWhAGpxy4NRCqxBFpAlIiiHt0SSl9noOmuj1ErQk11vytnvv4Pve+773+AuRxdasqB8ugXABC+Pj1pfjqXe6oN0XRV2btxq8R0QE3fFSBK5iX0REbI4hgTO9CqtPPAMFOly9OZTgZBJ0C6XUQG1qTI17Tfn8mspuS2PE7eDhhIQsuQZHQG1qpHJVlgs1ZMllIJDKVUnltg3/Lxe+k7w3RnxitH8CG5UWD15sUa4dmGrl2kEHPJvwI0suiqU9HqUrpHLbzIR8eM85+vPAs8w3yrUD4lFzN5vlfQCmgl7CAQ+y5GQm5CMW8qG2NDYq+/2bUJZcZBN+krExU63d3cixLtWmNjgTLs1e6Vlrd51R6oQDHsKB87xZ3yW/riJLTsIBz2C3oFtkE34mFz4zl678mYzbQTbhP507kMpVUZsa4YCHWMiHLDlRW5ppMyyZQEapk1F2iIV8Bqnm0pWOLLGQz7oJ5NdUABPIdPDXnSiWGtZK0N4CtWV0/fFvywhcl892bsXm751XSo2O/pZvQTw6SqZYZ7Oyz+TzT0YZxr3/1P/EBB7fvYjXbTw6b59eY0Wp80qpd2SZDv4fOIAQXdjTT+dB4hw+SLp74MOPO10Lt1YuDxTo9fINU07XhaRtE9B1IXmp8H5etBPcFg/8DQ4g6ug7doEDiEcc3Qa+2gEO8BMSidYHadDDogAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACPklEQVR42u2WP2gTYRjGf7k2oTGSVK40WHMgDlkqGAWHdKpVaIfbbLOGItnV21zSOLil7aaQgnRscAyiQ4KTAScFq9DBP71AaMlRe7SJXHs5hzbFJA1Wc/GWPOP73vE8vN/zvN/nmnxSiwvW4TK4hukhPm9+aS29sVzmvCBY5kKvyTtg0mUNPBeAyziHSQGH0Rcw2KmRf+Szlegwf6N/BH93BKehuLGPXjWZjvib6qpmsJLX2K2ZBLwDzET8RMM++wToVZN0botMQUMSPU0CMoUKyWy56ftMoYIij6LIwe4FfCzVuPd0E1Uz2nqqZpDMlvGfE1DkIDPXAqiawYNVlXRuG0n0EIte6M4DyWwZVTNITI209VbyFQAez42RmBpBEt1MhH0sxSUA1oo73ZtQEj28eHiFVOxiW2+3VgcgJHpa/nGfeKZrAcvxEBMdDBXwCsdEe031knbwf2I4HQkcmS6vkS3usF76yev3OvdXSwD4vQP2xrAVE2Efihwknds6IW3UVc3gqjTUWwEAijxKLDrMqw86etUkGj5PcWOPtxv7f0yALQIaRm2kRNUMZnPbSKL7TMvI1lWsagazi1+PJxNEaklHzybQiNz8s+/oVRNFDp5p/LYJWFdr3F08enSm5sZI3BZ7cxkp8uip0RqXvKRiY4yHhjruDJsEdL5cElPiP02v/yAZ/HRw59TGzbVLthK9zFxvq1mWK+XYBCzLlQoW3i0ITpI74oHfyQEEC+uHU+QAQp36LeCbE+QAvwACrcoZiREYiAAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACjUlEQVR42u2WQUhTcRzHP3tr4jZ4GU9a2h6FhyUpSEEHPZlLENoxvYrgoKO1WxfdYd1mHgOhsJvLWyO8KJ1cdvIyiyFSvUex4LF8tPfG5tvrUD20Taw2GYHf4//3+/+/X36/7+/H3zX80JwU7P0FcHVwgnj7cff3o1e2y5oSBNuaO2nyIzDsst1PBeAyrcOwQItxKuDMUYG1B/6mEu2vXT9twX/mgYPI5IosZwooWpn+oJfpsIQstR3KSabzrG7piD43YwMi0XBncwQk03mS6S8AiD7BEbMS66E/2A7AbOoTi+sasuRBNy1mn38mq5ZYmAw21gLdsJyHNxNXeDffR3y8C920SL7IA5DKFFhc14hFAmwmetlM9BId6SSVKbCRKzYmYM+0GAr5iY93OyWPhjuRJQ/bagmA1S0dWfIQi5x37sUnuhB9blKZQmMtkKU2nty9VEdY1Sm/olW4GvTW5IwNiGQarcBRhtQNi76fArKqSb/cXpN31iugaOXmCtANi5klFdEnMH2My0Wfu/l7YOaZiqKVid2+4HhC9LlRtEpNrqJVEL3u5uwB3bCYevyBTK5ILBIgGpacWF+wnaxq1tzJKqW6rfnrCihamdHEDplckfh49yG3AwyF/GSV0qGRW93SyaomE4PnGquAbliMJnbQjR/jqJv7JNN5Jx6LBJyZv7ekMjHYgW5UWX5dQJY8DIb8jQnYMy10wwJgI1esWSyxSADR52blfg935nedjTkU8vNoMlizruvBNZL4ZjfrP/DLjLLkqfMf8Py7Cf8U9YhP/wPHmnC7cqtu4MbyxaYSvVy8VnNm2654yypg2654YP3NnNBK8pZ44CA5gGBjf20VOYBQpXoTeN8KcoDv7l8JuauTMrAAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACHklEQVR42u2WP2gTYRjGf3dnJE0gWiLt4B1KwAy2IAoOyRSrgkM2pWsUdHBSk01E2qFuqdkrSt0S61ZEhRQnD5w6+AeCVPECQugRPUwiZy/nYHrY/MFILrklz3Tf833wPPe+7/fwCYl7jZRo7+RAOMgQ8eHLVjv1yhasK6JoWwvDFu+BhGBLj0TgKN4hIeIxxgb29doo3g66KrRTPDVuwf+1oB0FtcrrUg2AAxMSV8+GUcL7u559vmkQCkjEo0F3DFxc3kJtie8ir1ZZy0SYlf0Op+kmN1fLqKUa8WiQeDoyeAsKahW1VGNG9rOWjvDyzjHmY5MYDYtbq2XnnFqqcX7pY4fRgQ3k1SoA9y8rxKNBZmU/uZRMKCDxTmtQ1k2nSmBzbe6QuzOQSylourmn1H/mQMSoW856Rvbz8PoRAFY2tt0zoIR9KGFfB/+90QRAbg3i03SEUEBCa1VkqNewoFYx6hbzsUmHCwWk0eSApptk1ysAZJJTow0iTTe5tPwJTTfJJKd75sBQDLSLu/H3fQfRi02DG4/LGHXLVfG+DDwobnP3yVen5/FocE/YyGHfQK34p4G35Z/Od3a9QpZKW07IKLEhGrhwItQ1B3ZxXJloCyiJTHKq76oIc0s/7NE8SHzjB0n3GXj/61zXjdP5w64KPVs52cHZtrDoWQVsW1ic3nizIHop7skM/C0OINrY37wSBxCbNM8An70QB/gN5mjEI42T+CIAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACeklEQVR42u2WQUgUYRiGn51tF3VhrWZpiXbaCPKQBhZ00JNZUIc9mlfJWNhu0t4izL10W/FmsLDi0anjEhEonRroFrgFBho7g6I4rU3sjoyO00FbXHdNY1a2g+/p5/v+mff9v/f7fn5P30tzSHC2J8BzlhPE18LiwdAHx2M/EgTHHjtp8kPQ53G8UwJwheahT6DJOBVw5rDE7LNAQ4m2Z2+dWvBvFuyHUbZRFkoUflhcPu/nutSCJPqr9igLJVTd4qdp0xVppacj0BgBqm4xML6EqltV8YmhCIM95wBI51ZJ59aq8vG7IVIPL7q3YGRaQ9Ut4v0hsoko8f4QAKPyCkbZRlaKpHNrSKKPbCJKNhFFEn1kZtdJ51bdVUDVLZSFEr0dAVKDu6d50B0EHDJzOh+/lZhRigC8eXq1YkuwzcvA+CLz6qY7AZLo5/3za7S3Vhcq2OatrKcSUea1zaqekEQfAL9M230PdEVaamL5vZNFRD/BNi+9BxpO07cA6KzzresxVHWLd58NJNFXVxxQseV+d3vjBQxPFgBIxsJ185m5dWSlyGDPuZrKuBJglG1GplXymkkyFq6M4H7ISpEX8gqS6CMZu9C4i0jVLYYnC+Q1k3h/qO7P/9wFkuirmgjXAuY1k8eTBVTdIhkL15AbZZvR18vIygadkRayT6LHJj+WgIHxJYyyjST6UXWLkWmtkuvtCJBXTWRlY7frpdaaG3FiKOJOgFG2KzaoivXXvfJe9zdUwPKrG0eW8SiS0yfZ//0g+bJ1r27i9sylhhK9zdysiTmOJ9W0CjiOJxWe+zQmNJO8KT2wnxxAcHA2mkUOIOywcwf43gxygN+qBPa0Cz03OwAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACsUlEQVR42u2WP0wTcRTHP73aBlpTlGto1J4YEhnExD+JA0xYHBi6CayNSBPckG7GIB10o7IxNMF0FBiJISY0TjZxkgQ0wQRMrwkROTEX25KD4xwKZ6+FGNqSLrzlLr939/t+33vf9/Js3a/yIcHYmwTbBU7RvqbXSo8+GDb9kSAY+vhpgx9j3TbD/kYArlE/6xaos50ROHecY/GZu6ZAe4t3z0pwshIUm5rTSa1mSf/SuNrs5IbUgCQ6Ld+kVrMsZ/IAdLWfp8PfUBsCsqLRF1tHVjTL+WTIz0DnRQAm5n8wMb9p8Yd7vET7L1VfgpFEBlnRCAe8TA+3Eg54ARib2UDN6cyktpmY36TD38D0cCtzo21IooP44hYLS2p1GZAVjdRqlq52N9GBQjS9tz2AQTyp8PFbFlnRCuBPWs2yvA5J9MXWWPis0nvLUzkBSXTy/vl1mhqtifK47OZ7JOgjEvRZ/LaDZ+l/FWng5hFiWpF3APAfIUQ1pzM2u4HHJTDU461NF5SWZWFJRRIdFnKyovEwtmYRaWmn1ITA4FTaTH2xNTXaiQRbAJhJbTOSyACYnVL1IFJzOiMJmZVMnkjQV3axx2U39TA32obHZS9rzYozICsag1NpVjJ5wgGvGelh3WVFsxCSRCdNjULZ7KiIwHImz+OpNLKiHUTYUjInZGRlF7/opKvdbRKWlV0k0VE9gb7YOmpORxKdyIpm1rYwct0MBby8mN3gaSJj9vzhABrobK6egJrT/0WVKk/pZMiPmt8nnvxJPLl1oAeBaP9lwj3ifwnYAi//GLXYB9ScznJmx5wdxcOqsA84atOGx5nHZTc1cLYTnmgh+bL74EjHvbdXagr0Ln6n7MwwbNG6ZcAwbFFf8tO4UE/wumigGBxAMDB+1wscQNhn/z7wvR7gAH8B/IoN5NQ54xQAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACR0lEQVR42u2WT2iScRjHP+9rypzhWooSaUWQh1j0Bwr0ZNJhB2+J19FC6DjyVjHmpdtkN4NBsWNGtxERbHSa0C3ICoMM35dFg7cNQY13c28XfdO9GvmPl8Dn+Pwe+H5/z/f7PDxC+HFtTtQOVkA4wQjjU+nr0dRbTajfEUWtvjRq8C4RFjTLMxE4h3kRFjE5xgSOdXvYeOAYKtDBxrWxBL1J0Brlap1coULpp8qZkzYu+ifwu2xd62VlHwCfyzo4AUlRiaWLSIrall+Z8xEPThvqs7ldFtZkALafXBpcgoU1GUlRSUTcPL13lkTEDcBi9jvlat1Adnl9Z3gSSIpKrlAhFHCQip8CYPaKE9BY3VTY+lJh9rJTr19e30FSVJyTFgO5vgj4XTbePLrAlL29Uc5JS0ey2dwu8eC0TnwoUzDjMxouL/1qmOxPPpYu4ndZSUY9ox1DSVF5/b6M32VlxjfRaP0PJEUlGfX+dTqGQmA+UwIgGfW2GS8UcHSciqHsgeYuWHyxTV6ukYx6dbCm65NRrz7/rfvAaRc7eqYnApKiMp8pkZdrJCJuXeem8QBupw0XDzcefiYZ9ejd6ovAB7nG3UxJ17jVZFN2S0fTZXN7jXoPwcDxwSSIpYuUq3X8LhuSoupbDiAUcHT83VahohMe2APNhSIpKlJONbz3Y7yeCPzLPj8aL++fH59k/9FB8nH/VseH689PDxXo1epVQ07ThJRpHdA0IeXdfLckmgluigdawQFEDW3PLHAA8ZDDm8A3M8ABfgM5e/KpBI0oKQAAAABJRU5ErkJggg==","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACpUlEQVR42u2WMUwTcRjFf22lodQUsY0NsWccpBrBoCYmthOiAwMbiCOByE7CpkbBRDcqGyQdDKN1JQY1ECcuOknSalKTor2LRMOBXHK95uR6DrQNtRACV9KFN35f/ve+//veuztH13N90GltTYHjFEeIr9nM/6UPlsMccjotc/yoyfdAl8NyvXQC56kfupzUGccDnNirsfDAW1OirYXrxys42Ap2Qs2ZiGmN7LrBudNuLguNCH53RV/VC7ueDfkb7A0gKQb9sRUkxaioTw2GGIi0ADA594v4olJ1VvC7+fjsor0BRmdlJMVgpDtAJOxFTGvEF9d4nFilp9OHr8lFUs4DMNZ7puKsz+OytwJJMRDTGtGwl4mBVgB6rvoAi/iiwtI3jZ5OH2quQLvQyFhvsLYeEPxu3j1qo9lT6VVfU+XNpHWDSJv3aEzYEWqsqqWkfNFg7m0D5kxU3aQvliEl52n2uIiEvTy921o1rO0YSorB/LKK4G+gI9TIpm4CIKY1UrJONOwFLBLiBkMzP2oTw50Yns4WDRescPr8sspId6Acy75YBjGtsVT0kG0F1JzJ6KxEStYZ6w2WI1gaokRe8sj924HiunT7CkiKwfB0lpSsM9IdqIhbUtYR0xqR8Mld/aIWV3RoBZKyTn9spXzzUhxLENMaTxKrvBY3quoA7YLHngL9sRXUnIngdyMpBqOzcrkXDXu5d7OFybnfxBfW2MyZCP4GknKet5+3jdrT6bM3gJozy2uQRKOqPxBp4f3DC/THMiR2qBANe3kxGLKfgp8zV/Z9yHYSLpGU82W1hH0+QoeO4UFfWsf/hPuu4MvfO7s2brw6W1OiN/FrVTXLckzUTQHLckwEFz+NO+tJXhcP7CQHcFpYf+pFDuAsULgFfK8HOcA/p0QX1wgsFaoAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACr0lEQVR42u2WT0iTcRjHP5tuzBbT9Yqj2qsROaIWWtBhO5l0GLRbNo8jQfA43C2k3KFuTm8GgrFjo6OEJUonR50MXMGCrL0jQXozB/vDq/Pt4Dady9zaZBef4/P8eL/f3/f5Ps/v1fQ9y3i16s4UaNo4wfgc/3o49U7V5B5qtWpu/KTBj4g+jdr0QgtconHRp6XBcUqg+ajC4iNjXYF2Fm+dtqC6FhyMZDpHJJYi/kuh85yea6IBUdAfeX41kcFubakPAUlWGAiuIclKSX7Ka8XjMJed9YUSRKUsC2NX/kmy4hb4QgkkWWG4v53ZkS6G+9sBeBxeJ5nOlRGNxFIMOsy0tjTVroAkK0RiKZw2IwHPeQBcvSZAZWZJZvlLClePqUSlKa+Ix9FWHw+Igp63Y920tpQKZTpTeruJuQ0kWSHw4EJV4BV5wG41lOWiUhYAq6BHkhXCkU2cNiN20cDM0s89pXpMFXmgudqxkWSF+Y9JREGH3WogHNnM57e5H9x/cp+E1/G7O/C7LfXdA0PTcYDih6NSBoCtzA6zI128f3qVSa8VUdAxMbfBcixVHwLJdA5fSCKayOB3W4ojuJXZ3SN0z4Kr14Qo6Bh0mBnNE3yzslV7CyRZYWg6TjSRYbi/Hb+7o1grGLT1kDE78/0vEPxvBVYTGQaCa8WbF8axEA7bWYAyqedXkgA4bcbaFBgIrpFM5xDzjveFEsWa02bE4zAjCrqiGa+LBqJSlnBkE1HQ4eox1UagsO0kWUGKKGV1j8PMq9HLDE1/3yMR2Sc36bWW7YyqCfx4fuNYj4iCnoWxblYT2aJaoqCr32tYafxtaZ3+Ex7bgk/bd/9auP3yYl2BXs/cLMupqibQMAVUVROwLH0Y1zYSvCEeOAgOoFVRfzcKHEC7y+4d4FsjwAH+AOVDD5i1H1ADAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACSElEQVR42u2WMWgTcRTGf3c1oTWS2l4xqDlxMYIKrYJDMsXokCGbtWuxNnsgm4g0Q91aumXIIBntXKQIDU4edCsYhQhW8j8QSs/KYXJybXoOLaHNNVXbq+fQb3yP///7eO97jyclX1jjsrM1B9J5ThAf6587Q28dqfVYlp3W1EmTd0FScnpeysBV/ENSxmecCjjTLbH0NOQp0dbSndMW/F0L9sJsttBqDerfbK4MBrmh9qIqwXbOtLa7vo0qgeMJEIbN6OwqwrD3xefGo4zFByhV1plZWOv6fnn6OtFdsUcSkCvrCMMmmxoiHguh1RqUKus8n/9KejhMPHaOfKZT9Cbz2gYA4b6eo1dAGDZarUEiFqIwdhGA9EgYcChVDN59apAeDpOI7Z+Yh7M7e7/w6BLhs8cQoCpB3jy7Rn/ffq8e9um8toFWa5BNDZG9rxzfhLeiva5YVfzcNVjQZdaZhTVUJcDkH5AfaQyFYbO4YqIqAZe4xRUTYdikR/rbU+K5gIliHYB8JuLKlZYMACZTiveLyGy2yJUFVd0in4kwFh9wVaaqW9zcsyM8W0TCsJko1qnqFtnUEPnMhe6+GAx6uwnf6xZPinWEYZPPRA4kB6jq1o5p1V5vBYzOrmI2W6hKEGHY5Mp6O5eIhdqtEMZme3Q9FWA2W+02CM125Tu98LvF0wkpNf3D+Tf3QOD0HvhPD5IPmw8OTNx9ddlTotel266Y40gF3yrgOFIhUlmekv0k98UDe8kBZAfnu1/kAPI22/eAL36QA/wCDAPfxsKqqRgAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACqUlEQVR42u2WTWgTYRCGn2zs0iYQTRMaxGyrhRbRilXwsDnVIKiQmyXXoBLQW2luIv056DHkVqGo9Gjas0ShxVMXPbXQKEQwpRvai2vbYH5Ym64H0yU/rbYmJZfO7ZuZ3Xm/eWfeXcvQ80JIMHZiYDnDMdqXtW+1rg+GpXRfEIzSxHEXP8CGLIb1tQCcp3U2JNBiOwFw6qDA/BN7UwvtzF8/oeBoFFRaNl9CSeVY+6HT3SlySWpHcol1OYnlLNuFEt2dIrcHHc0BoGo6w9E0qqZX+WMhL0HZeWCO5BKZG71QB/TIFIzMZFA1nbDfzatHPYT9bgDG4htk8yUAs3jY72ZutJdIwIOq6YzMZBrrgKrpKKkcvn47k8GzANwZdAAG0wsai19z+PrsqJpelePrt5NYyqKkcmTzJRw26/8BkFwi75/2cbqjulH7vdCoOTtsQnNmYMDbXudLqkUAvC4Rh81KUHYSVzaZnv/OgNRBYmkbJZUj7Hf/9faH3oJaWhLLWSRXmwkuFvKSVIuMz26YeZe97SYlTdWBB1NrAEQCnopBVUlmCgRlJ5FAF0HZSTJTbHwIa/d8bHadZKZAJOAxV1BJ5YgrWwRlJ7GQt+qZuLJJUHbi67c31gFV07kXTRNXtgj73UQCXWZsMfXTnPxKk8vnpFpojIKVTIHhaNq8eS2v3rLQLKZyVX6lfJbcYmMUDEfTZPMlJJdYJy6+fjt3rzoYt1mJK5vl1W1jJVPk3dKfQfX12RsDsKd2qqajKnpdPCg7mRvt5eHUqgliD8jLxz2Nr+H6iyscRis+PrvISqZoKt9++tEUHTiqaJ38E/6Tgs+/bu0buPHmXFMLvZ2+Vv8BMyyTLeuAYVgmPQufJoRWFm/JDFQWBxAMjK1WFQcQdtm9Cay2ojjAb8F4F3uF/wLNAAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACpUlEQVR42u2WQUhTcRzHP3tzY3Owyg1H9J6VoIc0WkEHPdko2mFH8ZhkDDqKu1U4PdQt82YwKDw27RYhhaOTg26CK1iRsTcmBC/z4fbi6fN1cBubU3Jssou/4+/34//9/r/f3//3nmXomTYqmLuzYDnLCcbXzI+DqU+mxbgvCKYxddLgR8SQxbS+FoBLtC6GBFocpwTajiosP3I1FWh3+capBfVZUBlqwSCZzpP5rdPVYeeK5EDy2Gt6llZVZEWnX3Ry1+9uDgFZ0RmeWUdW9Kr87KjIyMA5ANayGsMz66gFo1yXPHYWJy7XEK3bgvH5LLKiEw54efXwIuGAF4DJ+AZqwSgTBJNIyMfiRDfhgLecryRVtwKyopNM5xnsdTE9ch6AoN8NmMQSCivf8qRkDbVgVCky2OtiSzOIJzdZWlXL+boVkDx2Pjzp4cWoWJV3t1srSO4AIB6QeqB3/xmnZK0xC/rF2oFLyX/LoJLHBkAyvV3Vk0znAdjS9hp/BQdtWVpVkTw2+kUHZ5wCsYRCbFkpEnaykt4mntwsqmhrLoGxuQwAkZCvbNPsPZHoQo7n734VLRIY6HWRTOfpk5zNIaAWDCYXcqSyGpGQr2qwgn43Qb+blXQed7uVrg4bd55+R/LYCF5zN05AVnTG5jKkshrhgJdIqPPQvsHi4EXjOWRFL6vUEIG1rMaDuUz5wKPASxGN54glFPpEx397j0WgtEwkjx1Z0Rmfz1bduHIbRuMb+76LDt5OdDdnFZc2mazoyEm9pl4i0NVhJ1vcmJFQZ9WuaIhA7uXVYx3kbrfy8XHPsYFP5HNcL/jpDwlA25ed24cWbr650FSg97HrNTnTtEy3TAHTtEz7Ep+nhFaCt2QGKsEBBBPzT6vAAYQ99m4BP1sBDvAP3HcVryGTVowAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACn0lEQVR42u2WQUiTYRzGf/vWhtvCOb7YsPaReNhlQhREbCeTDkE7unkcER28id+toJxQt2m3DkvCY8NuVnqYdHLQSUGLFmi4j0LZWH60TTY/vy7ua+YsY7N18Lm9//eF53mf//N/eU39j8tRQd99AqYuThAfNtZ+Lb3VTdptQdC1sZMmPwL9Jt38XAB6aB/6BdqMUwFnjtpI3XO0lGg3deW0Bc0JUPJV0pkiaklruK+WNOaX1N+e+asM1JDNVxiZVkhnikZNDrmRQx5jvaKUGZxYN4gl0crU8EX6vB3NOzA4sU46U0QOeZiMevF7O4jPbpFMFwyBd55u4LQJTEa9TEa9gM5gfO1YTgh/ur0kWrg7cA455GYo4OLlaC8Ab5ZUAJ6lcmTzFWZGexkKuBgKuJga7kEtayQWcs21QBKtzOwT1rBdPnirFWWHoM+BJFqNWp+3g4DPwWKmiNyqEK4qO8wvqYxMK3TaBcYj3Ubd36DXkmhlNbvTfAhreJD8YgQxEnAZN1ZLGp12cwMBFtSy1joB4+Futst7JNMFkukCTruZWLjbENFoLFsyhjX4JRsAQZ+DbL5CIpVDvuVGEi1s5KsNAlzFLzU5hivKDiPTCnPL6oG60/bT8oDv7KHHJ5uvsPipiN9ra06ASddJpgs8TH4lm68AkM4UmVtWkUQLnXYzkYALtawRf7VlWB+f3UQtaUQCruZa4JdsyCEP8dlNrt3/iCRayO7bHQufN1pSO5NI5epeSw9Bn6P5DMghN17RwvyyilrSuHnJSTjYRV+dvbUz9VNyHHIA08Cj7/q/+Q9YTv8D/+mf8H31RsONqy8utJTodeLyoZqum2Jtc0DXTTHPwrsxoZ3kbclAPTmAoKN/axc5gLDH3nXgczvIAX4A6SAdYsDAGeAAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACQklEQVR42u2WP2gTYRjGf3exIfbksEZaxByRgFlaaBWsJFMsFjt0a8kaHAQ7mmxGsAXrlpA91bpaMwYpQoJTA04K/qlRgpgoRD1qg0kk6fUcDKGpCbZy5y15p+973497Hp73+d77hMDdekjUdxIgHMfEePOxsD/1VBe0q6Koa4tmg/eIgKDbVkXgDNZFQMTi6BM40quQuSkZCrSTOd9vweFasD/Wclts5KsAjCoOZsZlFKe969n15xUE4MqEbAyBuXiBXAscgBysZFTuLbgZczna6UpNI5Yuk8yqKE77gQj8tQUrmW/k8lVGXQ5SYQ9Pbp3l2tRJimqD22uf2+delupML78nmVWN9cB2XcPvlbi/4MbvlRhzOVgKnkIetHWocuPBJ4pqg8jsiLEe6PXBSk1DcQ609/KgSCrswe+ViKXLxpsQoKQ22a5rJDNfAQj6TrRrq9fdyIM2824BwGR0s732eSUis8N7FLCZPweCviFmJmQU5wC5fPVQUhuiQCLkAqCoNpiPF4ilv+DzHsPvlcydhCW12bFXnHZmxuVWrWHuKL4YfctkdJNKTevIF1uk/rX3Bybgal21uXiBV6WflNQmsXSZ9ReV32N5zyQ0xQOJkIv5Fvj0nXf7akrP/4FhBBSnnVTYw0a+yqPcVksVO0HfUE/zRWaHkY8erDXC1PIP/f88SAb6D5LuHnjdvNy1cOHhaUOBHifP/ZHTdWHJMgV0XVgayT5bFK0Et8QDe8EBRB39u1XgAOIuu5eAD1aAA/wC083IzkRnqHoAAAAASUVORK5CYII="],"arrR":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAARCAYAAAAhUad0AAAAZUlEQVR42mNkYGBgSOt495+BTmBWhRAjIz0thAEmhgEAQ8fSmeWCA+NTSiymKHjJtZjiOCXHYqokJFItpoql6Z3v6WspqRZSbCk5FlJkKbkWkm0pJRaOsLJ3VoUQIz0tnFUhxAgA0EMYRk5rSpMAAAAASUVORK5CYII=","arrL":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB0AAAARCAYAAAAhUad0AAAAZElEQVR42uXUURGAMAwD0BQHVCRIoBI2CVQkSBhfCFi6644jBt5PEgGArVwNSXFTkUzwzYIJ+R56HmsuyoI0GgEpNAp2oyPAbnSv95z2joCpIkVhejIROHQOLPyj73VTyQTdVB5IUhhGVdHiBQAAAABJRU5ErkJggg==","miniNav":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAAAMCAYAAAAH4W+EAAAAZElEQVR42mNkYGBg6Fj17j8DiaAiTIiRUr3IgJEcg6gB0B3DxDBIAEGHlIcKkmwoOXqYqG0guXqZaOEIcswY/Gmkc/V7ig0nxQwmahlEqV4mahtIrp7Bk0awFbfEloyU6EUXAwDEbiGbJxOS8QAAAABJRU5ErkJggg==","close":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAYUlEQVR42mNkYGBg2H3m/38GYsDuM/+JBkwwTZ2r3zN0rn6PYRiyOBM2SWxsBgYGBsbdZ/7/dzHGLgkD5aGCmCbDBHGJMTGQAJhwuRebGBM2wfJQQRTrcYYGsiIMP5ASKQDlG3vYITjb5AAAAABJRU5ErkJggg==","plus":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABABAMAAABYR2ztAAAAFVBMVEUAAADqQzX7vAXlZjJChfTVbDY0qFNGmUfDAAAABHRSTlMA///pR/n12QAAAEhJREFUeAFjwAZGgSAQDLyCUQWjCpTgACgv7AIH2BWYEFAg7EJAgQkBBaIuBBSEEFAg6kJAQQiqAkyQBgQI3oApGFUwqmAUAAA3gEptDjzKJgAAAABJRU5ErkJggg==","mi":{"add":" ","apps":" ","arrow_drop_down":" ","check":" ","check_box":" ","check_box_outline_blank":" ","chevron_left":" ","chevron_right":" ","close":" ","delete":" ","edit":" ","event":" ","expand_less":" ","expand_more":" ","help_outline":" ","lock_outline":" ","menu":" ","more_vert":" ","notes":" ","notifications":" ","people_outline":" ","place":" ","print":" ","refresh":" ","schedule":" ","search":" ","settings":" ","subject":" "}};
}
return ugfCalArt.c;
}
function ugfCalWanted() {
if (window.location.host !== "calendar.google.com") {
return false;
}
// Gplex's own hidden helper frame, and Calendar shown inside other pages
try {
if (window.top !== window.self) {
return false;
}
} catch (e) {
return false;
}
const p = window.location.pathname || "";
if (!/^\/calendar(\/|$)/.test(p)) {
return false;
}
// Google's own pages for editing, settings, search and the rest stay Google's
if (/\/r\/(eventedit|settings|search|tasks|trash|appointment|birthdays|timeline|tasks|workinglocation)/.test(p) ||
/\/(embed|htmlembed|appointments|render|event)(\/|$|\?)/.test(p.replace(/^\/calendar(\/u\/\d+)?/, ""))) {
return false;
}
let on = null;
try {
on = typeof GM_getValue === "function" ? GM_getValue("UGF_CAL_ON", null) : null;
} catch (e) {}
return String(on) !== "false";
}
// Which Google Calendar a layout gets. Calendar opened in April 2006, so every
// older layout shows the 2006 Calendar.
// c2006 the original, in Gmail's blue (to May 2010)
// c2010 the lighter one of May 2010
// c2011 the grey redesign of June 2011, under the dark Google bar
// c2013 the same without the bar, as it stayed until October 2017
// c2017 the Material redesign of October 2017
// c2019 Google Material 2 (2019), and c2022 the same with the 2020 icon
function ugfCalEra() {
const l = String(layout || "2015");
if (l === "2022") {
return "c2022";
}
if (l === "2019") {
return "c2019";
}
if (l === "2018" || l === "2018M") {
return "c2017";
}
if (["2014", "2015", "2016", "2016C", "2017"].indexOf(l) > -1) {
return "c2013";
}
if (["2011", "2012", "2013", "2013L", "2015L", "2016L"].indexOf(l) > -1) {
return "c2011";
}
if (l === "2010" || l === "2010N") {
return "c2010";
}
return "c2006";
}
function ugfCalClassic(era) {
return era === "c2006" || era === "c2010" || era === "c2011" || era === "c2013";
}
// ---- dates ------------------------------------------------------------------
function ugfCalDay(d) {
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
}
function ugfCalAdd(d, n) {
return new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
}
function ugfCalSame(a, b) {
return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
}
function ugfCalWeekStart(d, first) {
const x = ugfCalDay(d);
const back = (x.getDay() - (first || 0) + 7) % 7;
return ugfCalAdd(x, -back);
}
// (functions rather than consts: this part of the script is reached before a
// const this far down would exist)
function ugfCalK() {
if (ugfCalK.c) {
return ugfCalK.c;
}
ugfCalK.c = {};
ugfCalK.c.months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
ugfCalK.c.days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
return ugfCalK.c;
}
function ugfCalMon(d, len) {
return ugfCalK().months[d.getMonth()].slice(0, len || 99);
}
function ugfCalDow(d, len) {
return ugfCalK().days[d.getDay()].slice(0, len || 99);
}
// "10am", "10:30am" (classic), "10:30" style is left to the caller
function ugfCalTime(d, style) {
let h = d.getHours();
const m = d.getMinutes();
const pm = h >= 12;
h = h % 12 || 12;
if (style === "gm2") {
return h + (m ? ":" + String(m).padStart(2, "0") : "") + (pm ? "pm" : "am");
}
if (style === "short") {
// month cells in the classic pages: 2:05p
return h + (m ? ":" + String(m).padStart(2, "0") : "") + (pm ? "p" : "");
}
return h + (m ? ":" + String(m).padStart(2, "0") : "") + (pm ? "pm" : "am");
}
function ugfCalHourLabel(h, era) {
const pm = h >= 12;
const hh = h % 12 || 12;
if (era === "c2019" || era === "c2022") {
return hh + " " + (pm ? "PM" : "AM");
}
return hh + (pm ? "pm" : "am");
}
// ---- where we are: Google's own addresses (/r/week/2026/9/23 and the like) ----
function ugfCalBase() {
const m = (window.location.pathname || "").match(/^\/calendar(\/u\/\d+)?/);
return (m ? m[0] : "/calendar") + "/r";
}
function ugfCalParseUrl() {
const p = window.location.pathname || "";
const m = p.match(/\/r\/(day|week|month|year|customday|agenda|schedule|customweek)(?:\/(\d{4})\/(\d{1,2})\/(\d{1,2}))?/);
const out = { view: "", date: ugfCalDay(new Date()) };
if (m) {
out.view = { day: "day", week: "week", month: "month", year: "month", customday: "4day",
customweek: "week", agenda: "agenda", schedule: "agenda" }[m[1]];
if (m[2]) {
out.date = new Date(parseInt(m[2], 10), parseInt(m[3], 10) - 1, parseInt(m[4], 10));
}
}
return out;
}
function ugfCalUrl(view, d) {
const name = { day: "day", week: "week", month: "month", "4day": "customday", agenda: "agenda" }[view] || "week";
return ugfCalBase() + "/" + name + "/" + d.getFullYear() + "/" + (d.getMonth() + 1) + "/" + d.getDate();
}
// the days a view covers
function ugfCalRange(view, d, first) {
if (view === "day") {
return { from: ugfCalDay(d), days: 1 };
}
if (view === "4day") {
return { from: ugfCalDay(d), days: 4 };
}
if (view === "month") {
const a = ugfCalWeekStart(new Date(d.getFullYear(), d.getMonth(), 1), first);
const last = new Date(d.getFullYear(), d.getMonth() + 1, 0);
const b = ugfCalAdd(ugfCalWeekStart(last, first), 7);
return { from: a, days: Math.round((b - a) / 864e5) };
}
if (view === "agenda") {
return { from: ugfCalDay(d), days: 30 };
}
return { from: ugfCalWeekStart(d, first), days: 7 };
}
function ugfCalStep(view, d, dir) {
if (view === "day") {
return ugfCalAdd(d, dir);
}
if (view === "4day") {
return ugfCalAdd(d, 4 * dir);
}
if (view === "month") {
return new Date(d.getFullYear(), d.getMonth() + dir, 1);
}
if (view === "agenda") {
return ugfCalAdd(d, 30 * dir);
}
return ugfCalAdd(d, 7 * dir);
}
// ---- colours ----------------------------------------------------------------
// Events arrive in today's colours; each period drew them from its own set, so
// every colour is matched to the nearest one of the period's.
function ugfCalClassicColors() {
return ugfCalClassicColors.c || (ugfCalClassicColors.c = [
["#A32929", "#D96666"], ["#B1365F", "#E67399"], ["#7A367A", "#B373B3"], ["#5229A3", "#8C66D9"],
["#29527A", "#668CB3"], ["#2952A3", "#668CD9"], ["#1B887A", "#59BFB3"], ["#28754E", "#65AD89"],
["#0D7813", "#4CB052"], ["#528800", "#8CBF40"], ["#88880E", "#BFBF4D"], ["#AB8B00", "#E0C240"],
["#BE6D00", "#F2A640"], ["#B1440E", "#E6804D"], ["#865A5A", "#BE9494"], ["#705770", "#A992A9"],
["#4E5D6C", "#8997A5"], ["#5A6986", "#94A2BE"], ["#4A716C", "#85AAA5"], ["#6E6E41", "#A7A77D"],
["#8D6F47", "#C4A883"]
]);
}
// the calendar colours of June 2011 on (the swatches in its colour picker)
function ugfCal2011Colors() {
return ugfCal2011Colors.c || (ugfCal2011Colors.c = ["#ac725e", "#d06b64", "#f83a22", "#fa573c", "#ff7537", "#ffad46", "#42d692", "#16a765",
"#7bd148", "#b3dc6c", "#fbe983", "#fad165", "#92e1c0", "#9fe1e7", "#9fc6e7", "#4986e7", "#9a9cff",
"#b99aff", "#c2c2c2", "#cabdbf", "#cca6ac", "#f691b2", "#cd74e6", "#a47ae2"]);
}
function ugfCalRgb(hex) {
const m = String(hex || "").replace("#", "").match(/^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i);
if (!m) {
const rgb = String(hex || "").match(/(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);
return rgb ? [parseInt(rgb[1], 10), parseInt(rgb[2], 10), parseInt(rgb[3], 10)] : [3, 155, 229];
}
return [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)];
}
function ugfCalNear(hex, list, pick) {
const a = ugfCalRgb(hex);
let best = 0;
let bd = 1e9;
list.forEach(function(c, i) {
const b = ugfCalRgb(pick ? pick(c) : c);
// weighted by how the eye sees the channels
const d = 2 * Math.pow(a[0] - b[0], 2) + 4 * Math.pow(a[1] - b[1], 2) + 3 * Math.pow(a[2] - b[2], 2);
if (d < bd) {
bd = d;
best = i;
}
});
return list[best];
}
// { bg, fg, border, text } for an event in this period
// ---- your Calendar settings in Gplex: display density, the colour set of the
// Material pages and the colours you give your calendars (kept by Gplex, like the
// rest of its settings)
function ugfCalPrefs() {
if (!ugfCalPrefs.p) {
const get = function(k, d) {
try {
return typeof GM_getValue === "function" ? GM_getValue(k, d) : d;
} catch (e) {
return d;
}
};
let colors = {};
try {
colors = JSON.parse(get("UGF_CAL_COLORS", "{}")) || {};
} catch (e) {}
ugfCalPrefs.p = { density: get("UGF_CAL_DENSITY", ""), colorset: get("UGF_CAL_COLORSET", "modern"), colors: colors };
}
return ugfCalPrefs.p;
}
function ugfCalSetPref(k, v) {
const p = ugfCalPrefs();
p[k] = v;
try {
if (typeof GM_setValue === "function") {
GM_setValue({ density: "UGF_CAL_DENSITY", colorset: "UGF_CAL_COLORSET", colors: "UGF_CAL_COLORS" }[k], k === "colors" ? JSON.stringify(v) : v);
}
} catch (e) {}
}
// a calendar's colour: yours if you picked one here, else Google's
function ugfCalColorFor(cal, color) {
const c = ugfCalPrefs().colors;
return (cal && c[cal]) || color;
}
// the calendar colours of the Material pages, by the names Google gives them
function ugfCalMaterialColors() {
return [["#ad1457", "Radicchio"], ["#d81b60", "Cherry blossom"], ["#d50000", "Tomato"], ["#e67c73", "Flamingo"], ["#f4511e", "Tangerine"], ["#ef6c00", "Pumpkin"],
["#f09300", "Mango"], ["#f6bf26", "Banana"], ["#e4c441", "Citron"], ["#c0ca33", "Avocado"], ["#7cb342", "Pistachio"], ["#33b679", "Sage"],
["#0b8043", "Basil"], ["#009688", "Eucalyptus"], ["#039be5", "Peacock"], ["#4285f4", "Cobalt"], ["#3f51b5", "Blueberry"], ["#7986cb", "Lavender"],
["#b39ddb", "Wisteria"], ["#9e69af", "Amethyst"], ["#8e24aa", "Grape"], ["#795548", "Cocoa"], ["#616161", "Graphite"], ["#a79b8e", "Birch"]];
}
function ugfCalPaint(hex, era) {
if (era === "c2006" || era === "c2010") {
const p = ugfCalNear(hex, ugfCalClassicColors(), function(c) {
return c[1];
});
return { dark: p[0], light: p[1], text: "#fff" };
}
if (era === "c2011" || era === "c2013") {
const c = ugfCalNear(hex, ugfCal2011Colors());
const rgb = ugfCalRgb(c);
const lum = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2];
return { dark: c, light: c, text: lum > 170 ? "#1d1d1d" : "#fff" };
}
const rgb = ugfCalRgb(hex);
// the "Classic" colour set of 2018 on: the colour paled, with black writing
if (ugfCalPrefs().colorset === "classic") {
const pale = rgb.map(function(v) {
return Math.round(v + (255 - v) * 0.55);
});
return { dark: "rgb(" + rgb.join(",") + ")", light: "rgb(" + pale.join(",") + ")", text: "#202124" };
}
return { dark: "rgb(" + rgb.join(",") + ")", light: "rgb(" + rgb.join(",") + ")", text: "#fff" };
}
// ---- your events --------------------------------------------------------------
// [{ id, title, start, end, allDay, color, cal, where }] and [{ id, name, color, mine, on }]
// Read out of Google's page by ugfCalHarvest; kept per day so paging back and forth
// does not wait on Google again.
function ugfCalS() {
return ugfCalS.s || (ugfCalS.s = { events: {}, calendars: [], days: {} });
}
function ugfCalKey(d) {
return d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate();
}
function ugfCalPut(list, from, days) {
for (let i = 0; i < days; i++) {
ugfCalS().days[ugfCalKey(ugfCalAdd(from, i))] = true;
}
// what Google showed for these days replaces what we had for them; an event
// just made or changed here stays until Google shows it too (or a minute has
// gone by), and one just deleted here stays away as long
const gone = ugfCalS().gone || {};
const kept = {};
list = list.filter(function(x) {
return !(x.eid && gone[x.eid] && Date.now() - gone[x.eid] < 60000);
});
Object.keys(ugfCalS().events).forEach(function(id) {
const ev = ugfCalS().events[id];
if (ev.end > from && ev.start < ugfCalAdd(from, days)) {
if (ev.pending && Date.now() - ev.pending < 60000 && !list.some(function(x) {
return x.title === ev.title && x.start.getTime() === ev.start.getTime() && (!ev.eid || x.eid === ev.eid);
})) {
if (ev.eid) {
kept[ev.eid] = true;
}
return;
}
delete ugfCalS().events[id];
}
});
list.forEach(function(ev) {
if (!(ev.eid && kept[ev.eid])) {
ugfCalS().events[ev.id] = ev;
}
});
}
function ugfCalHave(from, days) {
for (let i = 0; i < days; i++) {
if (!ugfCalS().days[ugfCalKey(ugfCalAdd(from, i))]) {
return false;
}
}
return true;
}
function ugfCalEventsIn(from, days) {
const to = ugfCalAdd(from, days);
const offCal = {};
ugfCalS().calendars.forEach(function(c) {
if (c.on === false) {
offCal[c.name] = true;
}
});
return Object.keys(ugfCalS().events).map(function(id) {
return ugfCalS().events[id];
}).filter(function(ev) {
return ev.end > from && ev.start < to && !offCal[ev.cal];
}).sort(function(a, b) {
return (b.allDay - a.allDay) || (a.start - b.start) || ((b.end - b.start) - (a.end - a.start)) || String(a.title).localeCompare(b.title);
});
}
// ---- the page -----------------------------------------------------------------
function ugfCalEsc(s) {
return String(s === undefined || s === null ? "" : s).replace(/[&<>"']/g, function(c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
function ugfCalIcon(n, size) {
const A = ugfCalArt();
let svg = A.mi[n] || "";
if (size) {
svg = svg.replace(/(]*?)\s(width|height)="\d+"/g, "$1").replace("' + svg + "";
}
// the Google logo in the 2011-2017 header: the one Gplex's results pages show
function ugfCalHeadLogo() {
const M = ugfMapsArt();
const l = String(layout || "");
if (l === "2011" || l === "2012") {
return ' ';
}
if (["2014", "2015", "2015L"].indexOf(l) > -1) {
return ' ';
}
// the new logo of September 2015 (layout 2018 is "2017-2018")
if (["2016", "2016C", "2016L", "2017", "2018", "2018M", "2019", "2022"].indexOf(l) > -1) {
return ' ';
}
return ' ';
}
// the tab icon: the small blue "31" (2006), the flat "31" (2011), the blue one
// with today's date on it (2014 on) and the four-colour one of late 2020
function ugfCalFaviconFor(era) {
const A = ugfCalArt();
const d = new Date().getDate();
if (era === "c2022") {
return A.fav2020[d - 1];
}
if (era === "c2013" || era === "c2017" || era === "c2019") {
return A.fav2014[d - 1];
}
if (era === "c2011") {
return A.fav2011;
}
return A.fav2006;
}
function ugfCalSetFavicon(era) {
let href = ugfCalFaviconFor(era);
ugfApplyFavicon(href);
// Google puts its own back, and swaps in its own now and then (the 2026 one)
ugfKeepFavicon(function() {
return href;
});
// the date on it moves on with the day, and so does the one in the header
let day = new Date().getDate();
setInterval(function() {
if (new Date().getDate() === day) {
return;
}
day = new Date().getDate();
href = ugfCalFaviconFor(era);
ugfApplyFavicon(href);
document.querySelectorAll("#ugf-cal img.datelogo").forEach(function(img) {
img.src = ugfCalDateIcon(era);
});
}, 60000);
}
// the logo in the Material header: Google's icon with today's date on it
function ugfCalDateIcon(era) {
const d = new Date().getDate();
if (era === "c2022") {
return "https://ssl.gstatic.com/calendar/images/dynamiclogo_2020q4/calendar_" + d + "_2x.png";
}
return "https://ssl.gstatic.com/calendar/images/dynamiclogo/2x/cal_" + String(d).padStart(2, "0") + "_v2.png";
}
// who is signed in, for the bars and the account menu
function ugfCalWho() {
const id = ugfGmailIdentity();
return { name: id.name || "", first: id.first || "", email: id.email || "", photo: id.photo || "" };
}
// ---- the Google bar per period (Calendar's own, which differs from Search's)
function ugfCalGbar(era) {
const esc = ugfCalEsc;
const who = ugfCalWho();
const l = String(layout || "");
if (era === "c2006" || era === "c2010") {
const apps = [["Gmail", "https://mail.google.com/"], ["Calendar", ""], ["Documents", "https://docs.google.com/"],
["Photos", "https://photos.google.com/"], ["Reader", "https://www.google.com/reader/"], ["Web", "https://www.google.com/"]];
let left = "";
apps.forEach(function(a) {
left += a[1] ? '' + esc(a[0]) + " " : "" + esc(a[0]) + " ";
});
left += 'more ▼ ';
// before 2007 there was no Google bar: just the account links on the right
if (["1997", "1998", "1999", "2000", "2001", "2002", "2003", "2005", "2006"].indexOf(l) > -1) {
left = "";
}
const right = (who.email || who.name ? '' + esc(who.email || who.name) + " | " : "") +
'Settings | ' +
'Help | ' +
(who.email || who.name ? 'Sign out ' : 'Sign in ');
return '' + left + '
' + right + "
";
}
// late 2012 to 2013: the +You bar; 2014 on had none
if (era !== "c2011") {
return "";
}
// June 2011 on: the dark bar
const late = l === "2013" || l === "2014" || l === "2015";
const apps = [["Search", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Maps", "https://www.google.com/maps"],
["Play", "https://play.google.com/"], ["YouTube", "https://www.youtube.com/"], ["News", "https://news.google.com/"],
["Gmail", "https://mail.google.com/"], [ugfDocsLabel(), "https://docs.google.com/document/"], ["Drive", "https://drive.google.com/"], ["Calendar", ""]].filter(ugfDvGbarKeep);
let links = late ? '+' + esc(ugfGmailPlusName()) + " " : "";
apps.forEach(function(a) {
links += a[1] ? '' + esc(a[0]) + " " : '' + esc(a[0]) + " ";
});
links += 'More ▾ ';
const right = late ? ""
: (who.first || who.email ? '' + esc(who.first || who.email) + " " : 'Sign in ') +
'' + ugfCalIcon("settings", 16) + " ";
return '' + links + '
' + right + "
";
}
// the account corner of the 2012-2017 header: +Name, count, Share, photo (2012-2014);
// app grid, bell, round photo (2015-2017)
function ugfCalAccount(era) {
const esc = ugfCalEsc;
const l = String(layout || "");
const who = ugfCalWho();
if (!who.name && !who.email) {
return 'Sign in ';
}
if (era === "c2011" && l !== "2013") {
return ""; // the name is on the dark bar
}
if (l === "2013" || l === "2014") {
return '';
}
return '";
}
// ---- reading your events out of Google's page ----------------------------------
// Google's Calendar, hidden underneath, is kept on the same days as Gplex's; what it
// draws is read back. Each event Google draws carries its id and a line of text
// for screen readers with everything about it ("10am to 11am, Title, Calendar,
// Location, September 23, 2026"), which is what this goes by rather than anything
// Google styles differently from one build to the next.
function ugfCalGoogleDriving() {
return !!ugfCalGoogleDriving.on;
}
// Move Google's own Calendar to a view and day, through its own address handling
function ugfCalDrive(view, d) {
const want = ugfCalUrl(view, d);
if ((window.location.pathname || "") !== want) {
try {
history.replaceState(history.state, "", want);
} catch (e) {}
}
ugfCalGoogleDriving.on = true;
try {
const w = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
w.dispatchEvent(new PopStateEvent("popstate", { state: null }));
} catch (e) {}
ugfCalGoogleDriving.on = false;
}
// the months Calendar spells out in its screen-reader text
function ugfCalMonthNo(name) {
const i = ugfCalK().months.findIndex(function(m) {
return m.toLowerCase().indexOf(String(name).toLowerCase().slice(0, 3)) === 0;
});
return i;
}
// "10am", "10:30pm", "22:30", "noon"
function ugfCalParseClock(t, base) {
t = String(t).trim().toLowerCase();
if (t === "noon") {
return new Date(base.getFullYear(), base.getMonth(), base.getDate(), 12, 0);
}
if (t === "midnight") {
return new Date(base.getFullYear(), base.getMonth(), base.getDate(), 0, 0);
}
const m = t.match(/(\d{1,2})(?::(\d{2}))?\s*(am|pm|a\.m\.|p\.m\.)?/);
if (!m) {
return null;
}
let h = parseInt(m[1], 10);
const mi = m[2] ? parseInt(m[2], 10) : 0;
if (m[3]) {
const pm = /p/.test(m[3]);
if (h === 12) {
h = pm ? 12 : 0;
} else if (pm) {
h += 12;
}
}
return new Date(base.getFullYear(), base.getMonth(), base.getDate(), h, mi);
}
// a date spelled out: "September 23, 2026" / "Wednesday, September 23" / "23 September 2026"
function ugfCalParseDateText(t, fallbackYear) {
let m = String(t).match(/([A-Z][a-z]+)\s+(\d{1,2}),?\s*(\d{4})?/);
if (m && ugfCalMonthNo(m[1]) > -1) {
return new Date(m[3] ? parseInt(m[3], 10) : fallbackYear, ugfCalMonthNo(m[1]), parseInt(m[2], 10));
}
m = String(t).match(/(\d{1,2})\s+([A-Z][a-z]+)\s*(\d{4})?/);
if (m && ugfCalMonthNo(m[2]) > -1) {
return new Date(m[3] ? parseInt(m[3], 10) : fallbackYear, ugfCalMonthNo(m[2]), parseInt(m[1], 10));
}
return null;
}
// one event from its screen-reader line
function ugfCalParseLabel(txt, dayHint) {
const parts = String(txt).split(/,\s+/);
const out = { allDay: false };
let i = 0;
// the time comes first: "10am to 11am" / "All day" / "10am to September 24, 2026 at 1am"
const first = parts[0] || "";
let startT = null;
let endT = null;
if (/^all day$/i.test(first)) {
out.allDay = true;
i = 1;
} else {
const tm = first.match(/^(.+?)\s+(?:to|–|-)\s+(.+)$/i);
if (tm && /\d/.test(tm[1])) {
startT = tm[1];
endT = tm[2];
i = 1;
}
}
out.title = (parts[i] || "").trim();
const rest = parts.slice(i + 1);
// the day it is on: the last part that reads as a date
let day = null;
for (let k = rest.length - 1; k >= 0 && !day; k--) {
day = ugfCalParseDateText(rest[k] + (rest[k + 1] && /^\d{4}$/.test(rest[k + 1]) ? " " + rest[k + 1] : ""), (dayHint || new Date()).getFullYear());
}
day = day || dayHint;
if (!day) {
return null;
}
rest.forEach(function(p) {
const pl = p.toLowerCase();
if (/^location:?\s*/.test(pl)) {
out.where = p.replace(/^location:?\s*/i, "");
} else if (/^calendar:?\s*/.test(pl)) {
out.cal = p.replace(/^calendar:?\s*/i, "");
}
});
// a stretch of days: "September 25, 2026 to September 27, 2026"
const span = String(txt).match(/([A-Z][a-z]+\s+\d{1,2},?\s*\d{4}|\d{1,2}\s+[A-Z][a-z]+\s+\d{4})\s+(?:to|–|-)\s+([A-Z][a-z]+\s+\d{1,2},?\s*\d{4}|\d{1,2}\s+[A-Z][a-z]+\s+\d{4})/);
const spanFrom = span ? ugfCalParseDateText(span[1], day.getFullYear()) : null;
const spanTo = span ? ugfCalParseDateText(span[2], day.getFullYear()) : null;
if (out.allDay && spanFrom && spanTo && spanTo >= spanFrom) {
out.start = ugfCalDay(spanFrom);
out.end = ugfCalAdd(ugfCalDay(spanTo), 1);
} else if (out.allDay) {
out.start = ugfCalDay(day);
out.end = ugfCalAdd(out.start, 1);
} else if (startT) {
out.start = ugfCalParseClock(startT, day) || ugfCalDay(day);
// an end on another day names that day
const endDay = /[A-Za-z]{3,}\s+\d/.test(endT) ? ugfCalParseDateText(endT, day.getFullYear()) : null;
out.end = ugfCalParseClock(endT.replace(/^.*\bat\s+/i, ""), endDay || day) || new Date(out.start.getTime() + 36e5);
if (out.end <= out.start) {
out.end = new Date(out.end.getTime() + 864e5);
}
} else {
out.start = ugfCalDay(day);
out.end = ugfCalAdd(out.start, 1);
out.allDay = true;
}
return out;
}
// Google marks each day column with a "datekey": either YYYYMMDD or its packed
// number ((year - 1970) << 9 | month << 5 | day)
function ugfCalDecodeKey(k) {
k = String(k || "");
let m = k.match(/^(\d{4})(\d{2})(\d{2})$/);
if (m) {
return new Date(+m[1], +m[2] - 1, +m[3]);
}
if (!/^\d{3,6}$/.test(k)) {
return null;
}
const n = parseInt(k, 10);
const y = 1970 + (n >> 9);
const mo = (n >> 5) & 15;
const d = n & 31;
if (y < 1990 || y > 2200 || mo < 1 || mo > 12 || d < 1) {
return null;
}
return new Date(y, mo - 1, d);
}
// the days Google's own page is showing right now (null when it cannot be told)
function ugfCalGoogleDays() {
const out = {};
let any = false;
document.querySelectorAll("[data-datekey]").forEach(function(el) {
if (ugfCalMine(el)) {
return;
}
const d = ugfCalDecodeKey(el.getAttribute("data-datekey"));
if (d) {
out[ugfCalKey(d)] = true;
any = true;
}
});
// the grid also carries the first and last day it covers
document.querySelectorAll("[data-start-date-key][data-end-date-key]").forEach(function(el) {
if (ugfCalMine(el)) {
return;
}
const a = ugfCalDecodeKey(el.getAttribute("data-start-date-key"));
const b = ugfCalDecodeKey(el.getAttribute("data-end-date-key"));
if (a && b && b >= a && b - a < 50 * 864e5) {
for (let d = a; d <= b; d = ugfCalAdd(d, 1)) {
out[ugfCalKey(d)] = true;
any = true;
}
}
});
return any ? out : null;
}
function ugfCalMine(el) {
return !!(el && el.closest && el.closest("#ugf-cal, [id^='ugf-']"));
}
// everything Google's page shows right now
function ugfCalHarvest() {
const out = [];
const seen = {};
const calNames = {};
ugfCalS().calendars.concat(ugfCalHarvestCals.last && ugfCalHarvestCals.last.length ? ugfCalHarvestCals.last : ugfCalHarvestCals()).forEach(function(c) {
calNames[String(c.name).toLowerCase()] = c.name;
});
document.querySelectorAll("[data-eventid]").forEach(function(el) {
if (ugfCalMine(el)) {
return;
}
const id = el.getAttribute("data-eventid");
// the screen-reader line: the hidden text inside the chip, else its label
let txt = "";
const sr = el.querySelector(".XuJrye, [role='heading'] ~ div, .ynRLnc");
if (sr && /\d/.test(sr.textContent || "")) {
txt = sr.textContent;
}
txt = txt || el.getAttribute("aria-label") || ugfMapsReadText(el) || el.textContent || "";
txt = txt.replace(/\s+/g, " ").trim();
// the day column it sits in gives the day when the text leaves it out
let hint = null;
const col = el.closest("[data-datekey], [data-date]");
if (col) {
hint = ugfCalDecodeKey(col.getAttribute("data-date") || col.getAttribute("data-datekey"));
}
const ev = ugfCalParseLabel(txt, hint);
if (!ev || !ev.title) {
return;
}
// which calendar, and where: the other parts of the line, past the
// answer ("Accepted") and the days
if (!ev.cal || !ev.where) {
const parts = txt.split(/,\s+/);
const ti = parts.indexOf(ev.title);
parts.slice(ti + 1).forEach(function(p) {
const pl = p.toLowerCase().trim();
if (!ev.cal && calNames[pl]) {
ev.cal = calNames[pl];
} else if (!ev.where && ev.cal && p.length > 1 && !/\d{4}|^\d|^(accepted|declined|tentative|maybe|needs rsvp|no location|organi[sz]er|busy|free|all day|invitation)/i.test(pl) &&
!ugfCalK().months.some(function(m) {
const w = pl.split(/\s/)[0];
return m.toLowerCase() === w || m.toLowerCase().slice(0, 3) === w;
}) && !/^(mon|tues|wednes|thurs|fri|satur|sun)day/i.test(pl)) {
ev.where = p.trim();
}
});
}
const key = id + "|" + ev.start.getTime();
if (seen[key]) {
return;
}
seen[key] = true;
// its colour: the chip's own background or border
const cs = window.getComputedStyle(el);
let color = cs.backgroundColor;
if (!color || /rgba\(0, 0, 0, 0\)|transparent/.test(color)) {
color = cs.borderColor || cs.color;
}
const inner = el.querySelector("[style*='background-color'], [style*='border-color']");
if ((!color || /rgba\(0, 0, 0, 0\)|transparent/.test(color)) && inner) {
color = inner.style.backgroundColor || inner.style.borderColor;
}
if (!color || /rgba\(0, 0, 0, 0\)|transparent/.test(color)) {
const v = (el.getAttribute("style") || "").match(/--[\w-]*colou?r[\w-]*:\s*([^;]+)/i);
if (v) {
color = v[1].trim();
}
}
ev.id = key;
ev.eid = id;
ev.color = color || "#039be5";
out.push(ev);
});
return out;
}
// the calendars in Google's side column (checkboxes with the calendar's colour)
function ugfCalHarvestCals() {
const out = [];
const seen = {};
document.querySelectorAll("[role='listitem'] input[type='checkbox'], [role='listitem'] [role='checkbox'], input[type='checkbox'][aria-label]").forEach(function(cb) {
if (ugfCalMine(cb)) {
return;
}
const li = cb.closest("[role='listitem']") || cb.parentElement;
const name = (cb.getAttribute("aria-label") || (li && li.textContent) || "").replace(/\s+/g, " ").trim();
if (!name || seen[name]) {
return;
}
seen[name] = true;
const list = cb.closest("[role='list']");
const listLabel = list ? (list.getAttribute("aria-label") || "") : "";
let color = "";
const sw = li ? li.querySelector("[style*='background-color'], [style*='border-color']") : null;
if (sw) {
color = sw.style.backgroundColor || sw.style.borderColor;
}
if (!color && li) {
const v = (li.outerHTML.match(/--[\w-]*colou?r[\w-]*:\s*([^;"]+)/i) || [])[1];
if (v) {
color = v.trim();
}
}
out.push({ name: name, color: color || "#039be5", mine: !/other/i.test(listLabel),
on: cb.checked !== undefined ? !!cb.checked : cb.getAttribute("aria-checked") !== "false" });
});
ugfCalHarvestCals.last = out;
return out;
}
// Test pages hand Gplex their events directly
function ugfCalMock() {
try {
const w = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
return w.__ugfCalMock || null;
} catch (e) {
return null;
}
}
// Bring the store up to the days of a view: Google's page is moved there and read
// once it has drawn them. cb(changed)
function ugfCalFetch(view, d, r, cb, quiet) {
if (ugfCalFetch.stuck === undefined) {
try {
ugfCalFetch.stuck = sessionStorage.getItem("ugfCalStuck") === "1";
} catch (e) {
ugfCalFetch.stuck = false;
}
}
const mock = ugfCalMock();
if (mock) {
const before = JSON.stringify(Object.keys(ugfCalS().events));
const evs = (mock.events || []).map(function(e) {
return { id: e.id, eid: e.id, title: e.title, start: new Date(e.start), end: new Date(e.end), allDay: !!e.allDay,
color: e.color || "#039be5", cal: e.cal || "", where: e.where || "" };
}).filter(function(e) {
return e.end > r.from && e.start < ugfCalAdd(r.from, r.days);
});
if (!ugfCalS().calendars.length) {
ugfCalS().calendars = (mock.calendars || []).map(function(c) {
return { name: c.name, color: c.color, mine: c.mine !== false, on: c.on !== false };
});
}
setTimeout(function() {
ugfCalPut(evs, r.from, r.days);
cb(before !== JSON.stringify(Object.keys(ugfCalS().events)));
}, quiet ? 0 : 150);
return;
}
// the first time, Google's page is already on the address's day
const boot = !ugfCalFetch.booted;
if (boot) {
ugfCalFetch.booted = true;
quiet = quiet || view === ugfCalParseUrl().view;
}
if (!quiet) {
// Google's page would not follow before: load the day properly instead
if (ugfCalFetch.stuck) {
window.location.assign(ugfCalUrl(view, d));
return;
}
ugfCalDrive(view, d);
}
const t0 = Date.now();
let checked = quiet;
let first = null;
let moved = false;
let last = "";
let steady = 0;
const iv = setInterval(function() {
const evs = ugfCalHarvest();
const sig = evs.map(function(e) {
return e.id;
}).join("|");
steady = sig === last ? steady + 1 : 0;
if (first === null) {
first = sig;
} else if (sig !== first) {
moved = true;
}
last = sig;
// Google should now be on the wanted days. Whether its day marks can be
// read at all is learnt the first time, when it is on the page's own day;
// if it can be seen that it has not followed, it does not take being moved
// like this, and the day is loaded properly instead
const shown = ugfCalGoogleDays();
const onIt = !!(shown && (shown[ugfCalKey(r.from)] || shown[ugfCalKey(d)]));
const late = Date.now() - t0 > 3000;
if (onIt && ugfCalFetch.trust === undefined) {
ugfCalFetch.trust = true;
} else if (late && ugfCalFetch.trust === undefined) {
ugfCalFetch.trust = false;
}
if (!checked && late) {
checked = true;
if (ugfCalFetch.trust && view !== "agenda" && !onIt) {
clearInterval(iv);
ugfCalFetch.stuck = true;
try {
sessionStorage.setItem("ugfCalStuck", "1");
} catch (e) {}
window.location.assign(ugfCalUrl(view, d));
return;
}
}
const ready = (boot ? !!shown || moved || late : quiet) || checked || (ugfCalFetch.trust ? onIt : ugfCalFetch.trust === false && moved);
if ((steady >= 3 && ready) || Date.now() - t0 > 8000) {
clearInterval(iv);
const before = JSON.stringify(ugfCalEventsIn(r.from, r.days).map(function(e) {
return e.id + e.title + e.start.getTime() + e.end.getTime();
}));
ugfCalPut(evs.filter(function(e) {
return e.end > r.from && e.start < ugfCalAdd(r.from, r.days);
}), r.from, r.days);
const cals = ugfCalHarvestCals();
if (cals.length) {
const was = {};
ugfCalS().calendars.forEach(function(c) {
was[c.name] = c.on;
});
cals.forEach(function(c) {
if (was[c.name] === false) {
c.on = false;
}
});
ugfCalS().calendars = cals;
}
cb(before !== JSON.stringify(ugfCalEventsIn(r.from, r.days).map(function(e) {
return e.id + e.title + e.start.getTime() + e.end.getTime();
})));
}
}, 250);
}
// ---- making an event ------------------------------------------------------------
// Gplex has no way of its own to write to your calendar, so Google's own editor does
// it, out of sight: it is opened in a hidden frame with everything filled in through
// its address (the same fields Google's "add to calendar" links use), and its Save
// is pressed. cb(ok)
function ugfCalDateParam(d, allDay) {
const p = function(n) {
return String(n).padStart(2, "0");
};
return d.getFullYear() + p(d.getMonth() + 1) + p(d.getDate()) + (allDay ? "" : "T" + p(d.getHours()) + p(d.getMinutes()) + "00");
}
function ugfCalEditUrl(ev) {
let u = ugfCalBase() + "/eventedit?text=" + encodeURIComponent(ev.title || "") +
"&dates=" + ugfCalDateParam(ev.start, ev.allDay) + "/" + ugfCalDateParam(ev.end, ev.allDay);
if (ev.where) {
u += "&location=" + encodeURIComponent(ev.where);
}
if (ev.details) {
u += "&details=" + encodeURIComponent(ev.details);
}
if (ev.recur) {
u += "&recur=" + encodeURIComponent(ev.recur);
}
return u;
}
// the words Google's Save button carries in the languages Gplex speaks
function ugfCalSaveWords() {
return ["save", "guardar", "speichern", "enregistrer", "salva", "salvar", "opslaan", "zapisz", "сохранить", "保存", "저장", "kaydet", "spara", "gem", "lagre", "tallenna", "uložit", "mentés", "salvează", "αποθήκευση", "שמירה", "حفظ", "simpan", "lưu", "บันทึก"];
}
function ugfCalSeen(el) {
if (!el || !el.getBoundingClientRect) {
return false;
}
const r = el.getBoundingClientRect();
const cs = el.ownerDocument.defaultView.getComputedStyle(el);
return r.width > 0 && r.height > 0 && cs.visibility !== "hidden" && cs.display !== "none";
}
function ugfCalCreate(ev, cb) {
const url = ugfCalEditUrl(ev);
const old = document.getElementById("ugf-cal-saver");
if (old) {
old.remove();
}
const fr = document.createElement("iframe");
fr.id = "ugf-cal-saver";
fr.name = "ugf-cal-saver";
fr.setAttribute("aria-hidden", "true");
fr.setAttribute("tabindex", "-1");
fr.style.cssText = "position:fixed;left:-12000px;top:0;width:1280px;height:900px;opacity:0;pointer-events:none;border:0;z-index:-1;";
fr.src = url;
document.body.appendChild(fr);
const t0 = Date.now();
let clickedAt = 0;
let clicks = 0;
let done = false;
const finish = function(ok) {
if (done) {
return;
}
done = true;
clearInterval(iv);
setTimeout(function() {
fr.remove();
}, ok ? 1500 : 0);
cb(ok);
};
const words = ugfCalSaveWords();
const iv = setInterval(function() {
let doc = null;
let path = "";
try {
doc = fr.contentDocument;
path = fr.contentWindow.location.pathname || "";
} catch (e) {
finish(false);
return;
}
if (!doc || !doc.body) {
if (Date.now() - t0 > 30000) {
finish(false);
}
return;
}
// saved: Google has left its editor
if (clickedAt && !/\/eventedit/.test(path)) {
finish(true);
return;
}
// the title, if the address did not put it there
const titleIn = doc.querySelector("input[aria-label='Title'], input[placeholder='Add title']");
if (titleIn && ev.title && !titleIn.value) {
try {
const setter = Object.getOwnPropertyDescriptor(fr.contentWindow.HTMLInputElement.prototype, "value").set;
setter.call(titleIn, ev.title);
} catch (e) {
titleIn.value = ev.title;
}
titleIn.dispatchEvent(new fr.contentWindow.Event("input", { bubbles: true }));
titleIn.dispatchEvent(new fr.contentWindow.Event("change", { bubbles: true }));
return;
}
// Save (again after a while, in case the first press came too early)
if (!clickedAt || (Date.now() - clickedAt > 4000 && clicks < 3)) {
const btns = Array.prototype.slice.call(doc.querySelectorAll("button, [role='button']")).filter(function(b) {
const t = String(b.getAttribute("aria-label") || b.textContent || "").replace(/\s+/g, " ").trim().toLowerCase();
return words.indexOf(t) > -1 && ugfCalSeen(b) && !b.disabled && b.getAttribute("aria-disabled") !== "true";
});
if (btns.length) {
btns[0].click();
clickedAt = Date.now();
clicks++;
return;
}
}
if (Date.now() - t0 > 35000) {
finish(false);
}
}, 400);
}
// ---- changing or deleting an event -------------------------------------------------
// The same way: Google's editor for the event is opened out of sight as soon as you
// choose to edit it, and read for what the bubble does not show (the description,
// how it repeats). When you save, only what you changed is typed into Google's
// fields and its Save pressed; deleting presses its Delete. Anything Google asks
// on the way (which events of a repeating one, whether to email the guests) is
// asked in the layout's own look through hooks.ask.
// hooks.ready(info) the editor is open: info.details, info.repeat, info.where
// hooks.ask(q, answer) q = { title, text, radios: [label], pick, buttons: [label] }
// answer(radioIndex, buttonIndex)
function ugfCalEditor(eid, hooks) {
hooks = hooks || {};
const fr = document.createElement("iframe");
fr.className = "ugf-cal-editor";
fr.setAttribute("aria-hidden", "true");
fr.setAttribute("tabindex", "-1");
fr.style.cssText = "position:fixed;left:-12000px;top:0;width:1280px;height:900px;opacity:0;pointer-events:none;border:0;z-index:-1;";
fr.src = ugfCalBase() + "/eventedit/" + eid;
document.body.appendChild(fr);
const self = { ready: false, busy: false, gone: false, info: null };
const t0 = Date.now();
let queued = null;
const W = function() {
return fr.contentWindow;
};
const D = function() {
try {
return fr.contentDocument;
} catch (e) {
return null;
}
};
const path = function() {
try {
return fr.contentWindow.location.pathname || "";
} catch (e) {
return "";
}
};
const one = function(sels) {
const doc = D();
if (!doc) {
return null;
}
for (let i = 0; i < sels.length; i++) {
const all = doc.querySelectorAll(sels[i]);
for (let j = 0; j < all.length; j++) {
if (ugfCalSeen(all[j])) {
return all[j];
}
}
}
return null;
};
const F = {
title: ["input[aria-label='Title']", "input[placeholder='Add title']"],
sd: ["input[aria-label='Start date']"],
st: ["input[aria-label='Start time']"],
et: ["input[aria-label='End time']"],
ed: ["input[aria-label='End date']"],
where: ["input[aria-label='Location']", "input[aria-label='Add location']", "input[placeholder='Add location']", "input[aria-label*='ocation']"],
desc: ["[contenteditable='true'][aria-label='Description']", "[contenteditable='true'][aria-label*='escription']", "textarea[aria-label*='escription']", "[contenteditable='true'][aria-multiline='true']"],
repeat: ["[aria-label^='Recurrence']", "[aria-label*='epeat'][role='combobox']", "[aria-label*='ecurrence'][role='combobox']"]
};
const allDayBox = function() {
const direct = one(["input[type='checkbox'][aria-label='All day']", "[role='checkbox'][aria-label='All day']"]);
if (direct) {
return direct;
}
const doc = D();
const lab = doc && Array.prototype.slice.call(doc.querySelectorAll("label")).filter(function(x) {
return /^all day$/i.test((x.textContent || "").trim());
})[0];
if (!lab) {
return null;
}
return lab.control || (lab.htmlFor && doc.getElementById(lab.htmlFor)) || lab.querySelector("input[type='checkbox']");
};
const isOn = function(box) {
return box ? (box.checked === true || box.getAttribute("aria-checked") === "true") : false;
};
// put text into one of Google's fields as typing would
const type = function(el, text, commit) {
const w = W();
try {
el.focus();
} catch (e) {}
let done = false;
try {
if (el.isContentEditable) {
const sel = w.getSelection();
sel.selectAllChildren(el);
done = text ? D().execCommand("insertText", false, text) : D().execCommand("delete", false, null);
} else {
el.select();
done = text ? D().execCommand("insertText", false, text) : D().execCommand("delete", false, null);
}
} catch (e) {
done = false;
}
const now = el.isContentEditable ? (el.innerText || "").replace(/\n$/, "") : el.value;
if (!done || now !== text) {
if (el.isContentEditable) {
el.textContent = text;
} else {
try {
Object.getOwnPropertyDescriptor(el instanceof w.HTMLTextAreaElement ? w.HTMLTextAreaElement.prototype : w.HTMLInputElement.prototype, "value").set.call(el, text);
} catch (e) {
el.value = text;
}
}
el.dispatchEvent(new w.Event("input", { bubbles: true }));
}
el.dispatchEvent(new w.Event("change", { bubbles: true }));
if (commit) {
["keydown", "keyup"].forEach(function(k) {
el.dispatchEvent(new w.KeyboardEvent(k, { key: "Enter", code: "Enter", keyCode: 13, which: 13, bubbles: true, cancelable: true }));
});
try {
el.blur();
} catch (e) {}
el.dispatchEvent(new w.FocusEvent("focusout", { bubbles: true }));
}
};
// dates and times written the way the field already writes them
const dateLike = function(was, d) {
const mon = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
if (/^\s*\d{4}-\d{1,2}-\d{1,2}\s*$/.test(was)) {
return d.getFullYear() + "-" + String(d.getMonth() + 1).padStart(2, "0") + "-" + String(d.getDate()).padStart(2, "0");
}
if (/^\s*\d{1,2}\/\d{1,2}\/\d{2,4}\s*$/.test(was)) {
return (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
}
return mon[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear();
};
const timeLike = function(was, d) {
const h = d.getHours();
const m = String(d.getMinutes()).padStart(2, "0");
if (was && !/[ap]\.?m/i.test(was) && /\d:\d\d/.test(was)) {
return String(h).padStart(was.trim().length > 4 ? 2 : 1, "0") + ":" + m;
}
const ap = h < 12 ? "am" : "pm";
const t = ((h + 11) % 12 + 1) + ":" + m;
if (/\s[AP]M/.test(was || "")) {
return t + " " + ap.toUpperCase();
}
if (/[AP]M/.test(was || "")) {
return t + ap.toUpperCase();
}
return t + (/\s[ap]m/.test(was || "") ? " " : "") + ap;
};
let finishCb = null;
let doneFlag = false;
const finish = function(ok, why) {
if (doneFlag) {
return;
}
doneFlag = true;
self.gone = true;
clearInterval(iv);
setTimeout(function() {
fr.remove();
}, ok ? 1500 : 0);
if (finishCb) {
finishCb(ok, why);
} else if (!ok && hooks.failed) {
hooks.failed(why);
}
};
// Google's questions, asked again in Gplex's own dialog
let asking = false;
let answeredCancel = false;
const dialogs = function() {
const doc = D();
if (!doc || asking) {
return false;
}
const dl = Array.prototype.slice.call(doc.querySelectorAll("[role='dialog'], [role='alertdialog']")).filter(function(x) {
return ugfCalSeen(x) && !x.hasAttribute("data-ugf-asked") && x.querySelector("button, [role='button']") &&
!x.querySelector("input[aria-label='Title'], [aria-label='Start date']");
}).pop();
if (!dl) {
return false;
}
dl.setAttribute("data-ugf-asked", "1");
const txt = function(x) {
return String((x && (x.innerText || x.textContent)) || "").replace(/\s+/g, " ").trim();
};
const head = dl.querySelector("[role='heading'], h1, h2, h3");
const radios = Array.prototype.slice.call(dl.querySelectorAll("[role='radio'], input[type='radio']")).filter(function(r) {
return r.tagName === "INPUT" || ugfCalSeen(r);
});
const rlabel = function(r) {
const lab = r.getAttribute("aria-label") || (r.labels && r.labels[0] && txt(r.labels[0])) ||
(r.id && txt(doc.querySelector("label[for='" + r.id + "']"))) || txt(r.closest("label")) || txt(r.parentElement);
return lab;
};
const buttons = Array.prototype.slice.call(dl.querySelectorAll("button, [role='button']")).filter(function(b) {
return ugfCalSeen(b) && txt(b) && !b.closest("[role='radiogroup']") && radios.indexOf(b) < 0;
});
if (!buttons.length) {
return false;
}
let body = txt(dl);
[head].concat(radios.map(function(r) {
return { innerText: rlabel(r) };
}), buttons).forEach(function(x) {
const t = txt(x);
if (t) {
body = body.replace(t, "");
}
});
const q = {
title: txt(head),
text: body.replace(/\s+/g, " ").trim(),
radios: radios.map(rlabel),
pick: Math.max(0, radios.findIndex(isOn)),
buttons: buttons.map(txt)
};
if (!hooks.ask) {
buttons[buttons.length - 1].click();
return true;
}
asking = true;
hooks.ask(q, function(ri, bi) {
asking = false;
if (radios[ri]) {
radios[ri].click();
}
const b = buttons[bi] || buttons[buttons.length - 1];
if (/^(cancel|back|keep editing|continue editing)$/i.test(txt(b))) {
answeredCancel = true;
}
setTimeout(function() {
b.click();
}, radios[ri] ? 150 : 0);
});
return true;
};
// saving or deleting: wait for Google to leave its editor
let pressedAt = 0;
let presses = 0;
let moreAt = 0;
let job = null;
const press = function() {
const doc = D();
if (job.kind === "save") {
const words = ugfCalSaveWords();
const b = Array.prototype.slice.call(doc.querySelectorAll("button, [role='button']")).filter(function(x) {
const t = String(x.getAttribute("aria-label") || x.textContent || "").replace(/\s+/g, " ").trim().toLowerCase();
return words.indexOf(t) > -1 && ugfCalSeen(x) && !x.disabled && x.getAttribute("aria-disabled") !== "true";
})[0];
if (b) {
b.click();
return true;
}
return false;
}
const del = one(["button[aria-label='Delete event']", "[role='button'][aria-label='Delete event']", "button[aria-label='Delete']", "[role='button'][aria-label='Delete']"]);
if (del) {
del.click();
return true;
}
const item = Array.prototype.slice.call(doc.querySelectorAll("[role='menuitem'], [role='option']")).filter(function(x) {
return ugfCalSeen(x) && /^delete( event)?$/i.test((x.textContent || "").replace(/\s+/g, " ").trim());
})[0];
if (item) {
item.click();
return true;
}
const more = one(["[aria-label='More actions']", "[aria-label='More options']", "[aria-label='Options']"]);
if (more && Date.now() - moreAt > 2000) {
moreAt = Date.now();
more.click();
}
return false;
};
const steps = [];
let stepAt = 0;
const iv = setInterval(function() {
const doc = D();
const p = path();
if (!doc || !doc.body) {
if (Date.now() - t0 > 30000) {
finish(false, "load");
}
return;
}
if (!self.ready) {
if (one(F.title)) {
self.ready = true;
const d = one(F.desc);
const r = one(F.repeat);
const w = one(F.where);
const dsc = d ? (d.isContentEditable ? d.innerText : d.value) : "";
self.info = {
details: String(dsc || "").replace(/\n$/, ""),
repeat: r ? String(r.textContent || r.value || "").replace(/\s+/g, " ").trim() : "",
where: w ? w.value : "",
allDay: isOn(allDayBox()),
canDelete: true
};
if (hooks.ready) {
hooks.ready(self.info);
}
if (queued) {
const q = queued;
queued = null;
q();
}
} else if (Date.now() - t0 > 30000) {
finish(false, "load");
}
return;
}
if (!job) {
return;
}
// typing, one field at a time
if (steps.length) {
if (Date.now() - stepAt > 250) {
stepAt = Date.now();
steps.shift()();
}
return;
}
if (pressedAt && !/\/eventedit/.test(p)) {
finish(true);
return;
}
if (dialogs() || asking) {
return;
}
if (answeredCancel) {
answeredCancel = false;
job = null;
pressedAt = 0;
presses = 0;
self.busy = false;
if (finishCb) {
const cb = finishCb;
finishCb = null;
cb(false, "cancel");
}
return;
}
if (!pressedAt || (Date.now() - pressedAt > 4000 && presses < 4)) {
if (press()) {
pressedAt = Date.now();
presses++;
}
}
if (Date.now() - job.at > 45000) {
finish(false, "stuck");
}
}, 200);
// ch: what changed { title, where, details, allDay, start, end } (only those present)
self.save = function(ch, cb) {
if (self.gone) {
cb(false, "gone");
return;
}
if (!self.ready) {
queued = function() {
self.save(ch, cb);
};
return;
}
self.busy = true;
finishCb = cb;
const put = function(key, val, commit) {
steps.push(function() {
const el = one(F[key]);
if (el) {
type(el, val(el), commit);
}
});
};
if (ch.title !== undefined) {
put("title", function() {
return ch.title;
}, false);
}
if (ch.allDay !== undefined) {
steps.push(function() {
const box = allDayBox();
if (box && isOn(box) !== ch.allDay) {
box.click();
}
});
}
if (ch.start) {
const ad = ch.allDay !== undefined ? ch.allDay : self.info.allDay;
const lastDay = ad ? ugfCalAdd(ugfCalDay(ch.end), -1) : ch.end;
put("sd", function(el) {
return dateLike(el.value, ch.start);
}, true);
if (!ad) {
put("st", function(el) {
return timeLike(el.value, ch.start);
}, true);
}
put("ed", function(el) {
return dateLike(el.value, lastDay);
}, true);
if (!ad) {
put("et", function(el) {
return timeLike(el.value, ch.end);
}, true);
}
}
if (ch.where !== undefined) {
put("where", function() {
return ch.where;
}, false);
}
if (ch.details !== undefined) {
put("desc", function() {
return ch.details;
}, false);
}
steps.push(function() {});
job = { kind: "save", at: Date.now() };
pressedAt = 0;
presses = 0;
};
self.del = function(cb) {
if (self.gone) {
cb(false, "gone");
return;
}
if (!self.ready) {
queued = function() {
self.del(cb);
};
return;
}
self.busy = true;
finishCb = cb;
job = { kind: "del", at: Date.now() };
pressedAt = 0;
presses = 0;
};
self.close = function() {
if (!self.busy && !self.gone) {
self.gone = true;
clearInterval(iv);
fr.remove();
}
};
self.url = fr.src;
return self;
}
// ---- views --------------------------------------------------------------------
// Lay a day's timed events out side by side where they overlap, as Calendar does:
// each gets a column within its cluster of overlapping events.
function ugfCalColumns(evs) {
const out = [];
let cluster = [];
let clusterEnd = 0;
const flush = function() {
const cols = [];
cluster.forEach(function(o) {
let c = 0;
while (cols[c] && cols[c] > o.s) {
c++;
}
cols[c] = o.e;
o.col = c;
});
cluster.forEach(function(o) {
o.cols = cols.length;
out.push(o);
});
cluster = [];
};
evs.forEach(function(o) {
if (cluster.length && o.s >= clusterEnd) {
flush();
clusterEnd = 0;
}
cluster.push(o);
clusterEnd = Math.max(clusterEnd, o.e);
});
if (cluster.length) {
flush();
}
return out;
}
function ugfCalMain() {
const era = ugfCalEra();
const A = ugfCalArt();
const esc = ugfCalEsc;
const classic = ugfCalClassic(era);
const material = !classic;
const l = String(layout || "");
const url = ugfCalParseUrl();
const st = { view: url.view || "week", date: url.date, first: 0 };
console.log("[Gplex] Calendar: layout " + layout + " (" + era + ")" + (UGF_VERSION ? " - Gplex " + UGF_VERSION : ""));
const style = document.createElement("style");
style.id = "ugf-cal-styles";
style.textContent = ugfCalCss(era);
(document.head || document.documentElement).appendChild(style);
document.documentElement.setAttribute("gplex-cal", era);
ugfCalSetFavicon(era);
document.title = "Google Calendar";
const shell = document.createElement("div");
shell.id = "ugf-cal";
shell.setAttribute("era", era);
shell.setAttribute("layout", l);
// ---- the frame: bar, header, side column, toolbar
let head = "";
if (era === "c2006" || era === "c2010") {
const beta = ["2009", "2010", "2010N"].indexOf(l) === -1;
head = ugfCalGbar(era) +
'';
} else if (classic) {
head = ugfCalGbar(era) +
'";
} else {
head = '";
}
// the toolbar over the calendar (2006-2017; the Material pages have it in the header)
let bar = "";
const views = era === "c2006" ? [["day", "Day"], ["week", "Week"], ["month", "Month"], ["4day", "Next 4 Days"], ["agenda", "Agenda"]]
: [["day", "Day"], ["week", "Week"], ["month", "Month"], ["4day", "4 Days"], ["agenda", "Agenda"]];
const viewBtns = views.map(function(v) {
return '' + v[1] + " ";
}).join("");
if (era === "c2006") {
bar = '";
} else if (era === "c2010") {
bar = '";
} else if (classic) {
bar = '";
}
// the side column
let side = "";
if (era === "c2006") {
side = '';
} else if (era === "c2010") {
side = '';
} else if (classic) {
side = 'Calendar
';
} else if (era !== "c2017") {
side = ' Create ';
}
side += '
';
shell.innerHTML = trusted_policy.createHTML(head +
'' +
(era === "c2017" ? '' + ugfCalIcon("add", 24) + " " : "") +
'Loading...
');
document.body.appendChild(shell);
// ---- the view picker of the Material pages
const viewSel = shell.querySelector(".viewsel");
if (viewSel) {
viewSel.innerHTML = trusted_policy.createHTML(' ' + ugfCalIcon("arrow_drop_down", 20) + " " +
'");
viewSel.querySelector(".vs").addEventListener("click", function(ev) {
ev.preventDefault();
viewSel.classList.toggle("open");
});
document.addEventListener("click", function(ev) {
if (!viewSel.contains(ev.target)) {
viewSel.classList.remove("open");
}
});
}
const view = shell.querySelector("#ugf-cal-view");
const loading = shell.querySelector("#ugf-cal-loading");
// ---- titles
const rangeTitle = function() {
const r = ugfCalRange(st.view, st.date, st.first);
const a = r.from;
const b = ugfCalAdd(r.from, r.days - 1);
if (st.view === "month") {
return ugfCalMon(st.date) + " " + st.date.getFullYear();
}
if (st.view === "day") {
if (material) {
return ugfCalMon(a) + " " + a.getDate() + ", " + a.getFullYear();
}
return ugfCalDow(a) + ", " + ugfCalMon(a) + " " + a.getDate() + ", " + a.getFullYear();
}
if (material) {
// Material: the month (or months) the range falls in
if (a.getMonth() === b.getMonth()) {
return ugfCalMon(a) + " " + a.getFullYear();
}
if (a.getFullYear() === b.getFullYear()) {
return ugfCalMon(a, 3) + " – " + ugfCalMon(b, 3) + " " + b.getFullYear();
}
return ugfCalMon(a, 3) + " " + a.getFullYear() + " – " + ugfCalMon(b, 3) + " " + b.getFullYear();
}
if (era === "c2011" || era === "c2013") {
if (a.getMonth() === b.getMonth()) {
return ugfCalMon(a, 3) + " " + a.getDate() + " – " + b.getDate() + ", " + b.getFullYear();
}
return ugfCalMon(a, 3) + " " + a.getDate() + " – " + ugfCalMon(b, 3) + " " + b.getDate() + ", " + b.getFullYear();
}
if (a.getMonth() === b.getMonth()) {
return ugfCalMon(a) + " " + a.getDate() + " – " + b.getDate() + " " + b.getFullYear();
}
return ugfCalMon(a, 3) + " " + a.getDate() + " – " + ugfCalMon(b, 3) + " " + b.getDate() + " " + b.getFullYear();
};
const paintBar = function() {
shell.querySelectorAll(".title").forEach(function(t) {
t.textContent = rangeTitle();
});
shell.querySelectorAll("[data-view]").forEach(function(a) {
a.classList.toggle("on", a.getAttribute("data-view") === st.view);
});
const vs = shell.querySelector(".viewsel .vs span");
if (vs) {
vs.textContent = { day: "Day", week: "Week", month: "Month", agenda: "Schedule", "4day": "4 days" }[st.view];
}
document.title = material ? "Google Calendar - " + rangeTitle() : "Google Calendar";
};
// ---- the small month
let miniMonth = new Date(st.date.getFullYear(), st.date.getMonth(), 1);
const paintMini = function() {
const box = shell.querySelector("#ugf-cal-mini");
const r = ugfCalRange(st.view, st.date, st.first);
const a = ugfCalWeekStart(miniMonth, st.first);
const today = new Date();
const dows = [];
for (let i = 0; i < 7; i++) {
const d = ugfCalAdd(a, i);
dows.push(classic ? ugfCalDow(d, era === "c2006" || era === "c2010" ? 2 : 1).slice(0, era === "c2006" || era === "c2010" ? 2 : 1) : ugfCalDow(d, 1));
}
let h = '' + dows.map(function(x) {
return "" + esc(x) + " ";
}).join("") + " ";
for (let w = 0; w < 6; w++) {
h += "";
for (let i = 0; i < 7; i++) {
const d = ugfCalAdd(a, w * 7 + i);
const inView = d >= r.from && d < ugfCalAdd(r.from, r.days) && st.view !== "agenda";
const cls = [d.getMonth() !== miniMonth.getMonth() ? "out" : "", ugfCalSame(d, today) ? "today" : "",
inView ? "sel" : "", ugfCalSame(d, st.date) ? "cur" : ""].filter(Boolean).join(" ");
h += '' + d.getDate() + " ";
}
h += " ";
}
box.innerHTML = trusted_policy.createHTML(h + "
");
box.querySelectorAll("[data-mini]").forEach(function(x) {
x.addEventListener("click", function(ev) {
ev.preventDefault();
miniMonth = new Date(miniMonth.getFullYear(), miniMonth.getMonth() + parseInt(x.getAttribute("data-mini"), 10), 1);
paintMini();
});
});
box.querySelectorAll("td[data-d]").forEach(function(td) {
td.addEventListener("click", function() {
const p = td.getAttribute("data-d").split("-");
go(st.view === "agenda" ? "day" : st.view, new Date(+p[0], +p[1] - 1, +p[2]));
});
});
};
// ---- your calendars
const paintCals = function() {
const box = shell.querySelector("#ugf-cal-cals");
const cals = ugfCalS().calendars;
const mine = cals.filter(function(c) {
return c.mine !== false;
});
const other = cals.filter(function(c) {
return c.mine === false;
});
const item = function(c) {
const p = ugfCalPaint(ugfCalColorFor(c.name, c.color), era);
const off = c.on === false;
if (material) {
return '' + (off ? "" : ugfCalIcon("check", 14)) + ' ' + esc(c.name) + ' ' + ugfCalIcon("more_vert", 20) + " ";
}
if (era === "c2011" || era === "c2013") {
return '' + esc(c.name) + ' ▾ ';
}
// 2006-2011: the name on a bar of its colour
return '' + esc(c.name) + ' ▼ ';
};
let h = "";
const sect = function(title, list, foot, add) {
if (material) {
return '" + list.map(item).join("") + "
";
}
return '' + (era === "c2006" || era === "c2010" ? "▼" : '▾ ') + title + "
" +
(add ? '
' : "") +
'
' + list.map(item).join("") + '
' + foot + "
";
};
if (material) {
h = '";
}
h += sect(era === "c2006" ? "My Calendars" : "My calendars", mine, era === "c2006" || era === "c2010" ? 'Settings Create ' : 'Add | Settings ', false);
h += sect(era === "c2006" ? "Other Calendars" : "Other calendars", other, era === "c2006" || era === "c2010" ? 'Add ▼ Settings ' : 'Add | Settings ', true);
box.innerHTML = trusted_policy.createHTML(h);
box.querySelectorAll("[data-cm]").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
calListMenu(a, a.getAttribute("data-cm"));
});
});
box.querySelectorAll("a.cal").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
const name = a.getAttribute("data-cal");
const opt = ev.target.closest(".dd, .opt");
if (opt) {
ev.stopPropagation();
calMenu(opt, name);
return;
}
ugfCalS().calendars.forEach(function(c) {
if (c.name === name) {
c.on = c.on === false;
}
});
paintCals();
paintView();
});
});
};
// ---- the calendar itself
let bubble = null;
const closeBubble = function() {
if (bubble) {
bubble.remove();
bubble = null;
}
};
const evClass = function(ev) {
return ugfCalPaint(ugfCalColorFor(ev.cal, ev.color), era);
};
const timeText = function(ev) {
if (ev.allDay) {
return "";
}
return ugfCalTime(ev.start) + (material ? " – " : " – ") + ugfCalTime(ev.end);
};
const chip = function(ev, mode) {
// mode: "month" (a line in a month cell), "allday" (a bar), "timed" (a block in the day grid)
const p = evClass(ev);
const t = esc(ev.title || "(No title)");
if (mode === "timed") {
if (ev.end - ev.start < 45 * 6e4) {
// too short for two lines: the title and the time on one
return '' +
(material ? "" + t + " , " + esc(ugfCalTime(ev.start)) : esc(ugfCalTime(ev.start)) + " " + t) + "
";
}
if (era === "c2006" || era === "c2010") {
return '' +
'
' + esc(ugfCalTime(ev.start) + " – " + ugfCalTime(ev.end)) + "
" +
'
' + t + "
";
}
if (classic) {
return '' +
'
' + esc(ugfCalTime(ev.start) + " – " + ugfCalTime(ev.end)) + "
" + '
' + t + "
";
}
return '' +
'
' + t + '
' + esc(ugfCalTime(ev.start) + " – " + ugfCalTime(ev.end)) + "
";
}
if (mode === "allday" || ev.allDay || (ev.end - ev.start) >= 864e5) {
return '' + t + "
";
}
// a timed event in a month cell
if (material) {
return ' ' +
'' + esc(ugfCalTime(ev.start, "gm2")) + " " + t + "
";
}
return '' + esc(ugfCalTime(ev.start, "short")) + " " + t + "
";
};
// the day grid: day, week and 4 days
// the height of an hour, by display density (Comfortable, Cozy, Compact in 2011-2017;
// Responsive or Compact on the Material pages)
let HOUR = 42;
const setDensity = function() {
const d = ugfCalPrefs().density;
if (material) {
HOUR = d === "compact" ? 40 : 48;
} else if (era === "c2011" || era === "c2013") {
HOUR = d === "compact" ? 30 : (d === "cozy" ? 36 : 42);
} else {
HOUR = 42;
}
shell.classList.toggle("dens-cozy", !material && d === "cozy");
shell.classList.toggle("dens-compact", d === "compact");
};
setDensity();
let scrollKept = null;
const paintGrid = function(from, days) {
const today = new Date();
const evs = ugfCalEventsIn(from, days);
const allday = evs.filter(function(e) {
return e.allDay || (e.end - e.start) >= 864e5;
});
// the all-day row: bars that can run across days
const rows = [];
allday.forEach(function(e) {
const a = Math.max(0, Math.round((ugfCalDay(e.start) - from) / 864e5));
const endDay = e.allDay ? ugfCalAdd(ugfCalDay(e.end), 0) : ugfCalAdd(ugfCalDay(e.end), 1);
const b = Math.min(days, Math.max(a + 1, Math.round((endDay - from) / 864e5)));
let r = 0;
while (rows[r] && rows[r].some(function(x) {
return x.a < b && a < x.b;
})) {
r++;
}
(rows[r] = rows[r] || []).push({ a: a, b: b, e: e });
});
let h = '
';
for (let i = 0; i < days; i++) {
h += '
';
}
rows.forEach(function(r, ri) {
r.forEach(function(x) {
h += '
' + chip(x.e, "allday") + "
";
});
});
h += '
';
for (let hr = 0; hr < 24; hr++) {
h += '
' + (hr === 0 && material ? "" : ugfCalHourLabel(hr, era)) + "
";
}
h += '
';
for (let hr = 0; hr < 24; hr++) {
h += '
' + (classic ? '
' : "");
}
for (let i = 0; i < days; i++) {
const d = ugfCalAdd(from, i);
const next = ugfCalAdd(d, 1);
const isToday = ugfCalSame(d, today);
h += '
';
const timed = evs.filter(function(e) {
return !(e.allDay || (e.end - e.start) >= 864e5) && e.start < next && e.end > d;
}).map(function(e) {
const s = Math.max(0, (e.start - d) / 6e4);
const en = Math.min(1440, (e.end - d) / 6e4);
return { ev: e, s: s, e: Math.max(en, s + 15) };
});
ugfCalColumns(timed).forEach(function(o) {
const w = 100 / o.cols;
h += '
' + chip(o.ev, "timed") + "
";
});
if (isToday && !(era === "c2006" || era === "c2010")) {
const nowM = (today - d) / 6e4;
h += '
';
}
h += "
";
}
h += "
";
view.innerHTML = trusted_policy.createHTML(h);
const body = view.querySelector(".gbody");
const sw = body.offsetWidth - body.clientWidth;
view.querySelectorAll(".sbar").forEach(function(sb) {
sb.style.width = sw + "px";
});
body.scrollTop = scrollKept !== null ? scrollKept : 7 * HOUR - (material ? 10 : 4);
body.addEventListener("scroll", function() {
scrollKept = body.scrollTop;
});
// a click in an empty slot: a new event there
view.querySelectorAll(".col").forEach(function(col) {
col.addEventListener("click", function(ev) {
if (ev.target.closest(".ev")) {
return;
}
const r = col.getBoundingClientRect();
const mins = Math.floor((ev.clientY - r.top) / HOUR * 2) * 30;
const p = col.getAttribute("data-day").split("-");
const s = new Date(+p[0], +p[1] - 1, +p[2], 0, mins);
quickBubble(ev.clientX, ev.clientY, s, new Date(s.getTime() + 36e5), false);
});
});
};
const paintMonth = function() {
const r = ugfCalRange("month", st.date, st.first);
const weeks = r.days / 7;
const evs = ugfCalEventsIn(r.from, r.days);
const today = new Date();
let h = '';
for (let i = 0; i < 7; i++) {
const d = ugfCalAdd(r.from, i);
h += "
" + (material ? (era === "c2017" ? ugfCalDow(d, 3) : ugfCalDow(d, 3).toUpperCase()) : ugfCalDow(d, 3)) + "
";
}
h += "
";
// as many chips as the cell has room for, the way Google fits them
const cellH = ((view.clientHeight || 600) - 24) / weeks;
const per = Math.max(2, Math.floor((cellH - (material ? 26 : 20)) / (material ? 20 : 16)));
for (let w = 0; w < weeks; w++) {
h += '
';
for (let i = 0; i < 7; i++) {
const d = ugfCalAdd(r.from, w * 7 + i);
const next = ugfCalAdd(d, 1);
const list = evs.filter(function(e) {
return e.start < next && e.end > d;
});
const cls = [d.getMonth() !== st.date.getMonth() ? "out" : "", ugfCalSame(d, today) ? "today" : ""].filter(Boolean).join(" ");
let num = d.getDate();
if (d.getDate() === 1 && !material) {
num = ugfCalMon(d, 3) + " 1";
}
h += '
";
}
h += "
";
}
view.innerHTML = trusted_policy.createHTML(h + "
");
view.querySelectorAll(".mc").forEach(function(c) {
c.addEventListener("click", function(ev) {
if (ev.target.closest(".ev, a")) {
return;
}
const p = c.getAttribute("data-day").split("-");
const s = new Date(+p[0], +p[1] - 1, +p[2]);
quickBubble(ev.clientX, ev.clientY, s, ugfCalAdd(s, 1), true);
});
});
};
const paintAgenda = function() {
const from = ugfCalDay(st.date);
const evs = ugfCalEventsIn(from, 30);
const today = new Date();
let h = '';
let any = false;
for (let i = 0; i < 30; i++) {
const d = ugfCalAdd(from, i);
const next = ugfCalAdd(d, 1);
const list = evs.filter(function(e) {
return e.start < next && e.end > d;
});
if (!list.length) {
continue;
}
any = true;
h += '
' +
(material ? '
' + d.getDate() + ' ' + ugfCalMon(d, 3).toUpperCase() + ", " + ugfCalDow(d, 3).toUpperCase() + " "
: ugfCalDow(d, 3) + " " + ugfCalMon(d, 3) + " " + d.getDate()) + '
';
list.forEach(function(e) {
const p = evClass(e);
h += '
' + (e.allDay ? (material ? "All day" : "All day") : esc(ugfCalTime(e.start) + (material ? " – " + ugfCalTime(e.end) : ""))) + " " +
'' + esc(e.title || "(No title)") + "
";
});
h += "
";
}
if (!any) {
h += '
' + (material ? "Nothing planned" : "No events") + "
";
}
view.innerHTML = trusted_policy.createHTML(h + "
");
};
const paintView = function() {
closeBubble();
const r = ugfCalRange(st.view, st.date, st.first);
view.setAttribute("data-view", st.view);
if (st.view === "month") {
paintMonth();
} else if (st.view === "agenda") {
paintAgenda();
} else {
paintGrid(r.from, r.days);
}
view.querySelectorAll(".ev[data-id]").forEach(function(el) {
el.addEventListener("click", function(ev) {
ev.stopPropagation();
const e = ugfCalS().events[el.getAttribute("data-id")];
if (e) {
eventBubble(el, e);
}
});
});
view.querySelectorAll("a[data-day]").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
const p = a.getAttribute("data-day").split("-");
go("day", new Date(+p[0], +p[1] - 1, +p[2]));
});
});
};
// ---- bubbles: an event, and a new one
const placeBubble = function(b, x, y) {
shell.appendChild(b);
const w = b.offsetWidth;
const hh = b.offsetHeight;
let left = x - w / 2;
let top = y - hh - 14;
b.classList.remove("below");
if (top < 60) {
top = y + 14;
b.classList.add("below");
}
left = Math.max(8, Math.min(window.innerWidth - w - 8, left));
b.style.left = left + "px";
b.style.top = top + "px";
const tail = b.querySelector(".tail");
if (tail) {
tail.style.left = Math.max(14, Math.min(w - 30, x - left - 8)) + "px";
}
};
const whenText = function(e) {
const d = e.start;
if (e.allDay) {
const last = ugfCalAdd(ugfCalDay(e.end), -1);
return ugfCalDow(d, 3) + ", " + ugfCalMon(d, 3) + " " + d.getDate() + (ugfCalSame(d, last) ? "" : " – " + ugfCalDow(last, 3) + ", " + ugfCalMon(last, 3) + " " + last.getDate());
}
return ugfCalDow(d, 3) + ", " + ugfCalMon(d, 3) + " " + d.getDate() + ", " + ugfCalTime(e.start) + " – " + ugfCalTime(e.end);
};
const editUrl = function(e) {
return e.eid ? ugfCalBase() + "/eventedit/" + e.eid : ugfCalBase() + "/eventedit";
};
// events on calendars you only look at (holidays, others' calendars) cannot be changed
const canEdit = function(e) {
if (!e.eid || e.pending) {
return false;
}
const c = ugfCalS().calendars.filter(function(x) {
return x.name === e.cal;
})[0];
return !(c && c.mine === false);
};
const eventBubble = function(el, e) {
closeBubble();
const p = evClass(e);
const b = document.createElement("div");
b.className = "ugf-cal-bubble ev-b";
const ok = canEdit(e);
let h;
if (material) {
h = '" +
'' + esc(e.title || "(No title)") + "
" +
'
' + esc(whenText(e)) + "
" +
(e.where ? '' + ugfCalIcon("place", 20) + "
" + esc(e.where) + "
" : "") +
(e.cal ? '' + ugfCalIcon("event", 20) + "
" + esc(e.cal) + "
" : "");
} else {
h = '' + (classic && era !== "c2006" && era !== "c2010" ? "×" : ' ') + " " +
'' + esc(e.title || "(No title)") + "
" +
'' + esc(whenText(e)) + "
" +
(e.where ? '' + esc(e.where) + "
" : "") +
(e.cal ? 'Calendar: ' + esc(e.cal) + "
" : "") +
(ok ? '" : "") +
' ';
}
b.innerHTML = trusted_policy.createHTML(h);
const r = el.getBoundingClientRect();
placeBubble(b, r.left + Math.min(r.width / 2, 60), r.top + (material ? r.height / 2 : 0));
bubble = b;
b.querySelector(".x").addEventListener("click", function(ev) {
ev.preventDefault();
closeBubble();
});
if (ok) {
b.querySelector(".ed").addEventListener("click", function(ev) {
ev.preventDefault();
editPage({ edit: e, title: e.title, start: e.start, end: e.end, allDay: e.allDay, where: e.where });
});
b.querySelector(".dl").addEventListener("click", function(ev) {
ev.preventDefault();
closeBubble();
removeEvent(e, null);
});
}
};
const quickBubble = function(x, y, s, e, allDay) {
closeBubble();
const b = document.createElement("div");
b.className = "ugf-cal-bubble new-b";
const when = allDay ? ugfCalDow(s, 3) + ", " + ugfCalMon(s, 3) + " " + s.getDate()
: ugfCalDow(s, 3) + ", " + ugfCalMon(s, 3) + " " + s.getDate() + ", " + ugfCalTime(s) + " – " + ugfCalTime(e);
b.innerHTML = trusted_policy.createHTML(material
? '' + ugfCalIcon("close", 20) + " " +
' ' +
'' + esc(when) + "
" +
''
: '' + (era === "c2006" || era === "c2010" ? ' ' : "×") + " " +
'When: ' + esc(when) + "
" +
'What:
' +
'" +
' ');
placeBubble(b, x, y);
bubble = b;
const what = b.querySelector(".what");
what.focus();
// made through Google's own editor, out of sight (see ugfCalCreate)
const open = function() {
closeBubble();
saveNew({ title: what.value.trim(), start: s, end: e, allDay: allDay });
};
const more = function() {
editPage({ title: what.value.trim(), start: s, end: e, allDay: allDay });
};
b.querySelector(".save").addEventListener("click", function(ev) {
ev.preventDefault();
open();
});
b.querySelector(".more").addEventListener("click", function(ev) {
ev.preventDefault();
more();
});
what.addEventListener("keydown", function(ev) {
if (ev.key === "Enter") {
open();
} else if (ev.key === "Escape") {
closeBubble();
}
});
b.querySelector(".x").addEventListener("click", function(ev) {
ev.preventDefault();
closeBubble();
});
};
document.addEventListener("mousedown", function(ev) {
if (bubble && !bubble.contains(ev.target) && !ev.target.closest(".ev, .col, .mc")) {
closeBubble();
}
});
// ---- going places
const paint = function() {
paintBar();
paintMini();
paintCals();
paintView();
};
let loadSeq = 0;
const load = function() {
const seq = ++loadSeq;
const r = ugfCalRange(st.view, st.date, st.first);
const cached = ugfCalHave(r.from, r.days);
shell.classList.toggle("busy", !cached);
ugfCalFetch(st.view, st.date, r, function(ok) {
if (seq !== loadSeq) {
return;
}
shell.classList.remove("busy");
paintCals();
paintView();
});
};
const go = function(v, d, replace) {
st.view = v;
st.date = ugfCalDay(d);
miniMonth = new Date(st.date.getFullYear(), st.date.getMonth(), 1);
scrollKept = null;
try {
history[replace ? "replaceState" : "pushState"]({ ugfCal: 1 }, "", ugfCalUrl(st.view, st.date));
} catch (e) {}
paint();
load();
};
// ---- making events, here rather than in today's Calendar -------------------
// a notice over the calendar: yellow on the older pages, a dark toast on Material
let noteTimer = 0;
const note = function(html, stay) {
let n = shell.querySelector("#ugf-cal-note");
if (!n) {
n = document.createElement("div");
n.id = "ugf-cal-note";
shell.appendChild(n);
}
n.innerHTML = trusted_policy.createHTML(html);
n.style.display = html ? "" : "none";
clearTimeout(noteTimer);
if (html && !stay) {
noteTimer = setTimeout(function() {
n.style.display = "none";
}, 8000);
}
};
const saveNew = function(ev) {
const id = "new-" + Date.now();
const primary = ugfCalS().calendars.filter(function(c) {
return c.mine !== false;
})[0];
const made = { id: id, eid: "", title: ev.title || "(No title)", start: ev.start, end: ev.end, allDay: !!ev.allDay,
color: primary ? primary.color : "#039be5", cal: primary ? primary.name : "", where: ev.where || "", pending: Date.now() };
ugfCalS().events[id] = made;
paintView();
note(material ? "Saving…" : "Saving...", true);
ugfCalCreate(ev, function(ok) {
if (!ok) {
delete ugfCalS().events[id];
paintView();
note((material ? "Couldn't save the event. " : "Sorry, your event could not be saved. ") +
'' + (material ? "Open in Calendar" : "Try again in Google Calendar") + " ", true);
return;
}
note(material ? "Event saved" : "Your event was created.");
// Google's page under ours takes the new event in shortly
[1500, 5000, 12000].forEach(function(ms) {
setTimeout(function() {
ugfCalFetch(st.view, st.date, ugfCalRange(st.view, st.date, st.first), function(changed) {
if (changed) {
paintCals();
paintView();
}
}, true);
}, ms);
});
});
};
const refetch = function() {
[1500, 5000, 12000].forEach(function(ms) {
setTimeout(function() {
ugfCalFetch(st.view, st.date, ugfCalRange(st.view, st.date, st.first), function(changed) {
if (changed) {
paintCals();
paintView();
}
}, true);
}, ms);
});
};
// Google's questions on the way (which events of a repeating one, whether to
// email the guests), asked in the look of the period. answer(radio, button)
const ask = function(qn, answer) {
const old = shell.querySelector(".ugf-cal-askfence");
if (old) {
old.remove();
}
note("");
const fence = document.createElement("div");
fence.className = "ugf-cal-askfence";
const last = qn.buttons.length - 1;
fence.innerHTML = trusted_policy.createHTML('' +
(qn.title ? '
' + esc(qn.title) + "
" : "") +
(qn.text ? '
' + esc(qn.text) + "
" : "") +
(qn.radios.length ? '
' + qn.radios.map(function(r, i) {
return ' " + esc(r) + " ";
}).join("") + "
" : "") +
'
' + qn.buttons.map(function(b, i) {
return '' + esc(b) + " ";
}).join("") + "
");
shell.appendChild(fence);
const pick = function(bi) {
const r = fence.querySelector("input[type=radio]:checked");
fence.remove();
answer(r ? +r.value : -1, bi);
};
fence.querySelectorAll(".ab button").forEach(function(b) {
b.addEventListener("click", function() {
pick(+b.getAttribute("data-i"));
});
});
fence.addEventListener("keydown", function(ev) {
if (ev.key === "Escape") {
const c = qn.buttons.findIndex(function(b) {
return /cancel|back/i.test(b);
});
pick(c > -1 ? c : last);
}
ev.stopPropagation();
});
const pri = fence.querySelector(".ab .pri");
if (pri) {
pri.focus();
}
};
// saving changes to an event, shown at once and made in Google's editor
const saveEdit = function(e, ch, sess) {
const was = { title: e.title, start: e.start, end: e.end, allDay: e.allDay, where: e.where, pending: e.pending };
if (ch.title !== undefined) {
e.title = ch.title || "(No title)";
}
if (ch.where !== undefined) {
e.where = ch.where;
}
if (ch.start) {
e.start = ch.start;
e.end = ch.end;
}
if (ch.allDay !== undefined) {
e.allDay = ch.allDay;
}
e.pending = Date.now();
paintView();
note(material ? "Saving…" : "Saving...", true);
sess.save(ch, function(ok, why) {
if (!ok) {
Object.keys(was).forEach(function(k) {
e[k] = was[k];
});
paintView();
if (why === "cancel") {
note("");
sess.close();
return;
}
note((material ? "Couldn't save the event. " : "Sorry, your changes could not be saved. ") +
'' + (material ? "Open in Calendar" : "Try again in Google Calendar") + " ", true);
return;
}
note(material ? "Event saved" : "Your event was saved.");
refetch();
});
};
// deleting an event: gone at once, deleted in Google's editor
const removeEvent = function(e, sess) {
sess = sess || ugfCalEditor(e.eid, { ask: ask });
const gone = ugfCalS().gone = ugfCalS().gone || {};
const keep = {};
Object.keys(ugfCalS().events).forEach(function(id) {
if (ugfCalS().events[id].eid === e.eid) {
keep[id] = ugfCalS().events[id];
delete ugfCalS().events[id];
}
});
gone[e.eid] = Date.now();
paintView();
note(material ? "Deleting…" : "Deleting...", true);
sess.del(function(ok, why) {
if (!ok) {
delete gone[e.eid];
Object.keys(keep).forEach(function(id) {
ugfCalS().events[id] = keep[id];
});
paintView();
if (why === "cancel") {
note("");
sess.close();
return;
}
note((material ? "Couldn't delete the event. " : "Sorry, the event could not be deleted. ") +
'' + (material ? "Open in Calendar" : "Try again in Google Calendar") + " ", true);
return;
}
note(material ? "Event deleted" : "The event was deleted.");
gone[e.eid] = Date.now();
refetch();
});
};
// the event details page, as each period had it
const fmtDate = function(d) {
return material ? ugfCalMon(d, 3) + " " + d.getDate() + ", " + d.getFullYear() : (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
};
const fmtTime = function(d) {
return ugfCalTime(d, "gm2").replace(/^(\d+)(am|pm)$/, "$1:00$2");
};
const parseDate = function(t) {
t = String(t || "").trim();
let m = t.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/);
if (m) {
return new Date(+m[3] < 100 ? 2000 + +m[3] : +m[3], +m[1] - 1, +m[2]);
}
m = t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
if (m) {
return new Date(+m[1], +m[2] - 1, +m[3]);
}
return ugfCalParseDateText(t.replace(/^[A-Za-z]+,\s*/, ""), new Date().getFullYear());
};
const editPage = function(pre) {
closeBubble();
closeMenu();
note("");
const old = shell.querySelector("#ugf-cal-edit");
if (old) {
old.remove();
}
pre = pre || {};
const editing = pre.edit || null;
let s0 = pre.start;
if (!s0) {
s0 = new Date(st.date.getFullYear(), st.date.getMonth(), st.date.getDate(), new Date().getHours() + 1, 0);
}
const e0 = pre.end || new Date(s0.getTime() + 36e5);
const allDay = !!pre.allDay;
const primary = ugfCalS().calendars.filter(function(c) {
return c.mine !== false;
})[0];
const calName = editing && editing.cal ? editing.cal : primary ? primary.name : (ugfCalWho().name || ugfCalWho().email || "");
const dow = ugfCalDow(s0);
const reps = [["", material ? "Does not repeat" : "Does not repeat"], ["RRULE:FREQ=DAILY", "Daily"],
["RRULE:FREQ=WEEKLY;BYDAY=" + ["SU", "MO", "TU", "WE", "TH", "FR", "SA"][s0.getDay()], "Weekly on " + dow],
["RRULE:FREQ=MONTHLY", "Monthly on day " + s0.getDate()], ["RRULE:FREQ=YEARLY", "Annually on " + ugfCalMon(s0) + " " + s0.getDate()],
["RRULE:FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", "Every weekday (Monday to Friday)"]];
// an event being changed keeps how it repeats: Google's editor says what that is
const repSel = editing ? '' + (material ? "Loading…" : "Loading...") + " " :
'' + reps.map(function(r) {
return '' + esc(r[1]) + " ";
}).join("") + " ";
const whereVal = ' value="' + esc(pre.where || "") + '"';
const descAttr = editing ? ' disabled placeholder="' + (material ? "Loading…" : "Loading...") + '"' : "";
const when = ' ' +
'to ' +
' ' +
' ' +
' All day ";
const box = document.createElement("div");
box.id = "ugf-cal-edit";
box.className = "e-" + era;
let h = "";
if (era === "c2006" || era === "c2010") {
const btns = 'Save Cancel ' +
(editing ? 'Delete ' : "") + "
";
h = '' + btns +
'" + btns;
} else if (classic) {
h = '" +
'
' +
'' + when + 'Repeat: ' + repSel + "
" +
'Event details Find a time
' +
'";
} else {
h = '" +
'' + when + "
" +
'' + repSel + "
" +
'Event details Find a time
' +
'' + ugfCalIcon("place", 24) + '
" +
'' + ugfCalIcon("event", 24) + ' ' + esc(calName) + "
" +
'' + ugfCalIcon("subject", 24) + '
";
}
box.innerHTML = trusted_policy.createHTML(h);
shell.appendChild(box);
shell.classList.add("editing");
const q = function(c) {
return box.querySelector(c);
};
const sync = function() {
const on = q(".allday").checked;
box.querySelectorAll(".st, .et, .to").forEach(function(x) {
x.style.display = on ? "none" : "";
});
};
q(".allday").addEventListener("change", sync);
sync();
q(".title").focus();
// changing an event: Google's editor for it opens out of sight now
let sess = null;
let info = null;
if (editing) {
const whereIn = q(".where");
let whereTouched = false;
whereIn.addEventListener("input", function() {
whereTouched = true;
});
sess = ugfCalEditor(editing.eid, {
ready: function(i) {
info = i;
if (!box.isConnected) {
return;
}
const d = q(".desc");
d.disabled = false;
d.value = i.details || "";
d.placeholder = material ? "Add description" : "";
const rt = q(".reptxt");
if (rt) {
rt.textContent = i.repeat || "Does not repeat";
}
if (!whereTouched && i.where && !whereIn.value) {
whereIn.value = i.where;
}
},
failed: function() {
if (!box.isConnected) {
return;
}
note((material ? "Couldn't open the event. " : "Sorry, this event could not be opened. ") +
'' + (material ? "Open in Calendar" : "Try again in Google Calendar") + " ", true);
},
ask: ask
});
}
let handed = false;
const close = function() {
box.remove();
shell.classList.remove("editing");
note("");
if (sess && !handed) {
sess.close();
}
};
const save = function() {
const sd = parseDate(q(".sd").value);
const ed = parseDate(q(".ed").value) || sd;
const ad = q(".allday").checked;
if (!sd || !ed) {
note(material ? "Enter a valid date" : "Please enter a valid date.", false);
return;
}
let start;
let end;
if (ad) {
start = ugfCalDay(sd);
end = ugfCalAdd(ugfCalDay(ed), 1);
} else {
start = ugfCalParseClock(q(".st").value, sd);
end = ugfCalParseClock(q(".et").value, ed);
if (!start || !end) {
note(material ? "Enter a valid time" : "Please enter a valid time.", false);
return;
}
if (end <= start) {
end = new Date(start.getTime() + 36e5);
}
}
if (editing) {
// only what was changed goes to Google
const ch = {};
const title = q(".title").value.trim();
const where = q(".where").value.trim();
if (title !== (editing.title || "")) {
ch.title = title;
}
if (where !== (info && info.where !== undefined && info.where !== "" ? info.where : editing.where || "")) {
ch.where = where;
}
if (info && q(".desc").value !== (info.details || "")) {
ch.details = q(".desc").value;
}
if (ad !== !!editing.allDay) {
ch.allDay = ad;
}
if (ch.allDay !== undefined || start.getTime() !== editing.start.getTime() || end.getTime() !== editing.end.getTime()) {
ch.start = start;
ch.end = end;
}
handed = true;
close();
if (!Object.keys(ch).length) {
sess.close();
return;
}
saveEdit(editing, ch, sess);
return;
}
close();
saveNew({ title: q(".title").value.trim(), start: start, end: end, allDay: ad, where: q(".where").value.trim(),
details: q(".desc").value, recur: q(".rep").value });
};
box.querySelectorAll(".del").forEach(function(b) {
b.addEventListener("click", function(ev) {
ev.preventDefault();
handed = true;
close();
removeEvent(editing, sess);
});
});
box.querySelectorAll(".save").forEach(function(b) {
b.addEventListener("click", function(ev) {
ev.preventDefault();
save();
});
});
box.querySelectorAll(".cancel").forEach(function(b) {
b.addEventListener("click", function(ev) {
ev.preventDefault();
close();
});
});
box.addEventListener("keydown", function(ev) {
if (ev.key === "Escape") {
close();
} else if (ev.key === "Enter" && ev.target.tagName === "INPUT" && ev.target.type === "text") {
save();
}
ev.stopPropagation();
});
};
// ---- the drop-down menus: the gear, More, the calendar list's links and each
// calendar's own, in the look of the period
let menu = null;
let menuFrom = null;
const closeMenu = function() {
if (menu) {
menu.remove();
menu = null;
}
if (menuFrom) {
menuFrom.classList.remove("menuon");
menuFrom = null;
}
};
const openMenu = function(anchor, items, opts) {
const again = menuFrom === anchor;
closeMenu();
closeBubble();
if (again) {
return; // a second click on the button closes it
}
opts = opts || {};
menu = document.createElement("div");
menu.className = "ugf-cal-menu" + (opts.cls ? " " + opts.cls : "");
let h = "";
items.forEach(function(it, i) {
if (it.sep) {
h += '
';
} else if (it.head) {
h += '' + esc(it.head) + "
";
} else if (it.sw) {
h += '' + it.sw.map(function(c) {
const hex = typeof c === "string" ? c : c[0];
const name = typeof c === "string" ? "" : c[1];
const cur = it.cur && ugfCalRgb(it.cur).join() === ugfCalRgb(hex).join();
return '
' +
(cur ? ugfCalIcon("check", 14) : "") + " ";
}).join("") + "
";
} else {
h += '" +
(it.on !== undefined ? '' + (it.on ? "✓" : "") + " " : "") + "" + esc(it.t) + " " +
(it.key ? "" + esc(it.key) + " " : "") + " ";
}
});
menu.innerHTML = trusted_policy.createHTML(h);
shell.appendChild(menu);
menuFrom = anchor;
anchor.classList.add("menuon");
// under the button; kept on the screen
const r = anchor.getBoundingClientRect();
const mw = menu.offsetWidth;
const mh = menu.offsetHeight;
let x = opts.right ? r.right - mw : r.left;
let y = r.bottom + (material ? 4 : 1);
x = Math.max(4, Math.min(x, window.innerWidth - mw - 4));
if (y + mh > window.innerHeight - 4) {
y = Math.max(4, r.top - mh - 2);
}
menu.style.left = x + "px";
menu.style.top = y + "px";
menu.addEventListener("click", function(ev) {
const sw = ev.target.closest("[data-sw]");
const a = ev.target.closest("a.it");
if (sw) {
ev.preventDefault();
const it = items.filter(function(x) {
return x.sw;
})[0];
closeMenu();
it.fn(sw.getAttribute("data-sw"));
return;
}
if (!a) {
return;
}
const it = items[parseInt(a.getAttribute("data-i"), 10)];
if (it.fn) {
ev.preventDefault();
closeMenu();
it.fn();
} else if (it.href && !/^https?:/.test(it.href)) {
closeMenu();
} else {
closeMenu();
}
});
};
document.addEventListener("mousedown", function(ev) {
if (menu && !menu.contains(ev.target) && !(menuFrom && menuFrom.contains(ev.target))) {
closeMenu();
}
}, true);
window.addEventListener("resize", closeMenu);
shell.addEventListener("scroll", closeMenu, true);
const setDensityTo = function(d) {
ugfCalSetPref("density", d);
setDensity();
scrollKept = null;
paintView();
};
const B = ugfCalBase();
// the gear
const gearMenu = function(anchor) {
const d = ugfCalPrefs().density || (material ? "responsive" : "comfortable");
if (material) {
openMenu(anchor, [
{ t: "Settings", href: B + "/settings" },
{ t: "Trash", href: B + "/trash" },
{ t: "Density and color", fn: densityDialog },
{ t: "Print", fn: function() {
window.print();
} },
{ t: "Get add-ons", href: "https://workspace.google.com/marketplace?host=calendar" }
], { right: true });
return;
}
openMenu(anchor, [
{ head: "Display density:" },
{ t: "Comfortable", on: d === "comfortable", fn: function() {
setDensityTo("comfortable");
} },
{ t: "Cozy", on: d === "cozy", fn: function() {
setDensityTo("cozy");
} },
{ t: "Compact", on: d === "compact", fn: function() {
setDensityTo("compact");
} },
{ sep: true },
{ t: "Settings", href: B + "/settings" },
{ t: "Labs", href: B + "/settings" },
{ t: "Offline", href: B + "/settings" },
{ sep: true },
{ t: "Help", href: "https://support.google.com/calendar" }
], { right: true });
};
const moreMenu = function(anchor) {
openMenu(anchor, [
{ t: "Refresh", fn: function() {
ugfCalS().days = {};
load();
} },
{ t: "Print", fn: function() {
window.print();
} },
{ sep: true },
{ t: "Create new calendar", href: B + "/settings/createcalendar" },
{ t: "Import calendar", href: B + "/settings/export" },
{ t: "Export calendars", href: B + "/settings/export" }
], { right: true });
};
// the links under the calendar list
const calListMenu = function(anchor, what) {
if (what === "settings") {
window.location.href = B + "/settings";
} else if (what === "create") {
window.location.href = B + "/settings/createcalendar";
} else if (material) {
openMenu(anchor, [
{ t: "Subscribe to calendar", href: B + "/settings/addcalendar" },
{ t: "Create new calendar", href: B + "/settings/createcalendar" },
{ t: "Browse calendars of interest", href: B + "/settings/browsecalendars" },
{ t: "From URL", href: B + "/settings/addbyurl" },
{ t: "Import", href: B + "/settings/export" }
]);
} else {
openMenu(anchor, [
{ t: "Browse Interesting Calendars", href: B + "/settings/browsecalendars" },
{ t: "Add by URL", href: B + "/settings/addbyurl" },
{ t: "Import calendar", href: B + "/settings/export" }
]);
}
};
// each calendar's own menu: show only it, its settings, its colour
const calMenu = function(anchor, name) {
const cal = ugfCalS().calendars.filter(function(c) {
return c.name === name;
})[0];
if (!cal) {
return;
}
const only = function() {
ugfCalS().calendars.forEach(function(c) {
c.on = c.name === name;
});
paintCals();
paintView();
};
const pick = function(hex) {
const colors = Object.assign({}, ugfCalPrefs().colors);
colors[name] = hex;
ugfCalSetPref("colors", colors);
paintCals();
paintView();
};
const cur = ugfCalColorFor(name, cal.color);
if (material) {
openMenu(anchor, [
{ t: "Display this only", fn: only },
{ t: "Settings and sharing", href: B + "/settings" },
{ sep: true },
{ sw: ugfCalMaterialColors(), cur: cur, fn: pick, cls: "m24" }
], { cls: "calm" });
return;
}
// 2006-2010 calendars wear the light colour of each pair
const sw = era === "c2011" || era === "c2013" ? ugfCal2011Colors() : ugfCalClassicColors().map(function(c) {
return c[1];
});
openMenu(anchor, [
{ t: "Display only this calendar", fn: only },
{ sep: true },
{ t: "Calendar settings", href: B + "/settings" },
{ t: "Create event on this calendar", fn: function() {
editPage();
} },
{ t: "Share this calendar", href: B + "/settings" },
{ t: "Edit notifications", href: B + "/settings" },
{ sep: true },
{ sw: sw, cur: ugfCalPaint(cur, era).light, fn: pick, cls: era === "c2011" || era === "c2013" ? "k24" : "c21" }
], { cls: "calm" });
};
// Material: the Density and color box
const densityDialog = function() {
const pr = ugfCalPrefs();
const fence = document.createElement("div");
fence.className = "ugf-cal-dlgfence";
const radio = function(group, val, label, cur) {
return '" + esc(label) + " ";
};
fence.innerHTML = trusted_policy.createHTML('Density and color
' +
'
Color set
' + radio("cs", "modern", "Modern (with white text)", pr.colorset === "classic" ? "classic" : "modern") +
radio("cs", "classic", "Classic (with black text)", pr.colorset === "classic" ? "classic" : "modern") + "
" +
'
Density
' + radio("dn", "responsive", "Responsive to your screen", pr.density === "compact" ? "compact" : "responsive") +
radio("dn", "compact", "Compact", pr.density === "compact" ? "compact" : "responsive") + "
" +
'
');
shell.appendChild(fence);
const apply = function() {
const cs = fence.querySelector("input[name=cs]:checked").value;
const dn = fence.querySelector("input[name=dn]:checked").value;
ugfCalSetPref("colorset", cs);
ugfCalSetPref("density", dn === "compact" ? "compact" : "");
setDensity();
scrollKept = null;
paintCals();
paintView();
};
fence.querySelectorAll("input").forEach(function(i) {
i.addEventListener("change", apply);
});
const close = function(ev) {
if (ev) {
ev.preventDefault();
}
fence.remove();
};
fence.querySelector(".done").addEventListener("click", close);
fence.addEventListener("mousedown", function(ev) {
if (ev.target === fence) {
close();
}
});
};
shell.addEventListener("click", function(ev) {
const mb = ev.target.closest("[data-menu]");
if (mb && shell.contains(mb)) {
ev.preventDefault();
ev.stopPropagation();
if (mb.getAttribute("data-menu") === "gear") {
gearMenu(mb);
} else {
moreMenu(mb);
}
return;
}
}, true);
shell.addEventListener("click", function(ev) {
const a = ev.target.closest("[data-act], [data-view]");
if (!a || !shell.contains(a) || a.closest(".vmenu") && !a.getAttribute("data-view")) {
return;
}
const act = a.getAttribute("data-act");
const v = a.getAttribute("data-view");
if (v && a.closest("#ugf-cal-bar, .viewsel, #ugf-cal-head")) {
ev.preventDefault();
if (viewSel) {
viewSel.classList.remove("open");
}
go(v, st.date);
return;
}
if (!act) {
return;
}
ev.preventDefault();
if (act === "today") {
go(st.view, new Date());
} else if (act === "prev" || act === "next") {
go(st.view, ugfCalStep(st.view, st.date, act === "prev" ? -1 : 1));
} else if (act === "refresh") {
ugfCalS().days = {};
load();
} else if (act === "print") {
window.print();
} else if (act === "create") {
editPage();
} else if (act === "quick") {
const r0 = shell.querySelector("#ugf-cal-view").getBoundingClientRect();
const s = new Date();
s.setMinutes(0, 0, 0);
s.setHours(s.getHours() + 1);
quickBubble(r0.left + r0.width / 2, r0.top + 80, s, new Date(s.getTime() + 36e5), false);
} else if (act === "search") {
const q = window.prompt("Search");
if (q) {
window.location.href = ugfCalBase() + "/search?q=" + encodeURIComponent(q);
}
}
});
const search = shell.querySelector("#ugf-cal-search");
if (search) {
search.addEventListener("submit", function(ev) {
ev.preventDefault();
const q = search.querySelector(".q").value.trim();
if (q) {
window.location.href = ugfCalBase() + "/search?q=" + encodeURIComponent(q);
}
});
}
// the keyboard shortcuts Calendar has always had
document.addEventListener("keydown", function(ev) {
if (ev.ctrlKey || ev.metaKey || ev.altKey || /^(INPUT|TEXTAREA|SELECT)$/.test((ev.target && ev.target.tagName) || "") || (ev.target && ev.target.isContentEditable)) {
return;
}
const k = ev.key.toLowerCase();
const map = { d: "day", "1": "day", w: "week", "2": "week", m: "month", "3": "month", x: "4day", "4": "4day", a: "agenda", "5": "agenda" };
if (map[k]) {
go(map[k], st.date);
} else if (k === "t") {
go(st.view, new Date());
} else if (k === "j" || k === "n") {
go(st.view, ugfCalStep(st.view, st.date, 1));
} else if (k === "k" || k === "p") {
go(st.view, ugfCalStep(st.view, st.date, -1));
} else if (k === "c") {
editPage();
} else if (k === "escape") {
closeBubble();
closeMenu();
} else {
return;
}
ev.preventDefault();
ev.stopPropagation();
}, true);
window.addEventListener("popstate", function() {
if (ugfCalGoogleDriving()) {
return; // our own nudge to Google's page, not Back or Forward
}
const u = ugfCalParseUrl();
if (u.view) {
st.view = u.view;
st.date = u.date;
miniMonth = new Date(st.date.getFullYear(), st.date.getMonth(), 1);
paint();
load();
}
});
// the account menus and app grid, as on Gmail
const menuChrome = ugfMenusRounded() ? "m2018" : "m2013";
shell.querySelectorAll("#ugf-cal-account .pfpwrap, #ugf-cal-account .plusname, #ugf-cal-account .me, #ugf-cal-head .me").forEach(function(el) {
el.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
ugfGmailAccountMenu(el, menuChrome);
});
});
shell.querySelectorAll("#ugf-cal-account .appsg, #ugf-cal-head .apps").forEach(function(el) {
el.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
ugfGmailAppsMenu(el, menuChrome);
});
});
const burger = shell.querySelector(".burger");
if (burger) {
burger.addEventListener("click", function(ev) {
ev.preventDefault();
shell.classList.toggle("noside");
});
}
go(st.view, st.date, true);
// Google's page keeps changing under us (new events, other devices): look again now and then
setInterval(function() {
if (!document.hidden) {
ugfCalFetch(st.view, st.date, ugfCalRange(st.view, st.date, st.first), function(changed) {
if (changed) {
paintCals();
paintView();
}
}, true);
}
}, 30000);
}
// ---- how each period's Calendar looked -----------------------------------------
function ugfCalCss(era) {
const common = [
'html[gplex-cal] body > *:not(#ugf-cal):not(#ugf-cal-styles):not(#ugf-gmail-accmenu):not(#ugf-gmail-appsmenu):not(#ugf-gmail-accfence):not(script):not(style) { visibility: hidden !important; pointer-events: none !important; }',
'html[gplex-cal], html[gplex-cal] body { overflow: hidden !important; }',
'html[gplex-cal] #ugf-gmail-accfence { z-index: 2147483600 !important; }',
'html[gplex-cal] #ugf-gmail-accmenu, html[gplex-cal] #ugf-gmail-appsmenu { z-index: 2147483601 !important; text-align: left; }',
'html[gplex-cal] #ugf-gmail-accmenu a, html[gplex-cal] #ugf-gmail-appsmenu a { text-decoration: none; }',
ugfMapsMenuCss(),
'#ugf-cal { position: fixed; inset: 0; z-index: 2147483000; background: #fff; color: #000; font: 13px arial, sans-serif; display: flex; flex-direction: column; text-align: left; visibility: visible; }',
'#ugf-cal * { box-sizing: border-box; }',
'#ugf-cal a { color: #00c; cursor: pointer; }',
'#ugf-cal .mi { display: inline-flex; font-style: normal; } #ugf-cal .mi svg { display: block; fill: currentColor; }',
'#ugf-cal-body { flex: 1; display: flex; min-height: 0; }',
'#ugf-cal-side { flex: 0 0 auto; overflow-y: auto; overflow-x: hidden; }',
'#ugf-cal.noside #ugf-cal-side { display: none; }',
'#ugf-cal-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }',
'#ugf-cal-view { flex: 1; min-height: 0; position: relative; display: flex; flex-direction: column; }',
'#ugf-cal-loading { position: absolute; left: 50%; top: 4px; transform: translateX(-50%); display: none; z-index: 50; }',
'#ugf-cal.busy #ugf-cal-loading { display: block; }',
// the day grid
'#ugf-cal .grid { flex: 1; display: flex; flex-direction: column; min-height: 0; }',
'#ugf-cal .ghead, #ugf-cal .gall { display: flex; flex: 0 0 auto; }',
'#ugf-cal .ghead .dh { flex: 1 1 0; min-width: 0; text-align: center; overflow: hidden; white-space: nowrap; }',
'#ugf-cal .gall .adwrap { flex: 1; position: relative; min-height: 20px; }',
'#ugf-cal .adcol { position: absolute; top: 0; bottom: 0; }',
'#ugf-cal .adpos { position: absolute; padding: 1px 2px; }',
'#ugf-cal .gbody { flex: 1; overflow-y: scroll; position: relative; }',
'#ugf-cal .gin { position: relative; display: flex; }',
'#ugf-cal .gin .gutter { position: relative; flex: 0 0 auto; }',
'#ugf-cal .hl { position: absolute; right: 0; left: 0; }',
'#ugf-cal .cols { flex: 1; position: relative; }',
'#ugf-cal .line, #ugf-cal .half { position: absolute; left: 0; right: 0; height: 0; }',
'#ugf-cal .col { position: absolute; top: 0; bottom: 0; }',
'#ugf-cal .tpos { position: absolute; padding: 0 2px 0 1px; }',
'#ugf-cal .ev { cursor: pointer; overflow: hidden; }',
'#ugf-cal .tpos .ev { height: 100%; }',
'#ugf-cal .ev.ad { white-space: nowrap; text-overflow: ellipsis; }',
'#ugf-cal .now { position: absolute; left: 0; right: 0; height: 0; z-index: 3; pointer-events: none; }',
'#ugf-cal .sbar { flex: 0 0 auto; }',
// month
'#ugf-cal .month { flex: 1; display: flex; flex-direction: column; min-height: 0; }',
'#ugf-cal .mhd { display: flex; flex: 0 0 auto; } #ugf-cal .mhd div { flex: 1 1 0; }',
'#ugf-cal .mrow { flex: 1 1 0; display: flex; min-height: 0; }',
'#ugf-cal .mc { flex: 1 1 0; min-width: 0; overflow: hidden; position: relative; }',
'#ugf-cal .mc .ev { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
'#ugf-cal .mc .mn { display: block; text-decoration: none; }',
// schedule / agenda
'#ugf-cal .agenda { flex: 1; overflow-y: auto; }',
'#ugf-cal .aday { display: flex; } #ugf-cal .aevs { flex: 1; min-width: 0; }',
'#ugf-cal .ev.ag { display: flex; align-items: center; gap: 8px; }',
// bubbles
'#ugf-cal .ugf-cal-bubble { position: fixed; z-index: 100; background: #fff; }',
'#ugf-cal .ugf-cal-bubble .tail { position: absolute; bottom: -12px; width: 0; height: 0; border: 12px solid transparent; border-bottom: 0; border-top-color: #fff; }',
'#ugf-cal .ugf-cal-bubble.below .tail { bottom: auto; top: -12px; border-top: 0; border-bottom: 12px solid #fff; }',
// the view picker of the Material pages
'#ugf-cal .viewsel { position: relative; }',
'#ugf-cal .viewsel .vmenu { display: none; position: absolute; top: 100%; right: 0; background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,.2); padding: 8px 0; min-width: 160px; z-index: 30; }',
'#ugf-cal .viewsel.open .vmenu { display: block; }',
'#ugf-cal .viewsel .vmenu a { display: flex; justify-content: space-between; padding: 8px 16px; color: #3c4043 !important; text-decoration: none; }',
'#ugf-cal .viewsel .vmenu a:hover { background: #f1f3f4; }',
'#ugf-cal .viewsel .vmenu kbd { font: inherit; color: #70757a; }',
// the event details page and the notices
'#ugf-cal.editing #ugf-cal-body, #ugf-cal.editing #ugf-cal-fab { display: none !important; }',
'#ugf-cal-edit { flex: 1; overflow: auto; min-height: 0; }',
'#ugf-cal-edit input[type=text], #ugf-cal-edit textarea, #ugf-cal-edit select { font: inherit; }',
'#ugf-cal-edit .when { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }',
'#ugf-cal-edit .when .sd, #ugf-cal-edit .when .ed { width: 96px; } #ugf-cal-edit .when .st, #ugf-cal-edit .when .et { width: 76px; }',
'#ugf-cal-edit .ad { display: inline-flex; align-items: center; gap: 4px; margin-left: 10px; white-space: nowrap; }',
'#ugf-cal-edit .wide { width: 100%; max-width: 560px; } #ugf-cal-edit textarea { width: 100%; max-width: 560px; resize: vertical; }',
'#ugf-cal-edit .etab { border-collapse: collapse; } #ugf-cal-edit .etab th { text-align: right; vertical-align: top; font-weight: bold; padding: 6px 10px 6px 0; white-space: nowrap; } #ugf-cal-edit .etab td { padding: 4px 0; width: 100%; }',
'#ugf-cal-note { position: absolute; z-index: 130; left: 50%; transform: translateX(-50%); top: 4px; }',
'#ugf-cal-note a { margin-left: 6px; }',
// the drop-down menus and the Material dialog
'#ugf-cal .ugf-cal-menu { position: fixed; z-index: 120; background: #fff; min-width: 150px; text-align: left; }',
'#ugf-cal .ugf-cal-menu .it { display: flex; align-items: center; white-space: nowrap; text-decoration: none; cursor: pointer; }',
'#ugf-cal .ugf-cal-menu .it kbd { font: inherit; margin-left: auto; padding-left: 24px; }',
'#ugf-cal .ugf-cal-menu .tick { display: inline-block; width: 18px; flex: 0 0 18px; }',
'#ugf-cal .ugf-cal-menu .sws { display: grid; grid-template-columns: repeat(6, auto); gap: 4px; justify-content: start; }',
'#ugf-cal .ugf-cal-menu .sws.k24 { grid-template-columns: repeat(6, auto); } #ugf-cal .ugf-cal-menu .sws.c21 { grid-template-columns: repeat(7, auto); }',
'#ugf-cal .ugf-cal-menu .sw { display: flex; align-items: center; justify-content: center; color: #fff !important; }',
'#ugf-cal .ugf-cal-askfence { position: fixed; inset: 0; z-index: 150; display: flex; align-items: center; justify-content: center; }',
'#ugf-cal .ugf-cal-ask { background: #fff; width: 440px; max-width: calc(100vw - 32px); }',
'#ugf-cal .ugf-cal-ask .ar label { display: flex; align-items: center; gap: 6px; padding: 3px 0; cursor: pointer; }',
'#ugf-cal .ugf-cal-ask .ab { display: flex; gap: 8px; }',
'#ugf-cal .ugf-cal-dlgfence { position: fixed; inset: 0; z-index: 140; background: rgba(32,33,36,.6); display: flex; align-items: center; justify-content: center; }',
'#ugf-cal .ugf-cal-dlg { background: #fff; width: 400px; border-radius: 8px; padding: 24px; box-shadow: 0 24px 38px 3px rgba(0,0,0,.14), 0 9px 46px 8px rgba(0,0,0,.12), 0 11px 15px -7px rgba(0,0,0,.2); }',
'#ugf-cal .ugf-cal-dlg .dt { font: 22px "Google Sans", Roboto, arial, sans-serif; color: #202124; margin-bottom: 20px; }',
'#ugf-cal .ugf-cal-dlg .dsec { margin-bottom: 18px; } #ugf-cal .ugf-cal-dlg .dh { font: 500 14px Roboto, arial, sans-serif; color: #3c4043; margin-bottom: 8px; }',
'#ugf-cal .ugf-cal-dlg .rd { display: flex; align-items: center; gap: 12px; font: 14px Roboto, arial, sans-serif; color: #3c4043; padding: 6px 0; cursor: pointer; }',
'#ugf-cal .ugf-cal-dlg .rd input { width: 18px; height: 18px; margin: 0; accent-color: #1a73e8; }',
'#ugf-cal .ugf-cal-dlg .dacts { display: flex; justify-content: flex-end; }',
'#ugf-cal .ugf-cal-dlg .done { font: 500 14px "Google Sans", Roboto, arial, sans-serif; color: #1a73e8 !important; text-decoration: none; padding: 8px 24px; border-radius: 4px; }',
'#ugf-cal .ugf-cal-dlg .done:hover { background: #f6fafe; }',
'@media print { #ugf-cal .ugf-cal-menu, #ugf-cal .ugf-cal-dlgfence { display: none !important; } }',
'@media print { #ugf-cal-side, #ugf-cal-head, #ugf-cal-gbar { display: none !important; } #ugf-cal { position: static; } }'
];
const css = {};
// ---- 2006 to May 2010: Gmail's blue
css.c2006 = [
'#ugf-cal-edit { padding: 6px 10px 10px 8px; font-size: 13px; }',
'#ugf-cal-edit .eback { margin: 2px 0 8px 0; } #ugf-cal-edit .eback a { font-weight: bold; }',
'#ugf-cal-edit .ebtns { display: flex; gap: 6px; margin: 6px 0; } #ugf-cal-edit .ebtns button { font: 13px arial, sans-serif; padding: 1px 10px; }',
'#ugf-cal-edit .eframe { background: #c3d9ff; padding: 6px; border-radius: 4px; } #ugf-cal-edit .eframe .etab { background: #fff; width: 100%; }',
'#ugf-cal-edit .etab th { background: #e8eef7; padding: 6px 10px; width: 1%; } #ugf-cal-edit .etab td { padding: 5px 8px; }',
'#ugf-cal-edit input[type=text] { border: 1px solid #7f9db9; padding: 2px 3px; } #ugf-cal-edit textarea { border: 1px solid #7f9db9; }',
'#ugf-cal-edit .title.wide { font-size: 15px; font-weight: bold; }',
'#ugf-cal-note { background: #fad163; padding: 3px 12px; font-weight: bold; border-radius: 3px; color: #000; }',
'#ugf-cal .ugf-cal-menu { border: 1px solid #6b90da; box-shadow: 2px 2px 3px rgba(0,0,0,.25); padding: 2px 0; font-size: 12px; }',
'#ugf-cal .ugf-cal-menu .it { color: #000 !important; padding: 3px 14px 3px 10px; }',
'#ugf-cal .ugf-cal-menu .it:hover { background: #c3d9ff; }',
'#ugf-cal .ugf-cal-menu .sep { border-top: 1px solid #c3d9ff; margin: 2px 0; }',
'#ugf-cal .ugf-cal-menu .hd { color: #666; padding: 3px 10px; }',
'#ugf-cal .ugf-cal-menu .sws { padding: 4px 10px 6px 10px; gap: 3px; } #ugf-cal .ugf-cal-menu .sw { width: 16px; height: 16px; border: 1px solid rgba(0,0,0,.25); } #ugf-cal .ugf-cal-menu .sw.cur { outline: 2px solid #000; }',
'#ugf-cal .ugf-cal-menu .sw .mi svg { width: 12px; height: 12px; }',
'#ugf-cal-gbar { display: flex; justify-content: space-between; padding: 4px 8px 0 8px; font-size: 13px; }',
'#ugf-cal-gbar .left { display: flex; gap: 0; } #ugf-cal-gbar .left > * { margin-right: 8px; }',
'#ugf-cal-gbar .more small { font-size: 9px; }',
'#ugf-cal-gbar .right { color: #000; } #ugf-cal-gbar .right a { color: #00c; }',
'#ugf-cal-head { display: flex; align-items: center; padding: 4px 8px 6px 4px; }',
'#ugf-cal-head .logo img { display: block; border: 0; }',
'#ugf-cal[layout="2009"] #ugf-cal-head .logo img, #ugf-cal[layout="2010"] #ugf-cal-head .logo img, #ugf-cal[layout="2010N"] #ugf-cal-head .logo img { margin: 8px 14px 6px 6px; }',
'#ugf-cal-search { display: flex; align-items: center; gap: 4px; margin-left: 14px; }',
'#ugf-cal-search .q { width: 290px; font: 13px arial, sans-serif; padding: 1px 2px; border: 1px solid #7f9db9; }',
'#ugf-cal-search input[type="submit"], #ugf-cal-search input[type="button"] { font: 13px arial, sans-serif; }',
'#ugf-cal-search .opts { font-size: 11px; margin-left: 4px; }',
'#ugf-cal-side { width: 190px; padding: 4px 8px 8px 8px; }',
'#ugf-cal-side .links a { display: block; font-weight: bold; margin: 0 0 4px 0; }',
'#ugf-cal-mini { background: #c3d9ff; border-radius: 4px; padding: 4px 4px 5px 4px; margin: 8px 0 12px 0; }',
'#ugf-cal-mini .mhead { display: flex; justify-content: space-between; align-items: center; font-weight: bold; padding: 1px 2px 3px 2px; }',
'#ugf-cal-mini .mp { text-decoration: none; font-weight: bold; color: #112abb !important; padding: 0 3px; }',
'#ugf-cal-mini .mgrid { width: 100%; border-collapse: collapse; background: #fff; font-size: 11px; }',
'#ugf-cal-mini .mgrid th { background: #c3d9ff; font-weight: normal; color: #333; padding: 1px 0; }',
'#ugf-cal-mini .mgrid td { text-align: center; padding: 1px 0; cursor: pointer; color: #000; }',
'#ugf-cal-mini .mgrid td.out { color: #888; }',
'#ugf-cal-mini .mgrid td.sel { background: #e0ecff; font-weight: bold; }',
'#ugf-cal-mini .mgrid td.today span { border: 1px solid #b90000; padding: 0 1px; }',
'#ugf-cal-cals .sect { background: #c3d9ff; border-radius: 4px; padding: 2px 3px 4px 3px; margin: 0 0 12px 0; }',
'#ugf-cal-cals .sh { font-weight: bold; padding: 2px 3px 4px 3px; font-size: 12px; }',
'#ugf-cal-cals .list { background: #fff; padding: 2px; }',
'#ugf-cal-cals .addf input { width: 100%; font: 12px arial, sans-serif; margin: 0 0 3px 0; padding: 1px 2px; border: 1px solid #7f9db9; }',
'#ugf-cal-cals .cal { display: flex; align-items: center; justify-content: space-between; margin: 1px 0; padding: 1px 0 1px 5px; text-decoration: none; font-size: 12px; border-radius: 2px; color: #fff !important; }',
'#ugf-cal-cals .cal .cn { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }',
'#ugf-cal-cals .cal .dd { font-size: 8px; color: #fff; padding: 2px 3px; margin-left: 4px; }',
'#ugf-cal-cals .sf { display: flex; justify-content: space-between; padding: 3px 2px 0 2px; font-size: 11px; }',
'#ugf-cal-main { padding: 0 8px 8px 0; }',
'#ugf-cal-bar { display: flex; justify-content: space-between; align-items: flex-end; }',
'#ugf-cal-bar .nav { display: flex; align-items: center; gap: 4px; padding: 0 0 4px 0; }',
'#ugf-cal-bar .arr img { display: block; } #ugf-cal-bar .arr { display: block; }',
'#ugf-cal-bar .today { font: 12px arial, sans-serif; color: #000 !important; text-decoration: none; border: 1px solid #aaa; border-radius: 3px; background: linear-gradient(#fff, #ddd); padding: 1px 6px; margin: 0 4px; }',
'#ugf-cal-bar .title { font-weight: bold; font-size: 14px; margin: 0 10px 0 4px; }',
'#ugf-cal-bar .refresh { font-size: 12px; }',
'#ugf-cal-bar .tabs { display: flex; align-items: flex-end; }',
'#ugf-cal-bar .tabs .print { display: inline-flex; align-items: center; gap: 2px; margin-right: 10px; font-size: 12px; padding-bottom: 4px; color: #00c; }',
'#ugf-cal-bar .tabs .v { padding: 3px 8px 4px 8px; margin-left: 2px; font-size: 13px; font-weight: bold; border-radius: 4px 4px 0 0; background: #e8eef7; text-decoration: none; }',
'#ugf-cal-bar .tabs .v.on { background: #c3d9ff; color: #000 !important; }',
'#ugf-cal-view { background: #c3d9ff; padding: 5px; border-radius: 4px 0 4px 4px; }',
'#ugf-cal .ghead { background: #c3d9ff; }',
'#ugf-cal .ghead .dh { padding: 2px 0 3px 0; font-size: 12px; } #ugf-cal .ghead .dh a { color: #112abb; text-decoration: none; }',
'#ugf-cal .ghead .dh.today { background: #fad163; }',
'#ugf-cal .gutter { width: 44px; }',
'#ugf-cal .gall { background: #fff; border-bottom: 2px solid #c3d9ff; }',
'#ugf-cal .adcol { border-left: 1px solid #ddd; } #ugf-cal .adcol.today { background: #fff7d7; }',
'#ugf-cal .gbody { background: #fff; }',
'#ugf-cal .hl span { display: block; text-align: right; padding: 1px 3px 0 0; font-size: 11px; color: #666; }',
'#ugf-cal .hl { border-top: 1px solid #ddd; }',
'#ugf-cal .line { border-top: 1px solid #ddd; } #ugf-cal .half { border-top: 1px dotted #ddd; }',
'#ugf-cal .col { border-left: 1px solid #ddd; } #ugf-cal .col.today { background: #fff7d7; }',
'#ugf-cal .ev.tm { border: 1px solid; border-radius: 3px; color: #fff; font-size: 11px; }',
'#ugf-cal .ev.tm.short { padding: 0 3px; white-space: nowrap; font-size: 11px; line-height: 13px; }',
'#ugf-cal .ev.tm .eh { font-weight: bold; padding: 0 3px; white-space: nowrap; overflow: hidden; }',
'#ugf-cal .ev.tm .eb { padding: 1px 3px; }',
'#ugf-cal .ev.ad { border-radius: 3px; padding: 1px 4px; font-size: 11px; border: 1px solid; }',
'#ugf-cal .mhd { background: #c3d9ff; } #ugf-cal .mhd div { text-align: center; font-size: 12px; padding: 2px 0 3px 0; }',
'#ugf-cal .month { background: #fff; }',
'#ugf-cal .mc { border-left: 1px solid #ddd; border-top: 1px solid #ddd; padding: 0 1px; }',
'#ugf-cal .mc .mn { background: #e8eef7; text-align: right; padding: 0 3px; font-size: 11px; color: #333 !important; margin: 0 -1px 1px -1px; }',
'#ugf-cal .mc.out .mn { color: #888 !important; background: #f3f3f3; }',
'#ugf-cal .mc.today { background: #fff7d7; } #ugf-cal .mc.today .mn { background: #fad163; }',
'#ugf-cal .mc .ev.mt { font-size: 11px; padding: 0 2px; }',
'#ugf-cal .mc .ev.mt .t { font-weight: bold; }',
'#ugf-cal .mc .ev.ad { margin: 0 0 1px 0; }',
'#ugf-cal .mc .more { display: block; font-size: 11px; padding: 0 3px; }',
'#ugf-cal .agenda { background: #fff; }',
'#ugf-cal .aday { border-top: 1px solid #ddd; } #ugf-cal .aday.today { background: #fff7d7; }',
'#ugf-cal .adate { width: 110px; flex: 0 0 110px; padding: 3px 6px; font-weight: bold; background: #e8eef7; font-size: 12px; }',
'#ugf-cal .ev.ag { padding: 3px 6px; font-size: 12px; } #ugf-cal .ev.ag .at { width: 110px; color: #333; } #ugf-cal .ev.ag .dot { display: none; }',
'#ugf-cal .agenda .none { padding: 20px; color: #666; }',
'#ugf-cal-loading { background: #c00; color: #fff; font-weight: bold; padding: 2px 8px; top: 2px; }',
'#ugf-cal .ugf-cal-bubble { border: 1px solid #99a; border-radius: 8px; box-shadow: 2px 2px 6px rgba(0,0,0,.3); padding: 10px 14px 10px 12px; width: 330px; font-size: 13px; }',
'#ugf-cal .ugf-cal-bubble .x { position: absolute; right: 6px; top: 6px; } #ugf-cal .ugf-cal-bubble .x img { display: block; }',
'#ugf-cal .ugf-cal-bubble .tt { font-weight: bold; font-size: 14px; margin: 0 16px 6px 0; }',
'#ugf-cal .ugf-cal-bubble .tw, #ugf-cal .ugf-cal-bubble .tc { margin: 0 0 4px 0; }',
'#ugf-cal .ugf-cal-bubble .wr { display: flex; align-items: center; gap: 6px; margin: 8px 0; } #ugf-cal .ugf-cal-bubble .wr input { flex: 1; font: 13px arial, sans-serif; }',
'#ugf-cal .ugf-cal-bubble .acts { display: flex; align-items: center; gap: 10px; margin-top: 8px; font-size: 12px; }',
'#ugf-cal .ugf-cal-bubble .acts button { font: 13px arial, sans-serif; }',
'#ugf-cal .ugf-cal-bubble .tail { border-top-color: #fff; filter: drop-shadow(1px 1px 0 #99a); }',
'#ugf-cal .ugf-cal-askfence { background: rgba(255,255,255,.5); }',
'#ugf-cal .ugf-cal-ask { background: #c3d9ff; border-radius: 4px; padding: 6px; font-size: 13px; color: #000; box-shadow: 2px 2px 6px rgba(0,0,0,.3); }',
'#ugf-cal .ugf-cal-ask .at { font-weight: bold; padding: 2px 4px 6px 4px; }',
'#ugf-cal .ugf-cal-ask .ax, #ugf-cal .ugf-cal-ask .ar { background: #fff; padding: 8px 10px; }',
'#ugf-cal .ugf-cal-ask .ax + .ar { padding-top: 0; }',
'#ugf-cal .ugf-cal-ask .ab { padding: 6px 4px 2px 4px; }',
'#ugf-cal .ugf-cal-ask button { font: 13px arial, sans-serif; padding: 1px 10px; }',
'#ugf-cal .ugf-cal-ask button.pri { font-weight: bold; }'
];
// ---- May 2010 to June 2011: lighter, with buttons
css.c2010 = css.c2006.concat([
'#ugf-cal-side .links { display: flex; align-items: center; gap: 10px; margin: 2px 0 10px 0; }',
'#ugf-cal-side .links a { display: inline-block; margin: 0; font-weight: normal; }',
'#ugf-cal-side .links .btn { color: #000 !important; text-decoration: none; border: 1px solid #aaa; border-radius: 3px; background: linear-gradient(#fff, #ddd); padding: 3px 8px; }',
'#ugf-cal-mini { background: #fff; padding: 0; margin: 0 0 14px 0; }',
'#ugf-cal-mini .mhead { color: #2a5db0; font-size: 13px; }',
'#ugf-cal-mini .mgrid th { background: #fff; color: #333; }',
'#ugf-cal-mini .mgrid td { font-weight: bold; } #ugf-cal-mini .mgrid td.out { font-weight: normal; }',
'#ugf-cal-mini .mgrid td.sel { background: #dde5f5; }',
'#ugf-cal-cals .sect { background: #fff; padding: 0; }',
'#ugf-cal-cals .sh { color: #2a5db0; font-size: 13px; padding: 4px 0; border-top: 1px solid #c3d9ff; }',
'#ugf-cal-cals .list { padding: 0; }',
'#ugf-cal-bar { align-items: center; padding: 0 0 4px 0; }',
'#ugf-cal-bar .nav .btn { margin: 0 4px 0 0; }',
'#ugf-cal-bar .print { display: inline-flex; align-items: center; gap: 2px; font-size: 12px; margin: 0 8px 0 4px; }',
'#ugf-cal-bar .views { display: flex; }',
'#ugf-cal-bar .views .v { color: #000 !important; text-decoration: none; border: 1px solid #aaa; border-left-width: 0; background: linear-gradient(#fff, #ddd); padding: 3px 10px; font-size: 12px; }',
'#ugf-cal-bar .views .v:first-child { border-left-width: 1px; border-radius: 3px 0 0 3px; } #ugf-cal-bar .views .v:last-child { border-radius: 0 3px 3px 0; }',
'#ugf-cal-bar .views .v.on { background: linear-gradient(#ccc, #e8e8e8); box-shadow: inset 0 1px 2px rgba(0,0,0,.2); }',
'#ugf-cal-view { background: #fff; padding: 0; border: 1px solid #c3d9ff; border-radius: 0; }',
'#ugf-cal .ghead, #ugf-cal .mhd { background: #fff; border-bottom: 1px solid #ddd; }',
'#ugf-cal .ghead .dh a { color: #333; }',
'#ugf-cal .ghead .dh.today { background: #fad163; }',
'#ugf-cal .gall { border-bottom: 1px solid #ccc; }',
'#ugf-cal .mc .mn { background: none; }',
'#ugf-cal .mc.today .mn { background: none; }'
]);
// ---- June 2011 to 2013 (and to October 2017 without the dark bar)
css.c2011 = [
'#ugf-cal-gbar.dark { display: flex; justify-content: space-between; align-items: center; background: #2d2d2d; height: 30px; padding: 0 14px; color: #ccc; flex: 0 0 auto; }',
'#ugf-cal-gbar.dark .left, #ugf-cal-gbar.dark .right { display: flex; align-items: center; gap: 13px; height: 30px; }',
'#ugf-cal-gbar.dark a { color: #ccc !important; line-height: 27px; height: 30px; border-top: 3px solid transparent; text-decoration: none; font-size: 13px; }',
'#ugf-cal-gbar.dark a:hover { color: #fff !important; }',
'#ugf-cal-gbar.dark a.here { color: #fff !important; font-weight: bold; border-top-color: #dd4b39; }',
'#ugf-cal-gbar.dark a.plus, #ugf-cal-gbar.dark a.who { color: #fff !important; font-weight: bold; }',
'#ugf-cal-gbar.dark.late { padding-left: 4px; height: 29px; } #ugf-cal-gbar.dark.late .left { gap: 0; height: 29px; }',
'#ugf-cal-gbar.dark.late a { border-top: 0; line-height: 29px; height: 29px; font-weight: bold; color: #bbb !important; padding: 0 9px; } #ugf-cal-gbar.dark.late a.here, #ugf-cal-gbar.dark.late a:hover { color: #fff !important; }',
'#ugf-cal-gbar.dark .gear { display: inline-flex; align-items: center; border: 0; line-height: normal; } #ugf-cal-gbar.dark .gear svg { fill: #ccc; }',
'#ugf-cal-head { display: flex; align-items: center; padding: 14px 16px 12px 16px; border-bottom: 1px solid #ebebeb; flex: 0 0 auto; }',
'#ugf-cal-head .logo { display: block; width: 186px; flex: 0 0 186px; } #ugf-cal-head .logo img { display: block; margin: -3px 0; }',
'#ugf-cal-search { display: flex; align-items: center; }',
'#ugf-cal-search .q { width: 482px; height: 29px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 1px 8px; font: 16px arial, sans-serif; outline: none; }',
'#ugf-cal-search .q:focus { border-color: #4d90fe; box-shadow: inset 0 1px 2px rgba(0,0,0,.3); }',
'#ugf-cal-search .go { width: 70px; height: 29px; border: 1px solid #3079ed; border-radius: 2px; background: linear-gradient(#4d90fe, #4787ed); color: #fff; margin-left: 4px; display: flex; align-items: center; justify-content: center; cursor: pointer; }',
'#ugf-cal-search .opts { font-size: 11px; margin-left: 14px; }',
'#ugf-cal-body { position: relative; }',
'#ugf-cal-bar { display: flex; align-items: center; height: 58px; padding: 0 16px 0 0; flex: 0 0 auto; }',
'#ugf-cal-side .label { height: 58px; margin-top: -58px; padding-top: 16px; color: #dd4b39; font-size: 20px; }',
'#ugf-cal-bar .nav { display: flex; align-items: center; gap: 8px; flex: 1; }',
'#ugf-cal-bar .views { display: flex; align-items: center; gap: 8px; }',
'#ugf-cal .kb { display: inline-flex; align-items: center; justify-content: center; gap: 2px; height: 29px; min-width: 34px; padding: 0 8px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444 !important; font: bold 11px arial, sans-serif; text-decoration: none; }',
'#ugf-cal .kb:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); color: #222 !important; }',
'#ugf-cal .kb svg { fill: #666; } #ugf-cal .kb small { font-size: 9px; }',
'#ugf-cal .kb.today { padding: 0 10px; }',
'#ugf-cal .grp { display: inline-flex; } #ugf-cal .grp .kb { border-radius: 0; margin-left: -1px; } #ugf-cal .grp .kb:first-child { border-radius: 2px 0 0 2px; margin-left: 0; } #ugf-cal .grp .kb:last-child { border-radius: 0 2px 2px 0; }',
'#ugf-cal .kb.v { font-weight: bold; }',
'#ugf-cal .kb.v.on { background: #eee; box-shadow: inset 0 1px 2px rgba(0,0,0,.1); border-color: #ccc; color: #333 !important; }',
'#ugf-cal-bar .title { font-size: 18px; color: #222; margin-left: 8px; }',
'#ugf-cal-side { width: 186px; padding: 58px 0 10px 16px; }',
'#ugf-cal-main { position: relative; }',
'#ugf-cal-side .create { display: flex; margin: 16px 0 16px 0; }',
'#ugf-cal-side .red { display: inline-flex; align-items: center; justify-content: center; height: 29px; border: 1px solid #b0281a; background: linear-gradient(#dd4b39, #d14836); color: #fff !important; font: bold 11px arial, sans-serif; text-decoration: none; padding: 0 8px; }',
'#ugf-cal-side .red:first-child { width: 72px; border-radius: 2px 0 0 2px; } #ugf-cal-side .red.dd { width: 22px; border-left-color: #c53727; border-radius: 0 2px 2px 0; margin-left: -1px; font-size: 10px; }',
'#ugf-cal-mini { margin: 0 12px 14px 0; font-size: 11px; }',
'#ugf-cal-mini .mhead { display: flex; align-items: center; margin: 0 0 4px 0; font-size: 12px; color: #222; }',
'#ugf-cal-mini .mhead .mt { flex: 1; font-weight: bold; } #ugf-cal-mini .mhead .mt:before { content: "\\25BE"; color: #999; margin-right: 4px; font-weight: normal; }',
'#ugf-cal-mini .mp { color: #444 !important; text-decoration: none; font-size: 16px; padding: 0 5px; }',
'#ugf-cal-mini .mgrid { width: 100%; border-collapse: collapse; }',
'#ugf-cal-mini .mgrid th { font-weight: normal; color: #222; font-size: 11px; padding: 2px 0; }',
'#ugf-cal-mini .mgrid td { text-align: center; padding: 2px 0; cursor: pointer; color: #222; font-weight: bold; font-size: 11px; }',
'#ugf-cal-mini .mgrid td.out { color: #999; font-weight: normal; }',
'#ugf-cal-mini .mgrid td.sel { background: #ddd; }',
'#ugf-cal-mini .mgrid td.today span { border: 1px solid #444; padding: 0 1px; }',
'#ugf-cal-cals .sh { font-weight: bold; font-size: 13px; color: #222; margin: 8px 0 4px 0; }',
'#ugf-cal-cals .sh .tri { color: #999; margin-right: 4px; font-weight: normal; }',
'#ugf-cal-cals .addf input { width: 100%; height: 25px; font: 12px arial, sans-serif; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 0 6px; margin: 2px 0 6px 0; }',
'#ugf-cal-cals .cal { display: flex; align-items: center; gap: 6px; padding: 3px 4px; text-decoration: none; color: #222 !important; font-size: 13px; }',
'#ugf-cal-cals .cal:hover { background: #eee; }',
'#ugf-cal-cals .cal .sw { width: 14px; height: 14px; flex: 0 0 14px; border: 1px solid; border-radius: 1px; }',
'#ugf-cal-cals .cal .cn { flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }',
'#ugf-cal-cals .cal .dd { color: #777; font-size: 10px; visibility: hidden; } #ugf-cal-cals .cal:hover .dd { visibility: visible; }',
'#ugf-cal-cals .cal.off { color: #999 !important; }',
'#ugf-cal-cals .sf { font-size: 11px; color: #999; padding: 2px 4px; } #ugf-cal-cals .sf a { color: #15c; }',
'#ugf-cal-view { border-top: 1px solid #ebebeb; }',
'#ugf-cal .gutter { width: 60px; }',
'#ugf-cal .ghead { border-bottom: 1px solid #ddd; }',
'#ugf-cal .ghead .dh { padding: 4px 0; font-size: 13px; } #ugf-cal .ghead .dh a { color: #222; text-decoration: none; }',
'#ugf-cal .ghead .dh.today { background: #fff7d6; } #ugf-cal .ghead .dh.today a { font-weight: bold; }',
'#ugf-cal .gall { border-bottom: 2px solid #ddd; }',
'#ugf-cal .adcol { border-left: 1px solid #ddd; } #ugf-cal .adcol.today { background: #fff7d6; }',
'#ugf-cal .hl span { display: block; text-align: right; padding: 2px 6px 0 0; font-size: 11px; color: #666; }',
'#ugf-cal .hl { border-top: 1px solid #ddd; }',
'#ugf-cal .line { border-top: 1px solid #ddd; } #ugf-cal .half { border-top: 1px dotted #eee; }',
'#ugf-cal .col { border-left: 1px solid #ddd; } #ugf-cal .col.today { background: #fff7d6; }',
'#ugf-cal .now { border-top: 2px solid #f00; opacity: .6; }',
'#ugf-cal .ev.tm { border: 1px solid; border-radius: 3px; font-size: 11px; padding: 1px 3px; }',
'#ugf-cal .ev.tm .eh { font-weight: normal; white-space: nowrap; overflow: hidden; font-size: 11px; }',
'#ugf-cal .ev.tm .eb { font-weight: bold; }',
'#ugf-cal .ev.tm.short { padding: 0 3px; white-space: nowrap; line-height: 13px; }',
'#ugf-cal .ev.ad { border-radius: 3px; padding: 1px 5px; font-size: 12px; border: 1px solid; }',
'#ugf-cal .mhd div { font-size: 13px; color: #666; padding: 4px 6px; border-bottom: 1px solid #ddd; }',
'#ugf-cal .mc { border-left: 1px solid #ddd; border-bottom: 1px solid #ddd; padding: 2px 0; }',
'#ugf-cal .mc .mn { padding: 0 6px 2px 6px; font-size: 12px; color: #666 !important; }',
'#ugf-cal .mc.out { } #ugf-cal .mc.out .mn { color: #bbb !important; }',
'#ugf-cal .mc.today { background: #fff7d6; } #ugf-cal .mc.today .mn { color: #222 !important; font-weight: bold; }',
'#ugf-cal .mc .ev.mt { font-size: 12px; padding: 0 6px; }',
'#ugf-cal .mc .ev.ad { margin: 0 1px 1px 1px; }',
'#ugf-cal .mc .more { display: block; font-size: 12px; padding: 1px 6px; color: #15c !important; }',
'#ugf-cal .adate { width: 140px; flex: 0 0 140px; padding: 6px 10px; font-size: 13px; color: #222; }',
'#ugf-cal .aday { border-bottom: 1px solid #eee; } #ugf-cal .aday.today .adate { font-weight: bold; }',
'#ugf-cal .ev.ag { padding: 6px 10px; font-size: 13px; } #ugf-cal .ev.ag .at { width: 120px; color: #222; } #ugf-cal .ev.ag .dot { width: 10px; height: 10px; }',
'#ugf-cal .agenda .none { padding: 20px; color: #777; }',
'#ugf-cal-loading { background: #f9edbe; border: 1px solid #f0c36d; border-radius: 2px; padding: 3px 10px; font-weight: bold; color: #222; top: -46px; }',
'#ugf-cal .ugf-cal-bubble { border: 1px solid #bebebe; box-shadow: 0 4px 16px rgba(0,0,0,.2); padding: 16px 20px 14px 20px; width: 360px; font-size: 13px; }',
'#ugf-cal .ugf-cal-bubble .x { position: absolute; right: 8px; top: 4px; color: #777 !important; text-decoration: none; font-size: 20px; }',
'#ugf-cal .ugf-cal-bubble .tt { font-size: 16px; font-weight: bold; margin: 0 16px 8px 0; }',
'#ugf-cal .ugf-cal-bubble .tw, #ugf-cal .ugf-cal-bubble .tc { margin: 0 0 6px 0; color: #222; }',
'#ugf-cal .ugf-cal-bubble .wr { display: flex; align-items: center; gap: 8px; margin: 10px 0; } #ugf-cal .ugf-cal-bubble .wr input { flex: 1; height: 27px; border: 1px solid #d9d9d9; padding: 0 6px; font: 13px arial, sans-serif; }',
'#ugf-cal .ugf-cal-bubble .acts { display: flex; align-items: center; gap: 12px; margin-top: 12px; }',
'#ugf-cal .ugf-cal-bubble .acts .sep { color: #ccc; }',
'#ugf-cal .ugf-cal-bubble .acts button { height: 29px; border: 1px solid #3079ed; border-radius: 2px; background: linear-gradient(#4d90fe, #4787ed); color: #fff; font: bold 11px arial, sans-serif; padding: 0 12px; }',
'#ugf-cal .ugf-cal-bubble .tail { filter: drop-shadow(0 2px 0 #bebebe); }',
// the +You corner of 2012-2014 and the grid corner of 2015-2017
'#ugf-cal-account { display: flex; align-items: center; gap: 10px; margin-left: auto; }',
'#ugf-cal-account .plusname { color: #666 !important; text-decoration: none; }',
'#ugf-cal-account .nbox { min-width: 26px; height: 26px; border: 1px solid #dcdcdc; border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #777; font-size: 12px; display: inline-flex; align-items: center; justify-content: center; padding: 0 6px; }',
'#ugf-cal-account .sharebtn { height: 26px; border: 1px solid #dcdcdc; border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font-size: 12px; display: inline-flex; align-items: center; gap: 5px; padding: 0 10px; }',
'#ugf-cal-account .sharebtn b { font-size: 14px; font-weight: normal; color: #777; }',
'#ugf-cal-account .pfpwrap { display: inline-flex; align-items: center; gap: 3px; border: 1px solid #dcdcdc; border-radius: 2px; padding: 1px 4px 1px 1px; cursor: pointer; }',
'#ugf-cal-account .pfpwrap .car { font-style: normal; color: #777; font-size: 9px; }',
'#ugf-cal-account .pfp { width: 24px; height: 24px; display: block; object-fit: cover; border-radius: 1px; }',
'#ugf-cal-account .pfp.letter, #ugf-cal-head .pfp.letter { background: #c62828; color: #fff; display: flex; align-items: center; justify-content: center; text-transform: uppercase; }',
'#ugf-cal-account.mat .pfp { width: 32px; height: 32px; border-radius: 50%; }',
'#ugf-cal-account .ic { display: inline-flex; width: 30px; height: 30px; align-items: center; justify-content: center; color: #666 !important; }',
'#ugf-cal-head .signin { margin-left: auto; display: inline-flex; align-items: center; height: 29px; padding: 0 12px; background: linear-gradient(#dd4b39, #d14836); border: 1px solid #c53727; border-radius: 2px; color: #fff !important; font: bold 13px arial, sans-serif; text-decoration: none; }',
'#ugf-cal .ugf-cal-askfence { background: rgba(255,255,255,.75); }',
'#ugf-cal .ugf-cal-ask { border: 1px solid rgba(0,0,0,.333); box-shadow: 0 4px 16px rgba(0,0,0,.2); padding: 30px 42px; color: #222; }',
'#ugf-cal .ugf-cal-ask .at { font-size: 16px; margin-bottom: 16px; }',
'#ugf-cal .ugf-cal-ask .ax { margin-bottom: 14px; line-height: 17px; }',
'#ugf-cal .ugf-cal-ask .ar { margin-bottom: 14px; }',
'#ugf-cal .ugf-cal-ask .ab { margin-top: 18px; }',
'#ugf-cal .ugf-cal-ask button { height: 29px; min-width: 72px; padding: 0 8px; border: 1px solid rgba(0,0,0,.1); border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font: bold 11px arial, sans-serif; cursor: default; }',
'#ugf-cal .ugf-cal-ask button:hover { border-color: #c6c6c6; box-shadow: 0 1px 1px rgba(0,0,0,.1); color: #222; }',
'#ugf-cal .ugf-cal-ask button.pri { border-color: #3079ed; background: linear-gradient(#4d90fe, #4787ed); color: #fff; }',
'#ugf-cal .ugf-cal-ask button.pri:hover { border-color: #2f5bb7; background: linear-gradient(#4d90fe, #357ae8); }',
'#ugf-cal-edit .reptxt { color: #222; }'
];
css.c2011 = css.c2011.concat([
'#ugf-cal-edit { padding: 0 24px 20px 16px; }',
'#ugf-cal-edit .etop { display: flex; align-items: center; gap: 12px; height: 58px; }',
'#ugf-cal-edit .etop .back { color: #15c !important; font-size: 13px; margin-right: 8px; }',
'#ugf-cal-edit .etop .red { display: inline-flex; align-items: center; height: 29px; padding: 0 16px; border: 1px solid #b0281a; border-radius: 2px; background: linear-gradient(#dd4b39, #d14836); color: #fff !important; font: bold 11px arial, sans-serif; text-decoration: none; }',
'#ugf-cal-edit .etop .kb { padding: 0 16px; }',
'#ugf-cal-edit .erow { margin: 0 0 12px 0; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }',
'#ugf-cal-edit input[type=text], #ugf-cal-edit textarea { border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 4px 6px; font: 13px arial, sans-serif; outline: none; border-radius: 1px; }',
'#ugf-cal-edit input[type=text]:focus, #ugf-cal-edit textarea:focus { border-color: #4d90fe; box-shadow: inset 0 1px 2px rgba(0,0,0,.3); }',
'#ugf-cal-edit .title.big { width: 560px; max-width: 100%; font-size: 18px; height: 34px; }',
'#ugf-cal-edit .when input { height: 27px; } #ugf-cal-edit .to { color: #222; margin: 0 2px; }',
'#ugf-cal-edit select { height: 27px; border: 1px solid #d9d9d9; border-radius: 2px; background: #f5f5f5; font: 13px arial, sans-serif; color: #444; padding: 0 4px; } #ugf-cal-edit .rl { margin-right: 4px; }',
'#ugf-cal-edit .etabs { display: flex; border-bottom: 1px solid #ebebeb; margin: 18px 0 12px 0; } #ugf-cal-edit .etabs span { padding: 8px 14px; color: #666; font-size: 13px; } #ugf-cal-edit .etabs span.on { color: #dd4b39; font-weight: bold; border-bottom: 2px solid #dd4b39; }',
'#ugf-cal-edit .etab th { color: #222; font-size: 13px; width: 110px; padding-top: 10px; }',
'#ugf-cal-note { background: #f9edbe; border: 1px solid #f0c36d; border-radius: 2px; padding: 4px 14px; font-weight: bold; color: #222; top: 60px; box-shadow: 0 2px 4px rgba(0,0,0,.2); }',
'#ugf-cal .ugf-cal-menu { border: 1px solid rgba(0,0,0,.2); box-shadow: 0 2px 4px rgba(0,0,0,.2); padding: 6px 0; font-size: 13px; }',
'#ugf-cal .ugf-cal-menu .it { color: #222 !important; padding: 6px 44px 6px 12px; }',
'#ugf-cal .ugf-cal-menu .it:hover { background: #eee; }',
'#ugf-cal .ugf-cal-menu .it .tick { color: #222; font-size: 13px; }',
'#ugf-cal .ugf-cal-menu:not(.calm) .it:not(.ck) { padding-left: 30px; }',
'#ugf-cal .ugf-cal-menu .sep { border-top: 1px solid #ebebeb; margin: 6px 0; }',
'#ugf-cal .ugf-cal-menu .hd { color: #777; padding: 6px 44px 6px 16px; font-size: 13px; }',
'#ugf-cal .ugf-cal-menu .sws { padding: 4px 16px 8px 16px; gap: 3px; } #ugf-cal .ugf-cal-menu .sw { width: 18px; height: 18px; border-radius: 1px; } #ugf-cal .ugf-cal-menu .sw:hover { outline: 1px solid #333; }',
'#ugf-cal .ugf-cal-menu .sw .mi svg { width: 13px; height: 13px; }',
'#ugf-cal .kb.menuon { background: #eee; box-shadow: inset 0 1px 2px rgba(0,0,0,.1); border-color: #ccc; }',
'#ugf-cal-cals .cal .dd { padding: 0 4px; } #ugf-cal-cals .cal .dd.menuon { visibility: visible; }',
// Cozy and Compact
'#ugf-cal.dens-cozy #ugf-cal-bar { height: 50px; } #ugf-cal.dens-cozy #ugf-cal-side .label { height: 50px; margin-top: -50px; padding-top: 12px; } #ugf-cal.dens-cozy #ugf-cal-side { padding-top: 50px; }',
'#ugf-cal.dens-compact #ugf-cal-bar { height: 42px; } #ugf-cal.dens-compact #ugf-cal-side .label { height: 42px; margin-top: -42px; padding-top: 8px; } #ugf-cal.dens-compact #ugf-cal-side { padding-top: 42px; }',
'#ugf-cal.dens-cozy .kb { height: 27px; } #ugf-cal.dens-compact .kb { height: 25px; min-width: 30px; }',
'#ugf-cal.dens-cozy #ugf-cal-side .create, #ugf-cal.dens-compact #ugf-cal-side .create { margin: 8px 0 12px 0; }',
'#ugf-cal.dens-compact .ev.tm { font-size: 11px; } #ugf-cal.dens-compact .ghead .dh { padding: 2px 0; } #ugf-cal.dens-compact #ugf-cal-cals .cal { padding: 1px 4px; }'
]);
css.c2013 = css.c2011;
// ---- October 2017 on: Material
css.c2017 = [
'#ugf-cal { font: 14px Roboto, arial, sans-serif; color: #212121; }',
'#ugf-cal a { color: inherit; text-decoration: none; }',
'#ugf-cal-head { display: flex; align-items: center; height: 64px; padding: 8px; border-bottom: 1px solid #e0e0e0; flex: 0 0 auto; }',
'#ugf-cal-head .ib { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 50%; color: #5f6368 !important; margin: 0 2px; }',
'#ugf-cal-head .ib:hover { background: rgba(0,0,0,.06); }',
'#ugf-cal-head .burger { display: inline-flex; width: 48px; height: 48px; align-items: center; justify-content: center; border-radius: 50%; color: #5f6368 !important; margin: 0 4px; }',
'#ugf-cal-head .logo { display: flex; align-items: center; gap: 4px; width: 238px; padding-left: 4px; }',
'#ugf-cal-head .logo img { display: block; }',
'#ugf-cal-head .logo .name { font-size: 22px; color: #757575; padding-left: 4px; }',
'#ugf-cal-head .nav { display: flex; align-items: center; flex: 1; gap: 2px; }',
'#ugf-cal-head .today { display: inline-flex; align-items: center; height: 36px; padding: 0 16px; margin-right: 12px; border-radius: 2px; background: #eee; color: #333 !important; font-weight: 500; font-size: 14px; }',
'#ugf-cal-head .title { font-size: 20px; color: #212121; margin-left: 8px; white-space: nowrap; }',
'#ugf-cal-head .tools { display: flex; align-items: center; gap: 2px; }',
'#ugf-cal-head .viewsel .vs { display: inline-flex; align-items: center; height: 36px; padding: 0 4px 0 12px; border-radius: 2px; background: #eee; color: #333 !important; font-weight: 500; margin: 0 6px; }',
'#ugf-cal-head .me { margin: 0 8px 0 6px; } #ugf-cal-head .me .pfp { width: 32px; height: 32px; border-radius: 50%; display: block; object-fit: cover; }',
'#ugf-cal-head .me .pfp.letter { background: #c62828; color: #fff; display: flex; align-items: center; justify-content: center; font-size: 16px; text-transform: uppercase; }',
'#ugf-cal-head .signin { display: inline-flex; align-items: center; height: 36px; padding: 0 16px; background: #4285f4; border-radius: 2px; color: #fff !important; font-weight: 500; margin: 0 8px; }',
'#ugf-cal-side { width: 256px; padding: 16px 0 16px 0; }',
'#ugf-cal-mini { padding: 0 16px 0 24px; margin: 0 0 12px 0; }',
'#ugf-cal-mini .mhead { display: flex; align-items: center; height: 32px; font-size: 13px; color: #212121; }',
'#ugf-cal-mini .mhead .mt { flex: 1; }',
'#ugf-cal-mini .mp { display: inline-flex; width: 28px; height: 28px; align-items: center; justify-content: center; border-radius: 50%; color: #616161 !important; }',
'#ugf-cal-mini .mgrid { width: 100%; border-collapse: collapse; font-size: 10px; }',
'#ugf-cal-mini .mgrid th { font-weight: 500; color: #757575; height: 24px; }',
'#ugf-cal-mini .mgrid td { text-align: center; height: 28px; cursor: pointer; color: #212121; }',
'#ugf-cal-mini .mgrid td span { display: inline-flex; width: 24px; height: 24px; align-items: center; justify-content: center; border-radius: 50%; }',
'#ugf-cal-mini .mgrid td:hover span { background: #eee; }',
'#ugf-cal-mini .mgrid td.out { color: #9e9e9e; }',
'#ugf-cal-mini .mgrid td.cur span { background: #e0e0e0; }',
'#ugf-cal-mini .mgrid td.today span { background: #4285f4; color: #fff; }',
'#ugf-cal-cals .people { display: flex; align-items: center; margin: 12px 16px 8px 24px; background: #eee; border-radius: 2px; }',
'#ugf-cal-cals .people input { flex: 1; min-width: 0; border: 0; background: transparent; height: 40px; padding: 0 12px; font: 14px Roboto, arial, sans-serif; outline: none; }',
'#ugf-cal-cals .people .add { display: inline-flex; color: #616161 !important; padding: 0 8px; }',
'#ugf-cal-cals .sect { border-top: 1px solid #e0e0e0; padding: 8px 0; }',
'#ugf-cal-cals .sh { display: flex; align-items: center; justify-content: space-between; height: 40px; padding: 0 16px 0 24px; font-size: 14px; color: #616161; font-weight: 500; }',
'#ugf-cal-cals .sh .add { display: inline-flex; color: #616161 !important; margin-left: auto; margin-right: 4px; }',
'#ugf-cal-cals .sh .mi { color: #616161; }',
'#ugf-cal-cals .cal { display: flex; align-items: center; height: 32px; padding: 0 16px 0 24px; gap: 16px; color: #212121 !important; }',
'#ugf-cal-cals .cal:hover { background: #f5f5f5; }',
'#ugf-cal-cals .cal .ck { display: inline-flex; width: 18px; height: 18px; border: 2px solid; border-radius: 2px; align-items: center; justify-content: center; color: #fff; flex: 0 0 18px; }',
'#ugf-cal-cals .cal .ck svg { width: 14px; height: 14px; }',
'#ugf-cal-cals .cal .cn { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }',
'#ugf-cal-view { border-left: 1px solid #e0e0e0; }',
'#ugf-cal .gutter { width: 56px; }',
'#ugf-cal .ghead .dh { padding: 8px 0 6px 0; text-align: left; padding-left: 8px; border-left: 1px solid #e0e0e0; }',
'#ugf-cal .ghead .dh .dw { display: block; font-size: 12px; color: #757575; }',
'#ugf-cal .ghead .dh .dn { display: block; font-size: 40px; line-height: 44px; color: #212121; }',
'#ugf-cal .ghead .dh.today .dw, #ugf-cal .ghead .dh.today .dn { color: #4285f4; }',
'#ugf-cal .ghead .tz { display: block; font-size: 10px; color: #757575; padding: 60px 0 0 6px; }',
'#ugf-cal .gall { border-bottom: 1px solid #e0e0e0; }',
'#ugf-cal .adcol { border-left: 1px solid #e0e0e0; }',
'#ugf-cal .hl span { display: block; text-align: right; padding-right: 8px; font-size: 12px; color: #757575; margin-top: -8px; }',
'#ugf-cal .line { border-top: 1px solid #e0e0e0; }',
'#ugf-cal .col { border-left: 1px solid #e0e0e0; } #ugf-cal .col.today { background: #f5f5f5; }',
'#ugf-cal .now { border-top: 2px solid #db4437; }',
'#ugf-cal .ev.tm { border-radius: 2px; color: #fff; font-size: 12px; padding: 2px 6px; box-shadow: 0 0 0 1px #fff; }',
'#ugf-cal .ev.tm .eb { font-weight: 500; } #ugf-cal .ev.tm .eh { opacity: .95; }',
'#ugf-cal .ev.tm.short { padding: 0 6px; white-space: nowrap; line-height: 16px; } #ugf-cal .ev.tm.short b { font-weight: 500; }',
'#ugf-cal .ev.ad { border-radius: 2px; padding: 2px 8px; font-size: 12px; font-weight: 500; border: 0; }',
'#ugf-cal .mhd div { font-size: 12px; color: #757575; padding: 6px 8px; border-left: 1px solid #e0e0e0; }',
'#ugf-cal .mc { border-left: 1px solid #e0e0e0; border-bottom: 1px solid #e0e0e0; padding: 2px 0; }',
'#ugf-cal .mc .mn { padding: 4px 8px; font-size: 12px; color: #212121 !important; }',
'#ugf-cal .mc.out .mn { color: #9e9e9e !important; }',
'#ugf-cal .mc.today .mn { color: #4285f4 !important; font-weight: 500; }',
'#ugf-cal .mc .ev.mt { display: flex; align-items: center; gap: 4px; font-size: 12px; padding: 1px 6px; } #ugf-cal .mc .ev.mt .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; } #ugf-cal .mc .ev.mt b { font-weight: 500; }',
'#ugf-cal .mc .ev.ad { margin: 0 4px 1px 4px; }',
'#ugf-cal .mc .more { display: block; font-size: 12px; padding: 2px 8px; color: #616161 !important; font-weight: 500; }',
'#ugf-cal .agenda { padding: 12px 0; }',
'#ugf-cal .aday { border-bottom: 1px solid #e0e0e0; padding: 8px 0; }',
'#ugf-cal .adate { width: 140px; flex: 0 0 140px; display: flex; align-items: center; gap: 8px; padding: 0 16px; }',
'#ugf-cal .adate .dn { font-size: 26px; color: #212121; width: 36px; }',
'#ugf-cal .adate .dw { font-size: 11px; color: #757575; }',
'#ugf-cal .aday.today .adate .dn, #ugf-cal .aday.today .adate .dw { color: #4285f4; }',
'#ugf-cal .ev.ag { height: 32px; padding: 0 16px; } #ugf-cal .ev.ag:hover { background: #f5f5f5; }',
'#ugf-cal .ev.ag .dot { width: 12px; height: 12px; border-radius: 50%; flex: 0 0 12px; order: -1; }',
'#ugf-cal .ev.ag .at { width: 140px; color: #616161; font-size: 13px; } #ugf-cal .ev.ag .an { font-weight: 500; }',
'#ugf-cal .agenda .none { padding: 24px; color: #757575; }',
'#ugf-cal-loading { background: #323232; color: #fff; padding: 8px 16px; border-radius: 2px; top: 8px; }',
'#ugf-cal-fab { position: absolute; right: 24px; bottom: 24px; width: 56px; height: 56px; border-radius: 50%; background: #db4437; color: #fff !important; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 5px rgba(0,0,0,.26); z-index: 20; }',
'#ugf-cal .ugf-cal-bubble { width: 448px; border-radius: 2px; box-shadow: 0 24px 38px 3px rgba(0,0,0,.14), 0 9px 46px 8px rgba(0,0,0,.12), 0 11px 15px -7px rgba(0,0,0,.2); padding: 0 0 16px 0; }',
'#ugf-cal .ugf-cal-bubble .bt { display: flex; justify-content: flex-end; padding: 6px 6px 0 0; }',
'#ugf-cal .ugf-cal-bubble .ib { display: inline-flex; width: 36px; height: 36px; align-items: center; justify-content: center; border-radius: 50%; color: #616161 !important; }',
'#ugf-cal .ugf-cal-bubble .ib:hover { background: #f1f1f1; }',
'#ugf-cal .ugf-cal-bubble .br { display: flex; align-items: flex-start; gap: 24px; padding: 6px 24px 6px 28px; color: #212121; }',
'#ugf-cal .ugf-cal-bubble .br .mi { color: #616161; }',
'#ugf-cal .ugf-cal-bubble .sq { width: 16px; height: 16px; border-radius: 3px; margin-top: 6px; flex: 0 0 16px; }',
'#ugf-cal .ugf-cal-bubble .tt { font-size: 22px; line-height: 28px; }',
'#ugf-cal .ugf-cal-bubble .tw { font-size: 14px; color: #3c4043; margin-top: 2px; }',
'#ugf-cal .ugf-cal-bubble.new-b { padding: 16px 24px; width: 420px; }',
'#ugf-cal .ugf-cal-bubble.new-b .x { position: absolute; right: 6px; top: 6px; }',
'#ugf-cal .ugf-cal-bubble.new-b .what { width: 100%; border: 0; border-bottom: 1px solid #e0e0e0; font: 22px Roboto, arial, sans-serif; padding: 8px 0; outline: none; margin: 24px 0 12px 0; }',
'#ugf-cal .ugf-cal-bubble.new-b .what:focus { border-bottom: 2px solid #4285f4; }',
'#ugf-cal .ugf-cal-bubble.new-b .acts { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }',
'#ugf-cal .ugf-cal-bubble.new-b .acts a { display: inline-flex; align-items: center; height: 36px; padding: 0 16px; border-radius: 2px; font-weight: 500; }',
'#ugf-cal .ugf-cal-bubble.new-b .acts .more { color: #616161 !important; } #ugf-cal .ugf-cal-bubble.new-b .acts .save { background: #4285f4; color: #fff !important; }',
'#ugf-cal .ugf-cal-bubble .tail { display: none; }',
'#ugf-cal .ugf-cal-askfence { background: rgba(0,0,0,.4); }',
'#ugf-cal .ugf-cal-ask { padding: 24px 24px 8px 24px; border-radius: 2px; font: 14px Roboto, arial, sans-serif; color: #616161; box-shadow: 0 24px 38px 3px rgba(0,0,0,.14), 0 9px 46px 8px rgba(0,0,0,.12), 0 11px 15px -7px rgba(0,0,0,.2); }',
'#ugf-cal .ugf-cal-ask .at { font: 500 20px Roboto, arial, sans-serif; color: #212121; margin-bottom: 20px; }',
'#ugf-cal .ugf-cal-ask .ax { margin-bottom: 16px; line-height: 20px; }',
'#ugf-cal .ugf-cal-ask .ar { margin-bottom: 12px; } #ugf-cal .ugf-cal-ask .ar label { padding: 8px 0; color: #212121; } #ugf-cal .ugf-cal-ask .ar input { width: 18px; height: 18px; margin: 0 8px 0 0; accent-color: #4285f4; }',
'#ugf-cal .ugf-cal-ask .ab { justify-content: flex-end; margin: 0 -16px 0 0; }',
'#ugf-cal .ugf-cal-ask button { height: 36px; min-width: 64px; padding: 0 8px; border: 0; border-radius: 2px; background: none; color: #4285f4; font: 500 14px Roboto, arial, sans-serif; text-transform: uppercase; cursor: pointer; }',
'#ugf-cal .ugf-cal-ask button:hover { background: rgba(0,0,0,.06); }',
'#ugf-cal-edit .reptxt { display: inline-flex; align-items: center; height: 36px; padding: 0 8px; color: #3c4043; }'
];
// ---- 2019 on: Google Material 2
css.c2017 = css.c2017.concat([
'#ugf-cal.editing #ugf-cal-head { display: none !important; }',
'#ugf-cal-edit { padding: 0 24px 24px 8px; font: 14px Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal-edit .etop { display: flex; align-items: center; gap: 12px; height: 72px; }',
'#ugf-cal-edit .etop .ib { display: inline-flex; width: 48px; height: 48px; align-items: center; justify-content: center; border-radius: 50%; color: #5f6368 !important; }',
'#ugf-cal-edit .etop .ib:hover { background: rgba(0,0,0,.06); }',
'#ugf-cal-edit .title.big { flex: 0 1 640px; font: 22px "Google Sans", Roboto, arial, sans-serif; border: 0; border-bottom: 1px solid #dadce0; background: #f1f3f4; padding: 10px 12px 8px 12px; border-radius: 4px 4px 0 0; outline: none; color: #3c4043; }',
'#ugf-cal-edit .title.big:focus { border-bottom: 2px solid #1a73e8; }',
'#ugf-cal-edit .etop .save { margin-left: 16px; display: inline-flex; align-items: center; height: 36px; padding: 0 24px; border-radius: 4px; background: #1a73e8; color: #fff !important; font: 500 14px "Google Sans", Roboto, arial, sans-serif; text-decoration: none; }',
'#ugf-cal-edit .erow { margin: 4px 0 8px 60px; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; }',
'#ugf-cal-edit .when input { border: 0; background: #f1f3f4; border-radius: 4px; padding: 8px; color: #3c4043; outline: none; } #ugf-cal-edit .when input:focus { background: #e8eaed; }',
'#ugf-cal-edit .when .sd, #ugf-cal-edit .when .ed { width: 118px; } #ugf-cal-edit .to { margin: 0 4px; }',
'#ugf-cal-edit select { border: 0; background: #f1f3f4; border-radius: 4px; padding: 8px; font: 14px Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal-edit .etabs { display: flex; border-bottom: 1px solid #dadce0; margin: 16px 0 12px 60px; max-width: 640px; } #ugf-cal-edit .etabs span { padding: 10px 16px; color: #5f6368; font: 500 14px "Google Sans", Roboto, arial, sans-serif; } #ugf-cal-edit .etabs span.on { color: #1a73e8; border-bottom: 3px solid #1a73e8; }',
'#ugf-cal-edit .mrow { display: flex; align-items: center; gap: 12px; margin: 6px 0 6px 72px; max-width: 628px; color: #5f6368; } #ugf-cal-edit .mrow.top { align-items: flex-start; }',
'#ugf-cal-edit .mrow input, #ugf-cal-edit .mrow textarea { flex: 1; border: 0; background: #f1f3f4; border-radius: 4px; padding: 10px; color: #3c4043; outline: none; font: 14px Roboto, arial, sans-serif; }',
'#ugf-cal-edit .mrow .cn { display: inline-flex; align-items: center; gap: 8px; color: #3c4043; } #ugf-cal-edit .mrow .dot { width: 14px; height: 14px; border-radius: 50%; }',
'#ugf-cal-note { top: auto; bottom: 24px; left: 24px; transform: none; background: #323232; color: #fff; border-radius: 4px; padding: 14px 24px; font: 14px Roboto, arial, sans-serif; box-shadow: 0 3px 5px -1px rgba(0,0,0,.2), 0 6px 10px 0 rgba(0,0,0,.14); }',
'#ugf-cal-note a { color: #8ab4f8 !important; text-decoration: none; font-weight: 500; margin-left: 16px; }',
'#ugf-cal .ugf-cal-menu { border-radius: 2px; padding: 8px 0; min-width: 176px; font: 14px Roboto, arial, sans-serif; box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2); }',
'#ugf-cal .ugf-cal-menu .it { color: #212121 !important; height: 32px; padding: 0 24px 0 16px; }',
'#ugf-cal .ugf-cal-menu .it:hover { background: rgba(0,0,0,.06); }',
'#ugf-cal .ugf-cal-menu .sep { border-top: 1px solid #e0e0e0; margin: 8px 0; }',
'#ugf-cal .ugf-cal-menu .sws { padding: 8px 16px 4px 16px; gap: 6px; } #ugf-cal .ugf-cal-menu .sw { width: 22px; height: 22px; border-radius: 50%; }',
'#ugf-cal .ugf-cal-menu .sw:hover { box-shadow: 0 0 0 2px rgba(0,0,0,.12); } #ugf-cal .ugf-cal-menu .sw .mi svg { width: 16px; height: 16px; }',
'#ugf-cal-cals .cal .opt { margin-left: auto; display: none; color: #5f6368; } #ugf-cal-cals .cal:hover .opt, #ugf-cal-cals .cal .opt.menuon { display: inline-flex; }',
'#ugf-cal-head .ib.menuon { background: rgba(0,0,0,.1); }'
]);
css.c2019 = css.c2017.concat([
'#ugf-cal .ugf-cal-menu { border-radius: 4px; font-family: Roboto, arial, sans-serif; box-shadow: 0 1px 2px 0 rgba(60,64,67,.3), 0 2px 6px 2px rgba(60,64,67,.15); }',
'#ugf-cal .ugf-cal-menu .it { color: #3c4043 !important; }',
'#ugf-cal .ugf-cal-menu .it:hover { background: #f1f3f4; }',
'#ugf-cal { font-family: Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal-head { border-bottom: 1px solid #dadce0; }',
'#ugf-cal-head .logo .name { font: 22px "Google Sans", "Product Sans", Roboto, arial, sans-serif; color: #5f6368; }',
'#ugf-cal-head .today { background: #fff; border: 1px solid #dadce0; border-radius: 4px; font: 500 14px "Google Sans", Roboto, arial, sans-serif; color: #3c4043 !important; }',
'#ugf-cal-head .title { font: 22px "Google Sans", "Product Sans", Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal-head .viewsel .vs { background: #fff; border: 1px solid #dadce0; border-radius: 4px; font: 500 14px "Google Sans", Roboto, arial, sans-serif; color: #3c4043 !important; }',
'#ugf-cal-head .signin { background: #1a73e8; border-radius: 4px; font-family: "Google Sans", Roboto, arial, sans-serif; }',
'#ugf-cal-side .create2 { display: inline-flex; align-items: center; gap: 12px; height: 48px; padding: 0 24px 0 12px; margin: 8px 0 16px 8px; border-radius: 24px; background: #fff; color: #3c4043 !important; font: 500 14px "Google Sans", Roboto, arial, sans-serif; letter-spacing: .25px; box-shadow: 0 1px 2px 0 rgba(60,64,67,.302), 0 1px 3px 1px rgba(60,64,67,.149); }',
'#ugf-cal-side .create2:hover { box-shadow: 0 1px 3px 0 rgba(60,64,67,.302), 0 4px 8px 3px rgba(60,64,67,.149); background: #fafafb; }',
'#ugf-cal-mini .mhead { font: 500 14px "Google Sans", Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal-mini .mgrid th { color: #70757a; }',
'#ugf-cal-mini .mgrid td { color: #3c4043; } #ugf-cal-mini .mgrid td.out { color: #70757a; }',
'#ugf-cal-mini .mgrid td.cur span { background: #d2e3fc; color: #185abc; }',
'#ugf-cal-mini .mgrid td.today span { background: #1a73e8; color: #fff; }',
'#ugf-cal-cals .people { background: #f1f3f4; border-radius: 4px; }',
'#ugf-cal-cals .sect { border-top: 0; }',
'#ugf-cal-cals .sh { font: 500 14px "Google Sans", Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal-cals .cal { color: #3c4043 !important; }',
'#ugf-cal-view { border-left: 0; }',
'#ugf-cal .ghead .dh { text-align: center; padding-left: 0; border-left: 0; }',
'#ugf-cal .ghead .dh .dw { font: 500 11px "Google Sans", Roboto, arial, sans-serif; color: #70757a; letter-spacing: .8px; margin-top: 2px; }',
'#ugf-cal .ghead .dh .dn { display: inline-flex; width: 46px; height: 46px; align-items: center; justify-content: center; border-radius: 50%; font: 26px "Google Sans", Roboto, arial, sans-serif; color: #3c4043; margin-top: 2px; }',
'#ugf-cal .ghead .dh .dn:hover { background: #f1f3f4; }',
'#ugf-cal .ghead .dh.today .dw { color: #1a73e8; } #ugf-cal .ghead .dh.today .dn { background: #1a73e8; color: #fff; }',
'#ugf-cal .ghead .tz { font-size: 10px; color: #70757a; padding: 62px 0 0 8px; }',
'#ugf-cal .gall, #ugf-cal .ghead { border-bottom: 0; }',
'#ugf-cal .gall { border-bottom: 1px solid #dadce0; }',
'#ugf-cal .adcol { border-left: 1px solid #dadce0; }',
'#ugf-cal .hl span { font-size: 10px; color: #70757a; margin-top: -7px; }',
'#ugf-cal .line { border-top: 1px solid #dadce0; }',
'#ugf-cal .col { border-left: 1px solid #dadce0; } #ugf-cal .col.today { background: transparent; }',
'#ugf-cal .now { border-top: 2px solid #ea4335; } #ugf-cal .now:before { content: ""; position: absolute; left: -6px; top: -7px; width: 12px; height: 12px; border-radius: 50%; background: #ea4335; }',
'#ugf-cal .ev.tm { border-radius: 4px; font-size: 12px; padding: 1px 8px; }',
'#ugf-cal .ev.ad { border-radius: 4px; }',
'#ugf-cal .mhd div { font: 500 11px "Google Sans", Roboto, arial, sans-serif; color: #70757a; text-align: center; border-left: 1px solid #dadce0; letter-spacing: .8px; }',
'#ugf-cal .mc { border-left: 1px solid #dadce0; border-bottom: 1px solid #dadce0; }',
'#ugf-cal .mc .mn { text-align: center; font: 500 12px "Google Sans", Roboto, arial, sans-serif; color: #3c4043 !important; padding: 4px 0; }',
'#ugf-cal .mc.today .mn { color: #1a73e8 !important; }',
'#ugf-cal .mc .more { color: #3c4043 !important; }',
'#ugf-cal .adate .dn { font: 26px "Google Sans", Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal .aday.today .adate .dn { color: #1a73e8; } #ugf-cal .aday.today .adate .dw { color: #1a73e8; }',
'#ugf-cal-loading { background: #202124; border-radius: 4px; }',
'#ugf-cal .ugf-cal-bubble { border-radius: 8px; }',
'#ugf-cal .ugf-cal-bubble .tt { font: 22px "Google Sans", Roboto, arial, sans-serif; color: #3c4043; }',
'#ugf-cal .ugf-cal-bubble.new-b .what { font-family: "Google Sans", Roboto, arial, sans-serif; } #ugf-cal .ugf-cal-bubble.new-b .what:focus { border-bottom-color: #1a73e8; }',
'#ugf-cal .ugf-cal-bubble.new-b .acts a { border-radius: 4px; font-family: "Google Sans", Roboto, arial, sans-serif; } #ugf-cal .ugf-cal-bubble.new-b .acts .save { background: #1a73e8; }',
'#ugf-cal .ugf-cal-askfence { background: rgba(32,33,36,.6); }',
'#ugf-cal .ugf-cal-ask { border-radius: 8px; box-shadow: 0 24px 38px 3px rgba(0,0,0,.14), 0 9px 46px 8px rgba(0,0,0,.12), 0 11px 15px -7px rgba(0,0,0,.2); }',
'#ugf-cal .ugf-cal-ask .at { font: 22px "Google Sans", Roboto, arial, sans-serif; color: #202124; }',
'#ugf-cal .ugf-cal-ask button { text-transform: none; border-radius: 4px; color: #1a73e8; font: 500 14px "Google Sans", Roboto, arial, sans-serif; letter-spacing: .25px; }',
'#ugf-cal .ugf-cal-ask button:hover { background: #f6fafe; } #ugf-cal .ugf-cal-ask .ar input { accent-color: #1a73e8; }'
]);
css.c2022 = css.c2019;
return common.concat(css[era] || css.c2013).join("\n");
}
// ---- end Gplex for Google Calendar ----
// ---- Gplex for Google Maps (4.1) ------------------------------------------
// Google's own Maps app keeps running underneath, hidden, and does the searching;
// Gplex draws the page and its own map on top. The map is Google's map tiles, the
// flat kind Maps used until 2013, coloured per era through the tile server's own
// style setting - which is how the old yellow highways come back.
// Assets are Google's own (the 2005-2013 controls, markers and logos still served
// from maps.gstatic.com) and, for 2015-2018, the shapes out of the Google Maps UI
// kit, inlined so nothing depends on them staying online.
// (a function, not a const: the page code reaches this before a const this far
// down in the script would exist)
function ugfMapsArt() {
if (!ugfMapsArt.c) {
ugfMapsArt.c = {"logo2005":"data:image/gif;base64,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","logo2007":"data:image/png;base64,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","logo2010":"data:image/gif;base64,R0lGODlhrwAoAPf+AA5bFQByDAB6DBVkHhd4Izl0PTd2QTpzQLcLJ6kTKaEZLZcwPMMNKs0NLMsSK9gYLs0UMNwZMeEYL+IbMcwmNtgrOOknNuo0O/I1OLZwLt52BOJ7AsRzJaM4RM82Rew4QpNNUq9RVqR6TbFcYLhucKV4d9tLV91PVPVGRu5TU/ZaVvZiW+BeZ9NtbfRsZupzcgKEDgWJDweNEwetIgmsJAyyJRW6KDicSU66Vkq7X029YT3LTFTAXVfEZGLObOqLBeuVDO6YDPOZBf6sBvqoCv+xDfmtFv65GMmGNumcJv69JPC1N//CLP7GOLmQWrCYdM+WR9amUO27Tu+Be9OzevvISPTDVfXOcwUptQgstg0wtw4yuBI1uRY5uhs8uzJEmh9AvTVNriREvihIvzJOulZlmWhzl0dbqERctVVmplJpuVVruGl4qmN2tStKwDFPwjNRwjdWxz1axTpbzDte0j9hzz1i1T9m2kJexktmxkRhyUtmylRvxlJtzFlyy111z0dq00Bn3EJq3Uty21h41mR6w2V80UNt4kp25lN94tN+gnuDl3mFp22BvHmItn7Wi1yB3GuDy3eLyX6RyWyC1GaF2nOJ13WL1niR13+S2ViG6WeL5GiT7Hma52WW8Hih8JCOkpmXmKuQiqSZmLOomIqSpo+XrIuWtJ2ir6SkpaGkraysrKaqtqywtLO0tLi1uLy8vNeHhsqSj+2Tj8qqj/imm8+tq8i6qMS8tfOvqOi6t5DZmrHTs9rBk/TYkcjCu/LPtvbirYqZxIKU2oOa2Yyd3Yyh3ZKj35mr2621yYKe5oil6JWq5Jur4pWy7qGv46Sy5Ky45qS77bG96Ke+8bnB07rF6rLF8cTExMTGyczMzM3RzsXK1tPT09PW39vb2+jIxPbSzc/o0/nt0Pbq2sTN5MTN7crS78vU79Xa5srW9NHZ8tXc8tje897i6d3i9Njj+OXk5OLl7ezs7Pfr6fX06+Lm9uXp9+fs9+ru+e7x+vT09Pn49/P1+////wAAACH5BAAAAAAALAAAAACvACgAAAj+AP0JHEiwoMGDCBMqXMhwoLhdux752MWvocWLGDNqHKhPHTVny0JKs9Zu38aTJ/nx8rFjhw0ZreJVREmzpk2B7JYhQmRIkqRIfgIh0rRpGbqZN5MO5DcvHo6XBVx9Q6q0qlWC93QSOuXqFSxs2GC1cqRHUKJBlcpRvYqS3z4eNmJEjce2blV1ng45WvVK27d48wLH6/aqDZ05cBpNtVuzR9wDsOYxnowSryBGqbB927eWabdGZMqk6maS8kbHMSBLNs26Iby8bUJhm7eWID9JbFLBktk6I2rVvYMf7PcpkR5QuxfyS6dNG2/hFn9Hhk7d3zVNgnIvVj6Ps1J+5Mb+iSdXW6NjGMCrB+/XSdOcRdNr8gM2y4UKF7N0lUZYz1eVJkowUYUv5CWUjznUSKOgNCApY809/pyX3kD01PKCCiu8kAs95al30jqaICJHKN10eBEwGMpiiywsfIBCCvodFAwTUtzyCy5UHKGEElfQVlA/0myySSWHaBIiIX0Isw1tPdSAXnz+8JMLCi/YYksLKLwIzn4H5YOPP/1YU8wwz7wzUDvNDFOMNf0YpI+YakZjj0H39MPPOccMc8w5tfVzDjPDEBMNhAJRo8khaKTyTU21oBDLV9p0o40sFnxggSyrDXQFE7S8gk0333RzixFHHCHFc/68w0kl1WSTDSv+gAiS3SqwdCNZk0+uxs8sKNACSzaSymJpBdpwWZAhe5zThxdddKHFG2weMwazXHBhSD4EmaMHF812wYUbzyD1jhuZUMKst11Ygu1A91DSbRdbwDGNQMtgp8YqdKGUiwotrIJNPPsEHE8LFlgQgS2Z+tJEFKtkAzA/TPVSxBFDUJGvPpwcwgosf8WTTCCC2HGKrRXpUIMA6e3br3MCnxABAyNsZ1AfXMCxRzTvoAlGHJSIkck575hjCBbHDLSOG2Ics4497EAjRxfWnMmFFm4Ug8471vyRxSUz8XPJFpeY8846x3gBhjn+cJKIIGq4ku9G4biAgSivoOpPPB4Y7EH+if6MU8URT9Rd0D5LFDEEEL+Y5IwmfIw20z6XHBJIHsUKpMMMKE9HjtyiQLmPCQgkAAI2xg7UBxaGfDlQMVh4Me9A9rixR5v+UMJF1AStI8YfM7XzLdoc/dEF8PeMYQhV0GRx/CaICJIHvinNokIFJHYWywQSMCCKTFc0EYQolRfkyxBD/PDEN/mEuAb0A5UjeRys5JsD5sDlssIFo/BNzywWeFBCKKsgDUL6IAYzZQsLw5iZG9rED2gcozZ+WKBA2rGFBBbEHFzIhEDs4YVLFCQfcsBDPpgniDmo4m0ZoccKUECBUSzKIODAHsy6QY4qMAEI+asNOYhQPiRoA0T+iMiDKzLlj3wgIhBwKMUL55c5yUxBBfj7RjhecAEW+AoWfvHRQfoAB9oN5BxZgIZB/iBBgvTjHva4hz78YQgxrNEfFCyGm+QwO3/oQw5uOEdB2NEOf3QCEYeggxJPEo4UYKCFKBxIPT6QvQ5gY0ZKAIIoZLaUJZSPA7Aox070ED/baOIOZKieP5gInBVWoAQtYEEscIENYD1MIVz0okDA+IwxltEf9yiGHsTQBTHwLA5unOAW5GjLdUGDC2PIhDnWNRBoHOIQd2iDNkwEppy14x3vYAc67qELFGAAAi5EiAkigIAFwCIYSjgCEJ7AN4NY4ZKuSMdOAuEISm5iDmf+UJRASDmdFFiqBH6J1De0uJBYFoSWtqRdO/SwBTxQAhOUICAWxvDGOB6EEmBQHT+igYdqvYESbBLIOgQhOT20gohmvAYhBDEISGhiEHSYhDd0gQEMPKAElBwIC8gJglcAo1RBcMI0D3KFIWwgA27DxDP7kI396OMQZFjEK1bDT8msAAMWCMG/ukPNghiUIAgtCBkZaAguNOONYLLHHoIJx2FeNKMEeRMx9gAvQ0CIH5UA2R0UU557lKMayXBFJABBBzKoohvgKFgEQhC+grDgAaKDBTmUUAQiIIF0RB2CBkQQmXQAwg6CoMRi+LGMOZTCcfuk33SmgFUKTFUjX/3+YhZqKVYJvkMMhjhIGyvqVoMYwg3MNOM6KLG1ikzDDncIhB2SgdKB7CMe3/gGJgIRhzCE4hv0OIEFJuDa5vrDBA1QACi0UY8rEIEIQCBFIgVSBSFoYLyc4cYa4kCHRDRDGpwQBCpW0diq+kMXBZtAzLo6sy4edLYJ9cc6tFA037KVgsYwSD/wUEd7WCO4YNqDG760j0gg9w6AqEbpogQxfhgDENVNBV108YAIPIAEOaUHTxUFniAIgQhQaOdSirABEdDYH/v4BisY4YhKYGcvAhxIDmjQRCCbYALbxVRGYjtLBNe2Te3oggZ/REDeUsIg69CyQJjRhWgYxBJemJP+P9KRBzokdxDcGPFATpxiuuyjBQ54AAVuYaxZMGABspEMP3rxAyEIgRaJvMIPOBDopQxGG4RAxB3YACXL0QAGBoiPLiDwgAlMIBYopQc9EkJlf4SVIGO1oxzgYECB9KMYWRjDunzHBTEOpB+GGN4su7AH1QkkH3iQwxv5wQ08xAG0g0CGdwViDDuQ4QsqFkg8QsAAB1AAF/vJRQM6EIq6zWQeVNhAoamgqysIAQmp8HZB3ELCQAgDpTeQQQAIsIrNAFkW1X6ABEwwC3CEQxcvmAVBvWpgsGKBtqgeA+2gsQU9ROOa0/CDt8RAKN+BwQuWEJvQtMA1gfADE1nYwzT+sGkNP2yhGQTZh3zJcGxBsAofa+nHJeDwBWjnix/xKEECGAABE8RCER6AAAloRcl53AIJGxCCEaQgBSMkgRau2E2HyiGIO8hqGFoUBwEAwPUB3GAbEJsHKRSAAAQwoAFoh4AiumE3giBLlgoWg5kLQgk80K4fxxADt7zlhmNYAg59bGsmiMFLdKkrrsPwwt65IIZiwD3IpzgDGeAwBzughRjHOAYxKjEHMqTBDFJ9G85/IYoQmH4EosAFFtvuj3l0gxROgAIUokALVrJ9Le+gRic2QQhjzwFklOANzmGRilS4QjOrmYc2RAGC5oOgBLSylYF8vZQ6uYn6cHzGMIb+AQ0znbF3W4gwO9J0DHOUZ/zbf0bgDYJzbaDCDGU4wxnQgAY1tMERp2DFK7qiGWM9txtgkQ2R8koHwRSh0hygAjAFAQ+dcAh/IAzJkAyvYApoMAd3YAeSwBvPFQ8cCBhI8VzaEBaQYm/VYVFW8X/ZAAuusApdASkJyFUI4RaB4R0MATEBQ4MEcR2AwBVYBCrfkA1tMAd0EAfMZREyOIMENhkmeBUy2IEciITCASJ3gBkOwxk2+A1+QAdJ9EIeshHtoAXE1IWTwR6JEAegMBvsxw2FtQg6JoYX8Q5jgHJuyBj4cBZxcF3lsQ+AQAbjlYRziBVw94dVcQ+DIAh0wAiDOSUQ+EAH+dSGgviI1NEPw4Bce5AMI8YMSeQ2kLiJ6uEOeVB5ySYPSIEPyxAHXJFknJiKvcEP3dAGk0cHggAJlmAJhFAHhdAKryB9qriLrRFkQ5YGwLgGbXAKrfArJMiLyEgZBpiCr+AV2JBFfpiM0igf+yAYUDiN2JiN2riN3AgdAQEAOw==","gcolor":"data:image/png;base64,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","ctl2005":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAAHKBAMAAABPsi6IAAAAHlBMVEUAAAAAAAAAAAD///8AAADMzMwAAAAAAAAAAACIiIjJW3aNAAAACXRSTlMA/xT/P/8VVjF43DyDAAAB60lEQVR4Ae2aNZIcQRBFSyxzUynyhAdQRkYfQGiL2l++woy5stSeyNJt1ayFql+xMPz/UkW/KHhFSxP+R/rcC9God7n/FOEih7eTWCE2gVhVATZXA7h9ywxtYdgvjssuCSx9Evjluy5v4gt6/bDLbsgmssNipWM7LFY6tsPGWRtwcRxvj3j72ATp8YeqOmAdsfmATXzANmIdcPvWY9cemw/YmkoDth5LnbaOiLrIgwYPz/K1cd945HlvPGsYjzssVjq2w2KlYzssVjq2w2KlfJb9Xps9bt/wrXjxO9VNeK+tQHgMpI7Ot28eg2syRViLR0eLwSJaiDxODdtdC3VL1L/b1X6Uwt8ndd+TaQKHqqpxVdGb3vSmN73pTW9605ve9KY3velNb3rTe2O8t7H3Nvbepje96U1vetOb3vy5Zb286U1vetOb3iXE32SKcDWpAsjd6mj5X1O0bFjq6MKHtv6vKbomfbbj2LvYB4g/fdi+EDapA2qXdb5csPGibNNi4B3Ht9/1OYzicDgkjm83zxscLhCvY5rEpqbE58Zbpu4AD6VZYCU+P3bHGOVVEJStHM40/rfLzxDPH2+DcTErbBi7uiFsGLtibBj7L4RF5MLeZZsUxiu25Asqogj/wbUNY1eMDWNXLGYLWdB/d8AHLcFSGSwAAAAASUVORK5CYII=","ctl2008":"data:image/png;base64,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","ctl2010":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADsAAAHsCAMAAABbtyWiAAABtlBMVEUAAAAAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEFBQaSkpLFxcXe3t7t7e329vb7+/v+/v4AAAEAAAGamprV1dXw8PD///8AAAGtra3k5OT8/PwAAAGUlJTg4OD9/f0AAAHHx8f19fUAAAFkZGXd3d0AAAGBgYHm5uZ/f3/o6OgAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAEAAAD///////////////////////////////////////////////////////////8AAADz8/PCwsKcnJyDg4PBwcHv7+/09PS2trasrKzY2NiPj4/Kysri4uKwsLCbm5vl5eXv7++ZmZmZmZmZmZmZmZmZmZnMzMwzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzP///////////////////////////////+eBLcZAAAAknRSTlMACxUdJSsvMgwaNF6FqMXd8PsPIGKZzv8ecLLzFl+s9giI3A1KpQ5Vt/+9CQEXESMCIgMpBS4GMQcsJxkkLSYEGyg1NjQ3HyozEhgQMDMgcIBgEPDgkKBQ0EDAMLAa/////////////////////81N/+33+/8g8FC/QP9wENDfbz8wkM/vgODAr3+/328/z++vf40zoAEAAAY6SURBVHgB7NaFlqs6FAbgASqUsTrUUx/BGiznUHd9/8e5Ro0mZch1+5dUv7X3aiP74e8VhuUi0Vg8HotGOJahgHxCeHx6fnlNplLJ15fnp0chwYeT6Uw2lxd9yeeymXSIZqVCsSRiKRUL0letlyvVmkhMrVopB0kg1Bvi3TTqArhLm622GJh2q3mHdrpvoj/v76I/b90OuWr3A6MY/uiSKn+23ggUr9z6xKgstIkUw21BvrVKnUCJbdeVG9qsNEiUhBuVpr/jTBUreyR44WrG17VawFbTWbxjK6ygXpfViiJFitpV4U62RGNL2c6lLJcTqZLjzoV1IU9n84J+sulHkTKP6VPLiaeA5U/85ClxbFrvPQcsf+Inz71j09B4CaBE/GJAz5rWK4kG4VfL9KztJIMpjpOO7VkUTwVTHKfiyLPg11hwtL+m55ON0f9WsZP9Rv8ffTta9J1+bXxHnrV79GuyZ3vWdOn3gmt6Fqbp92AaelZnDNq9bzC6Z2Ug0Z45EjgdHKZq0Z11lmqezxy+T3fG9nn9ZGXExmjO9hiLLocsbGo0d4rWhEfoFR6Ev8sGx7LHQJ4Lf4dyPPTdZbY6DHt3D1XbfwProBwNNzNEy0B/8Acy7iDMrDJwGYjNDKPmePD1jDQYN0fyA4bNn/BXs9lP1MSoh93JNGgmnE5cAj22zZQ1Z3ZvFp05WpkhNHzEEKicMV+QZuDF3OBUAI+UFN3m2eVqvbidvRfr1ZLlbR0XvtKoyUpDa7pYLGbz9Xo+++nJ1BpKbBORimKaVxVJm0RjTjzuxKITTVJUnixxrZuASW9YZeu6W4XdpBlg6mRJ5tC0EfgpyDYhDv8PfeS1eJO1HNZC3MKw1satHdYC3IJ/v30/5o+39D3/b3e/waYnOT/NTUJbfrtf+7LforAWdaRo/CLjUakzCmsh6rBu4hyX7SA9/Dk+QuAqaPRPPssPonj4kX05JAAAAAAA8v+1I3Tv+77v+77v+77v+77v+77v+77v+77v+77v+77v+77v+77v+77v+77vi5u7NqwgBmAAmi00lZlh/zU+KdTK4egY3oGh9f+x1nkf4pH1uCcF1ZLmUhPQZGuBetvEjixbBxoLDNV6FO5MeN1W7nQ41QakeN8uYKk2JnR7ox1dr6MAYHYAxSqWaRm39IK0JMsM79eTTcSiZRbxgSXeJ5Z4j2/rv3if77QcV4Qb3d4U16olI5Ut8Y2eWZB+y3v1/9XLWa/f72+T/78fXdm5CxzHwRgKwHdY5l2xLJWZKypfoczMvf/G5T95al3GN+zJV0wsi3w7SydYxnScZXyC/XrS9UsP/f66viWVfHOhGrSmuH67RdyEatqhue2wtRm3athQDd1v1HhcFNWQ9RmP8y1q+UKxVCxXljVg4RaRea1aI069sqgdZBvUbLVbTSorlrTstx1qad9bVNRZw/3SMlu2S23te5tKqv1KJ9ivgsfMlhbRvVYksj3i9A5+nTmMmR5hGTM90nJOtyD/wIYZVEPWBzbMoBqyUbBhBtWQtYENM6gm3TBzX1tnLJGkkohFTE2R/lcl/YhJamHz3JHBYPO7y2hdy38NtRjoaLjBPmOT8K0sf+roUMtg31qm4Tp6ylhqFargf3796+yHlul4VZossC/uTSrxxn3QcnQlV+ajf5v6P2Zcu+zi2yK2f5lf2xfIr8w/m9SabC71AnHZTAIrD7Cn5x3hbIYins1AxLMZiHg2A0GzGart3PBGtG4HqHZXFsxXqHaKfa7XSj4j3d7i2Uxq0RwmtWgO0+xUCbZwNpPeL5rDTtza+N4GKuz42KKOL33Mso6PrazjYyvr+MjiDnMvFvcD/M7J+gG2sn6AH7OsH2Ar6wfAPvtVfcIOWPiuwwjfdWFsD7wDdva/HfoqcCCGoQD4WIiV0osTHO52eu/L+ExB+r0dCOM8tGyIUIvQSxFKuaSUnIVcqRubtrs9FA7HgpRjtJBzHjilJuqfzpcCqeMZjU3leLlCyLsI2HqDvVtI3VO9plCgYrf3PbR4soAWPwzUDPTIQGkwJqIJQ268fDK93msozD5j0MAYhtxkAXypMfqn4XQMqc8QDdP4M11BaDExAC9/4I4h1dFyRY8xVPjVrdHr9f6LP7f8WeQNZqeMAAAAAElFTkSuQmCC","marker":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAuZJREFUeAGllgOMBVkQRce2bXPtsW3btm0bwdrRhmszztq2bW/X3hr/9OSrb3JGr/vMU1W+hpy4gzqwC245Yh80Am+gdIzADPjaWFeXLnO0pzx/b8oHVzg5kImeLmHsO7AETIHceILnHE2MaS3mKvq0tUqgkQ6BJrqJ4Z8/b6sWduIiyNXUhMWvggBwbnzAJ4kervRtV51AU71Eo51EQ22yjHYQj/3Y00hZPp4s/QqEAJkYgueTPF3pr6F2ojGRSAye+RfyHF8vlr4BzMBJppyxzK+7GwSRTB5YwY99zYKXhRlL145ljuDjzfhreCmKJGLwznUpscSHCDxZWGKkq0Ofttfwpss8/FlbNU1dfSkF2Vgx/DP/TVaId77FyiwN9Flaz8L1ix3szj0AFmBcBvxNPMvxLop0deLxbRbenOnriWvRI3oQsxIJ8TexcLKHSoP8iF0HwiycFP4oSVgW7H8i3LzEUeqSuynKzZnHd1hYyiX2WUetmofSTt/1nBxKAwudwWd7iVHqXRss9+a0eJZ9C3zAQaZdcLG/7WkUREuXByrl5/4WwcfCnIXr4CQm4LVsnPa/aABHS5cPlop/Lhyd7nvACsjEH3xWEuiLOu0iGm6XL8RBNIQHsewbEAbOzUXgp5lrLsfe9Mott92ESJb9ASKA3BRp4no8UZbLPVAsw+xfaSgTjHR0WNgKlMrtIbbW9MdgqyBaOoSpXu4sexwoHQ/w41Z8hGwFYd/uK8xgGXMVUCmrnuhzvw+0nMySm0CipxvL7gEqxxX8cldOCu/lQWm+1lBGWpqaLEwEauVObhws5KXPRFzOspeA2smxMjCg77sbiJd7mZM9C+ekCG3Aj4+XZNM3XfWkr63NwiuBpDyzEXsNPV6Sw7IvgLFU4XZNaCAtRV/JwoeB5DREuDrxxxEWrgPJSXQ3NyU/KwsW1gHJuUhPW+v4QBKA5PgCARC4HEiOHfgVEPABkqMP3gafAHMgN/8DJ6wYsnrivNcAAAAASUVORK5CYII=","markerA":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAzdJREFUeAGllgNsNlkUhmvbtr1Wzd+ubdu2jWDtYG1746xt2/bO+d9TTHG/VPMmT3nnyUHnpmrbxBUUggVwHWCWQAnwBLuOAegH3xhqa9OF9rZ02teTzoCLHezISEeb8LvvwSgwBtvGHTxvb2RIkzGX0mcVuRK1V0vUXUcMf/1FZZ40HxdBzsZGLH4N+AGV8QKfJro503e1hRL1NhB11BC1Vm6mo5r4dz/Vl9BxL3eWfg2Ctsr0wQtJ7s70d2sVUacoEsCZ/yA/6e3B0jeBCZDT64g2v6krllTJ8oL9yM3UWJSig58ayyQPMxOWToLl2INPZuLDuRXhoR/rivgwhdlY0Z2nDopSPHPFwVjiJQJ3FqYbaGvRZ1X5PHThgb7wC5crvPZQHEW7OIpCPPMdOjPX02VpEQunzrOzUb0AwK0+mX5iuVIzXV36sCxHPNdVS5HODiycY+G1x7zdibrrhYPcIgs3zrLu/FBR2FNPGQE+xK5l4XFsinpE4Qn8nGfHbTP4nqtUKcwM9JWFM+fbiy1za/gdz20jLOR5bmm5jqLwO5yfZ2EGv2KfVxdsXAq3xhUJ1czGhXPVG5ZSRd/Xy0spZqEj+HwxMWrjn82WSsTKX8xPldu99nA8/+w74AWW0+dkZEjf1ZdIaJ1F4qy2zJYXxK/hL03lkpeZKQungBwj8PoJbPs/XABy69uAVnnu0up23wcWYFN8wefp/t5EnbVEbVXbC7GI4tAAln0LQoDKnAt+7g+/CLOR5ymCWS8kRLLsTxABtk2qOob+ZOYpvgNFGap/tThTMtDSYmEF2FVuDLK2pD9bKiS0LggPebiy7Amw67iBn2bjIza/QZjb/SlHWcZcCvaUCXfcc380l8tV8iWQ6O7CsnvBnuMMfr315EGe5fKr+XpxJmmoq7MwEewrN/PFwUJuvT/iIpa9DPadkxZ6evRDXfFyuxc62LJwUInQCvz0BC7Yb2uLSFdTk4WXAEV5djo2nJ5IP8myL4GhUuFcfrA/jUZfwsJHgOIURzg78L8j8o2iNImupsbkY2HGwkKgOOfqaGqsLSQBKI43kACBi4Di2IDfAAEvoDi64B3wKTAF2+YsILoXRwAxlxYAAAAASUVORK5CYII=","markerB":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAyFJREFUeAGtlgOMrFkQhce2bXutMZ9tjW3bNoO1g7XtjbO2bdv71zs1uEmblXzN6i/3XKVN1FQwKAUr4DoGrIEKEA60LjswDL6xt7SkC3296WB0OB0CF/v5kIOVJeG778EkcNQkCwXP+zrY02zWpfRZTaFE3fUS9TcRw6+/qC2SlnPSKNDRgcWvgRhVsgjwaX5IIH3XWCrRYAtRTwNRZ60sPfXE3/3UXEF7I0JZ+jVIkJfZghcKQgPp7846ol5FkQLo+Q/y/ZFhLH0TOAFRg/6I+U1TubQle/L4Pm6UIcTZka7dkSOknOCn1iopzMWJv5/dkvmCTxZyUzkKN8oI8SwYSr1QfCak+M0V27OJFxGEsvC4naUFfVZXzJMuL1SImhnkz2Lxnn/zHZK52lhzfxkL587z8RILoE74Y1PZeuw7D2yX+Zz6Gik90I/7l1h47Z7IUGyLZqVCjEjgYm1N+7AICgs00Ewn4qKIXevCvdw0oFyIeIKixBj+jBdGQXgyPloIF8731S4ys5iTyiOVi9xEGUiA/mUWnuAj9nl9iVaLgvmT/by7jr5vFotSzkJ/8PlqfobGbcOyFC8Pji4T99qdudz7HYgA6zUUgI39XXOFhOgqNzaisoxXWxzDX9qqpQgXZ/5+DohyAK/vw2r/hwtARFcDovK8S5ur+z5wAzIVzdGPx0binDYSddWpF2IhypPjWPYtSAJK61zw83DqRZibFtUyzPVKXjrL/gRpQG0dNeXFOHmA70BFGUb/avlJyc7CgoU1QKu6McHTnf7sqJEUokO4IyyYZU8ArSsE/LSYmyZ7gjBv9x/ZzTLmUqBTzYTinvujvVqMki+B/NAglt0LdK5A8Out+7fzXK4fzdfLT5KZqSkL84FedTNfHCzk6MNpF7HsZaB37XezsaEfmsrX417o583CUUOEHuCnJ3AMv20sI2tzcxZeAgyqZ+ezU+mJ4/tZ9iWwN1S4VJwYS5OZl7DwEWBwlacF+vHfEXGjGFr5wc6OFOXmwsJSYwjPtTI321qQPGMII4EECFxkDKEX+A0QiDCG0Bq8Az4FziYa6iwbowJxCQwSeQAAAABJRU5ErkJggg==","markerC":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAytJREFUeAGllgOMP1cUhde2bbvWmn+ubds2ajuoHdS2G6e2bdud23OKl8x6d07yrWbel7n4TdZkkwSDNnA+uBKQC0EnCAfbjh1YAZ/bW1rKkb7eUhYdLuXgaD8fcbCyFFz7CpwCHMGmCQVP+TrYyxlZx8qHvU2azAxosjAshD9/3NesnZeTJoGODhS/CGI2kkWAD/JDAuXLoTZNlkZFZgdFpvr0zA4Ir3070ilFEaGUfgYSgC624OmC0ED5bapfZE4veqalSh6pKZZvhtvV33jPn5CXRIZR+gpwAipL/ijz8+EOTcnALaV7JcTZkQcUw4cnq+us4Nuxbi3MxYnXzgD/xBe8f3ZuKkvRySg4JydVPdkV+3LExdpallOPVPfxzMV7s4VDBKEU1thZWsiH/S1suroRT6Y/CAj/luLloX7nmS9RmauNNaXtFJ55mI+XbgDvdDfyInvH37dmfkjSA/145lwKryiMDMVajKgbOAAKtyUjiyNSGxcldP0jLMKk8EdDwrr4aCU8+3BffckYwqYlYzj6FZoflowgf545j8JafsQ+GmjVDYWN1w9FyXhQlHCmX74aUUPpoNAffHRBfsa6awPp6rXR7yLKvWJ/Lu/9EkSAf7IcgMX+cqRTE1W6Emyy2APy/XiPFuHiLNwWoOIAXirGtP/ky0CVroZEdH1Dqey79t903wJuQJdo8FFNbKTI3JDIdP8WuzcsHclxlH0BksC6ORR8t5J6FHozurEMvT4/L52yX0Aa2DRVpujVI3WlfAeuleHpX+io0+wsLCjsBdvKNQme7vLLZK/G0lcL94UFU/Yw2HZCwLfn5KZxLXR9u6vyIGXkWLCjnB6K99zPEz3qKfkSyA8NouwOsOMEgh9uKNkr7CX386WOOjEzNaUwH+wq1/HFQSFLX0k7irLnTAykxM3GRr4e7hCWe6SfN4UnGBF6gG8fxqfki6F2sTY3p/AYYChPnJWdKg/XlFD2CbA3Kjy3JTFWTsk8hsL7geF0pAX68d8R9UYxmvxgZ0eJcnOhsA0YzqFW5mb/DyQPGE4k0ICAo4DheIEfgYAIYDjW4HXwAXAGm+Zv4+sVIZTLtRkAAAAASUVORK5CYII=","markerD":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAwxJREFUeAGllgNsPXkUhWvbtv23Xdu2bdt2G6wdrG1vnLVt2965e24xyRQvr52TfMXgy7voL1VREGdQApbBtYBZBeXAHSgdPTAEvtbX1KSjttaU4u1OqeC4nQ0ZaGkS7n0HJoAhUBhX8JytgT7NXDhJn1YXCNRVJ1BfIzH88+c1hcLSpTPkaGjA4leBz24yD/BJuIsjfdtQItBAM1F3PVFHjZTuOuJ7PzaVU4KHK0u/AgFAEl3wfISrI/3VUUvUI4p2B8/8C3mSpxtL3wBGQMyAPcr8urFM2JSdd7LnByWEWFnQHclRopQr+LGlUnAzMeL7M5syW/DxfOhpLkV8mIWFgT70RFaiCP/OYokU71wedZF4iMCVhVl6mhr0aW0RN10iHDx9dFupjYeDycXYUPyd3/kWlZnqaLO0lIWzh2ysJANQJPygMp9fJP4uXu9toLOOdnx9kYXXxHu6EvU1KSVkWMgtEK/1N1G2nxexa02Y4OmGi/KEOf7eonD+sK3yJb9QlLFDyY10bn0rlliYzX9in9UVKz0UXh8Sh1JL3zWJQyljoT34bCX8nLJrs63ca2JC+fq3wAOsZdABi/1tU7lA3bsvNl+TLnYd/dxaJXiYGBNvCxBjAF5LxLT/xQEglq4AlMp9Fzam+x4wA5J4g8+yfD2JehqIOmsVCzGIsmA/ln0DgsCOOQh+Gjp9DL1p3l2GXi+HnWXZH+AMUJgMVW58TjKfgdtl+PSvlOUIehoaLKwGSuWGAEtz+qO9WkDp24TRbs4sexwoHRfw40LoGV4LSd/uS49jGXMS7CnTrjjnfm+rEj8lHwLhrk4suwfsOY7gl1uSooh7yfv5WlkOqamqsjAc7Cs38cHBQi596Mwxlr0E9p0kMx0d+r6xjLjco3bWLByRI7QAPz6elUjfNJSStro6C08AWXlm7uJpejwriWVfAH25wsWiQF+aOH+ChQ8D2Sk742jH/46IJ4rchDsbG5KXmQkLS4DsHNRSV9scSBiQHU8gAALHgOxYgV8BAQ8gO9rgbfAJMAYK8z90mwmrFWbGBwAAAABJRU5ErkJggg==","markerE":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAu5JREFUeAGllgOMLVkQhse2bXPtsW3btm0bwdrRhmszztq27eeu99egk5u+w/6Tb1j9pevUOSdX5ZA4gyqwCe5hwDaoBe7g2NEDE+BnfU1Nus7WmrK83Skb3GBnQwZamoT//QbmgOFRMlfwmq2BPi1F3ETfNpYJNNAi0Eg7Mfzz903lwkZUCDkaGrD4XeADlMYDfBPr4ki/tlUJNNZJNNhK1NekyGAL8f/+7KilNA9Xlv4EAoBCdMHrca6OdK6vmWhIKpKAmouQZ3i6sfQDYATEjNmjzZ/ba4R92QsF6VyolHAne67Z6eDPrnrBzcSI/760L7MFX69G38KtcKGCEN8lvFGRJ9bxM7clRBIPEbiysEBPU4O+ba7gRZcIj2wdz/yKzkx1tLm+moXLV9tYSQZwbCEz3EahjnZcv87Cu1M9XbEtOpQKsV4SFFpmRjuo0M+L2LUjTMOk8EelwvFbrpPwRX2pRFjk7y0KV6+xldtyO4XhzVG/wcJCPmLftVSecijN9FuHOJQaFtqD77Ziw469bYBCu3cnRXPtr8AD7GTcARv7145agQaP3thAPIZ/dzcIHibGxLsFiDEA76Vj2hf5MuDWj26V113Ym+5nwAwoxBt8V+DriXPaRtTffOQgaoL9WPYLCAJKcxX4a+KW67E2nQfLsNabMaEsOwNCwKHJU+VhFGXyHSiV4e3fqSkS9DQ0WNgIjpX7AyzN6UxvoyBpHcJEN2eWPQ+OHRfw51p0iOIJwro9lpvCMuYmcKIsuuKe+7+ngd9SvARiXZ1Y9gg4cRzBPw9lJPBa7hzN92qKSE1VlYWx4FR5kC8OFnLrEyHXs+wtcOpkmOno0O/tNTvtXmdnzcIpOUIL8OfzOIa/tFWTtro6C28EsvLKSuQt9HxBBst+APpyhesVgb40F34jC58GslMT4mjHH0fEG0VuYp2NDcnLzISFVUB2rtJSV9sfSAyQHU8gAALXA9mxAv8CAh5AdrTBx+AbYHxU8WUYrAwxlxokGwAAAABJRU5ErkJggg==","markerF":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAu1JREFUeAGllgOMNGkQhte2vTv+bdvm2rZt2w7Oji48m3HOtm37uv63Fp10xtNv8gyrn3R91bIzkVhQAObBrSssgmKgAhbHA/SBbzydnWlXeCgl6FSUCPZEhJGXizPhv+/BCPA2J1OA58O9PGni6D76rDxHoLYqgbpqieHPX1TkCnPHD1K0txeLXwNrgMGowaen4qLpu5oCgXrqidqriVoqpLRXEf/3U10xXVYrWPo12AAkcQcvnFZE098tlUQdEpFhUPMf5Fc1Spa+CXyAmJ5ItPlNbZGwKnsy7QoXGoT/4xru4KeGUkHp58O/T6zKwsEn0ycOcCtcKBHiXY8fawvFOt7m+rPHiIcIFCxM83B2os8q83jR9YRmW8c236EzfzdXri9k4eT2sBBxAFYLmc4aOhQdwfWzLLzlkkZB1FVnUHgkJlLCLeeO6wu76yh9nZbYtSS8rFHiR8PC3gO7JOB3g8KM9TpROL0jXG7LtXQYe4/6ORam8yn2eVW+jUOppO/rxKEUsTASfL5w6jAfAtYL0e4t509w7XdADZbSG+XlSd/VFQto3XIhzpRfGssEtZ8v104CMV7g9SuY9n98MeDWzbfK6y6sTPd9EAAk0YHP09ZqiDpqiForzQ6iaPM6ln0LNgGD2QZ+7juwm6i73rgMaz1/8hDL/gQH7cwkxZ7P4Yx4vgbqy7D3rxZlCB5OTiwsBxbljg3BgfRnc7mA1vWE55SxLHsCWJw48NPMiYPSMwjrdn/yRZYx+4BVGVfgOvdHUxnvpXgROKWIYdm9wOpEg1/vvnqW13Lp1Hy9KIMc7O1ZeArYlLv4wsFCbr3v4G6WvQxsztUANzf6obZoqd1dEaEsHJAjDAI/PYHT8NuaQnJ1dGThXiArz04dO0BPpF1l2ZfAU65wNm/jWho5speFjwDZKToYHcGPI+IVRW5Oxfp6kzbAj4UFQHa2uTg6rA7kJJAdDRAAgd1AdkLAb4CAGsiOK3gHfAp8zRVfA4nhHTfIbG7rAAAAAElFTkSuQmCC","markerG":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAzlJREFUeAGklgNsKFkUhmvbtr1Wzefatm3bRrB2tOHajLO2bds7Z/9T3HTqdv7ke6+de+83c65SlQPiDErBCrgFMGugAriDI0cPDIOv9TU16XJba0r1dqc0cKWdDRloaRLavgOTwPAwmSt4ztZAn2ajrqZPawol6q6XqL+JGP7589oiaTkmjBwNDVj8KvDZT+YBPol3caRvG0slGmwh6mkg6qyV01NP3PZjcwUleriy9CsQAGTRBc8nuDrSX511RL1y0RPZSet8UFUgnnGffyFP9nRj6RvACIgM2qPMr5vKpe2ypkuDyURbmwcIIp3s6YemsvV2ruDH1irJzcSI22bBemzBxwuxoVyKkBUF+qzLbj4TI569UJxJIVYWjHjGY647Hc3Cr4ErC7P1NDXo07pinnRRIp6zYNcc8tdxG/dZf4Yx36IyU531SspYOHeJjZVsAbjUJMyNEO2Wyp/1NVK4ox0Ll1h48wVPV2yLZtGB52ko9HL++WgMNFOOnxexa12YyF8zcLAQz2SLg3aZMNffWwgXLrU9vGTMp9g+WBS5sK+JIjZeuMzCHD5in9WXHGlRdlXQXUffNYtFKWehPfhsNT5iv20jFoFfwCJ+2WJMqCj35rOx/Oxb4AHWM+SAjf1tc4W0vXQM3rWxXYwN+SXiGP7cVi15mBhz2xwQMQCvJWG1/8UFgNIPP3ooFS+XNlf3PWAGZPHm0rN9PXFOG4m66g7eKliI8mA/ln0DgsCeuRj8NBx6BeamZX8Z5nolLpxlf4AwcGAyVflo5abwHbhbhq9/pTxX0tPQYGENOFJuD7A0pz86aqRdpUN4xs2ZZY+DI8cF/LgYGyY7QTxv92WcZxlzNThWZlxxz/3eXs1fKS6BeFcnlt0Djh1H8Mtdyad5LteP5mvluaSmqsrCeHCi3MkXBwu59OGwK1j2Ejhxks10dOj7pvL1ci+3s2bhqBKhBfjxcZySbxrLSFtdnYVXAUV5Zj46lB7PTmbZF0BfqXCpONCXJiOvYuHDQHHKwxzt+M8RcaMoTbwzriwvMxMWlgLFuVhLXW1rQeKA4ngCCRC4AiiOFfgVEPAAiqMN3gaf/D8g5iekGACf7gZfmTl+ggAAAABJRU5ErkJggg==","markerH":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAuVJREFUeAGl1gOMLFkYBeAe27b5bI5t27Zt2wjWjjZcm3HWtm1763/nH1TSqR7WSb52ndTF3Ixil7hAGazCrVvWoRI8YN/RhxH4xkBLi87b2VCajwelw0V7WzLU1iJ89z1MgRHsGjd43s7QgOZCLtNntUUC9TQINNBMjF9/UVcsrIQFkJORIRe/Br6gMp7waaSrE33XVCbQUCtRbyNRV52y3gbi735qqaQkTzcu/RqOglL04IUoNyf6u6ueqE9SJIXf/IfyFC93Ln0TjEHMkAOG+U1zhbBdFuzsQMNXz0uK+DP+jl/zCH5qqxbcTY25dA42YgefLIZf5aHwD/dfCHzN9TGhxIsIbqDI0dfSpM/qS3jSD16Ia77DyMx0dbi0HBTzZ2ytxQU4cCHrb6JAJ3suXAbFLYlebkQDLZJCfKeKtHCwhXL9vYm7NgqTvNzxobSw+JgvPZmTrASfqSzMO+IjFi6etZM75GYK2hzRCihy+U/s84bSQy5KPX3fIi5KBSgc4PO1yKDDbRsM95a4cC77DjxhI8OO2NjftVQK1HuQjd1Av7TXCJ6mJlw4D2IM4fVkrPZ/OADEoe8CQ+V5F7ZW930wB6X4wOc5fl5EfU1E3fW7F2IhKk74c9m3cBxU5jT8PHL1AuZGnE8pzPVqRCCX/QkBsGuy1LB5n8xL5TNQWoa7f7UiT9DX1OTCWthX7jhqZUF/dtYKkqGjMNbdhcuegH3HFX5aCg/gbaE0b/dnJnAZuwwHyqwbzrk/OmrEu+RDINLNmcvuhQPHCX69OyVmYy55f75ekUfqampcGAmHyl18cHAhD30k4AKXvQyHToq5ri790FyxMdzz9jZcOCan0BJ+egLH1rdN5aSjocGFl0BWnl0IvUpP5KRw2ZdgALKyXHLMj6aCL3HhIyA7FQFO9vzviHiiyE2ki4kReZubcmEZyM5pbQ317QWJANnxAgEILoDsWMNvQOAJsqMD78CnYAK75hrsTBEMgmcmJgAAAABJRU5ErkJggg==","markerI":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAvFJREFUeAGl1gNsLnkUBfCpbbufn2371bZt27YVrB1tuDbjrG3b9s595xaTTOrOSX51T787f6TCGgmAXJiBWxfNQQFoYMOxhm74xsbMjI54eVCsQUNxcMzbk2zNzQjf+x4GwQ7WjAqe97K1odHzJ+izkkyRmstFaq8ixh9/UZolTl88TX52tlz8GmyDFaOFT68E+tF3lbkiddYQtVQQNZbKtZQTf++n6gKK1Kq49GvYBbJYwQtXVX70d2MZUausaGX4mf9QHq1Tc+mbYA9SOn0w5jdV+aJUBpMXT1Hpgd10zt+HgtT+8x8/mRwlfZ8n+Km2SFQ72nPpKMzHCz6ZuHSKR1n2SriAC7tOHZGVSfA71wdfIF5EUIGQbG1mSp+VZfNDX2k8qXDF0fE732EyJ0sLLs0DYeygp7u0AJsuZG2VdMbPmwunQLglQqciaq/eemFHNaXs0BN3zRdGYqWoQ1lh6k6DVDhxyEvpyFV0Fj+DrmkQUviIfV6es8VFKaPvq6VFyQfBBz6fvXJ2a9sG494SeonLvgMtzKfLFxv7u+oCEaPLyqJ0atnGxmaXHcNf6opFraMDF46BFFt4PQqr/R8ugBVHX2FU/HFxcXXfB2eQxQCfJ2/XEbVWEjWVrV2Ihcjfu4PLvoU9sGIOwM/dp44SdUjPc8XjNnP5DJf9CadhzSQaCQI9mRrDd+DyMrz6V/NTRWtTUy4sgQ3ljl1uLvRnQ4m4bHQUhqgDuOwJ2HAC4afJS6flJwjP7f6EcC5jJ2BTGVHhnvujvlh6lXwJXFH5c9m9sOn4wa93Rwfzs5w/mq/np5KxkREXXoEt5S6+OLiQR+8+fZTLXoYtJ9rZ0pJ+qMqfH/eItwcX9iopdIWfnsAR/LYyjyxMTLjwOCjKs+MXTtETydFc9iXYgKJMZe/eToPnjnPhI6A4+af9vPnfEelGUZorAQ52pHd25MJcUJwD5ibGSwtyGRRHByIQHAXFcYffgEALimMB78Cn4ABr5hqJiypZla13FgAAAABJRU5ErkJggg==","markerJ":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAvlJREFUeAGllgOQPFcQxuds27f+27Ztnm3btl2IXYhtp1yxbdvOdL4+zGGS1XxVv8P2zm+nX897tYKRRIF0MAaunmYCZAGNYEFcQSv40s3BgTaEBNFZg4bOgU2hweTu6ECofQO6gQcwGhV4JsTdjfp3b6GP85JFqi0UqbGEGP770/wUcXTvdorwcGfxy2DR/8m04KMD0RH0dXG6SM1lRHVFRNX586krJK59X5pFJ7Uqln4BloF5cQHPHlRF0B/VBUT1cpEMvOdvyE/r1Cx9DXgCKc1haPPLkkzRiIwvpMdiT0n/cwffl+eIam9PrvWDyYSAD4f2beNWZBKjQsDXXHp4D9e+BCogxLo62NPHBam86JYLcc3X6MzH2YnrGUAYWBscKA3AYiHTUEw7IkK5PgKEq07oVESNpdYLm0opbome2DUpPKlT40VlwvilBkk4tC5EacsltDMyjOujQIjjLfZJYZpsKN5OTiwwMZQC+qZUGkomEMLAJ+MHdsoem2gvDzrFy4G/rzqyd1L4XUmGrN2rju7j2tdACybTEo4H++vSLHFu67edOUyoSbRs2yDbhj9W5Ipaby+uDwAp7uCVU5j23zgA5rbOd8RtvpeTJGsVHy5OT/cd4AvmxQA+iV2swz4tJqopMD4kDCJz5RKWfQVWgP/MGvBD67aNWBsj2xBrPbZ/B8t+A9uB0Vy04WnGn+EzUC7D3b+UGS+62tuzMA+YleuWBfjRb1V5IlqXCY+oo1j2qGBBosH3w/u2z99BWLd7LhxnGbMFWJQ+Fc65XytzpbvkQ+CAKpJldwGLEwF+uun0YV7Lya35SmY82drYsPAAsCo38MHBQm69dftGlr0gKMhpX2dn+rYkc7LdDaFBLGxXIvQH3z+KnfJVcQY52dmxcDNQlKcG92yjR2NPs+wz4KZUOJK6fDF179rMwgeB4mRujwjlryPSiaI0B6JwLup9vVmYDhRnjaOd7cxA9gPF0QERENgIFCcQ/AwIaIHiOIE3wUfACxjNv66iKPO+3XaMAAAAAElFTkSuQmCC","shadow":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAAAiCAYAAADYmxC7AAAABGdBTUEAAK/INwWK6QAAAhtJREFUeAHtlYXKG1EQRrsST+ouaB+hOPSp+xx1d3eJezL9gMMyLLHL7zJwWN89fDO5Sc3sxH6rVBxLHUsdSx1LHUsdBKljqUi16DRbW3ysHVWAVLBIlNvGYlGZ284jlZdLtyqUE4nB7efkEHHMvJyp0i0mE+dIRQIp5xIkqUxkKiYOrunBLSQTu48XHMVsi6RPygmNxED0eedYmD6BVFhCPpWiKDsqbEuiCKlrqSE1RqYtmllKXE9DEnIyJT5egzpUEStCsqh9tKvHvRHHI7YB7UOIFzXEKXGabQOhEq1L/dA7KYMZ90a0sOXl04CUEj58RpwXF5Bq5GRIdOESYRAjVhCJ/0VuJOWEyghdFZfZr7k2+aVgURnMGfQhLeyyPxUWsCRkKZ1D6gJC+Tbly9jOwc/TH/FD/BIdzgctnhFJnYaai34zGdIhmd/iOzSZq1nIim7ZlrVpg3T8aj0WI2Sa4hf8FT0SmhtCIUlNeUFbDBhuy8vADEY80xJ/oMnxQIzzMhtLmSqKohkf+CUuMeQFJKIFLWrToh8k0nKpMNBeJlAKsbnERnysRxJUJjMiie/iE1Jtzs8WiWxBiqI1fq4QGvPxz+Id6bQ2SGTrUrSpwgpeRKgvvoqX4qNoykEyW6uQ/76quC4ucLqJzFNmbRyWytaTSpC5Kcq06J54I3pyUWrULkvdEjfEB3FHtLeWzNalbpPSQ3lIaGfrP7yW/RxNGeHVAAAAAElFTkSuQmCC","spot":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAArCAYAAACJrvP4AAAC+ElEQVR4AWIgBP7//88DxCGAWssB1pIkCsO1iLG27WCtYG17x3Ywtm3bthlNMLZtz/NrXvStM/cbP/Vln6RSOfq/xqlOi2nO10bxUe26RRKLRdnxiZOnTqVpQO6NOc5AiYSd6O4dRcbAnlJQv4rk/fWt5HzzkbDjEydPHfX0pQr6Q4dcI7RqqZP7Z1z8i/cSLuqop4/+ZCB3iOt214UFVkG9SoikvOijHx1fGAXeqWNm7u9f0Zj2oh+dCoHcOlfkA0oZiB66ZYaBZ53uo/N7pOiWGBqmyF21xKEg24uhQf/mOWJsmaYgYOiiDwfYn5yTRE2X42vNWy/KyKcelZ6PPMCOTzwhEH04ii8ABzMRaNwzj0uXB+8rs4gnAqIPR/HJ4UvgV8wdlICUXOR9+9GHo/jG8enxK+aR+cDI+/ajD0eJ50Vzvv3Yt5h35Acj79ePPhylbetyXuVfA70z9OEoXVy0pbBl40DfGfpwVMy1R1kTRnpBTqM1cZQHh3P2Tiwv1wzynKEPR2HaNI4VNmsQyBcE3bj+UTgYE1kncmCvFQQMXRGpfQsmcre27fNFHVtkFYSeOM459OHcDvw+/mwtzkQ2QOigh64qz7RlrXRmTw1nA4ZOXG+F3z/Iozrkmvm1/80IRD866CkfY1hqeSeOGZnA6EdHJWPaNjdYw/tH0wHRR38q/43Padcx8/75ISUQ9fTRr1IxiUZbR7ZtSulxUk9fsoySZ8+xjxZ1bpkUiDrq6Uv3f/9TXVxk53z3qS+IPHXUq0xMbHuRNWGk77CQp05laiLysoRCbu4vn5cLIk6eOpUN06a52J46zisPRpy8ypaJyOvaMqycrz4sAcInTl5l07RprC3u1qYEDJ+4yraJSI3w5vVmiXO1dYNJPAjYQzo+CDlfvi+A2PGJqyBMG8aegiY1BRg7vgrKYqY53RjUS4Cx4wcGk1isa3zUNTB2/OBgIvVDq5bawNjxg4R96Z07U5T393fCjh8k7E7t2PPEi7rs+Kn0XwF82Z38cjx5pwAAAABJRU5ErkJggg==","iwbox":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAFJElEQVR42u3bQYjT6BvH8e+mG8aStKGFlpQGGhoyU9BB8OJV8DIXDyLe9eLBq+xJ9vTHk3j14EXv4snLXASvXgQZB9opKSmk5KWFljQJcQipe9jIqiPLf3ZXnMb+7in5QPq+efI87y8fP37ktFkulwghmE6nzGYzsiy7CFwCdoFtoAPogAbIp/z5FAgAAYyBI+AAeFsqld5dv36df5NfTgOez+d4nsdkMiGO4wvAHnBV07QrtVrtnKZpqKqKoihsbW0hyzKSJJ3qhlarFWmacnx8TBzHRFFEEAQsFosPQRC8Bl4B+4qivG+32xiGQb1e/2/BSZLgui7j8Zgoii4DN6vV6g1d181ms0mj0aBUKvE9k2UZs9mM6XSKEMJdLpcvgOeqqr7pdDqYpkm5XP73YCEEjuPg+34buF2v128ZhmG1220UReFHJI5jJpMJnuc58/n8GfC01WpNLMtC1/V/Dh6NRgyHQ8Iw3CuXy3dN07zW6XRQVZWzkCiKGI/HuK77MkmSx5VKZd+2bbrd7unBg8GAfr9PmqZ3dF2/Z1nWdqvV4izG930cxzkSQjySZflJr9djZ2fn/wcPBgMODw9ZrVa/dbvd+7Zta5VKhbOcMAwZDofBaDR6IEnSw/Pnz38TfQI8Go04ODggTdPfdnZ2/tfr9bZkWWYdkqYp/X7/eDAY/C7L8sPd3d0Tj7f09QI1HA5J0/ROt9u9v05YAFmW6fV6W91u936apneGwyFCiG+DkyTBcRzCMNzTdf2ebdvaOmE/R9u2rem6fi8Mwz3HcUiS5CTYdV1832+Xy+W7lmVtn/X/7N+lUqlgWdZ2uVy+6/t+23XdL8Hz+ZzxeAxw2zTNa2d1NT5NWq0WpmleA26Px2Pm8/lfYM/ziKLocr1ev9XpdChKOp0O9Xr9VhRFlz3P+xO8XC6ZTCYANw3DsM7KS8V/EVVVMQzDAm5OJhOWyyWSEII4ji9Uq9Ub7XaboqXdblOtVm/EcXxBCIE0nU4B9nRdN3/Uu/H3jKIo6LpuAnvT6RRpNpsBXG02mxQ1ue3qbDZDyrLsoqZpVxqNRmHBjUYDTdOuZFl2UQIu1Wq1c9+7nv2RKZVK1Gq1c8AlCdjVNI2iJzfuSsB2kbaiv9uigG0J6BRxdf7Wag10JEDf2toqPDg36hKwllXRP6miAE0C5NN+Sl3H5Ea5+NKv4RvwBrwBb8Ab8Aa8AW/AG/B3BKer1arw0NyYSkCQpmnhwbkxkABxfHxceHBuFBIwjuO48ODcOJaAoyiKCg/OjUcScBAEQeHBufFAAt4uFosPWZYVFptlGYvF4gPwViqVSu+CIHidt1wKmdlsRhAEr0ul0jspb7G8yptqhUxue9VoNJDyRtO+EMIt4modxzFCCBfYbzabSLquoyjK++Vy+SJvjBcqeSP8haIo73VdR6pWq+SN8Oee5zlF2qKiKMLzPAd4njfG/yweDMNAVdU38/n8WT7cUojkwyzPVFV9YxjGX9VSvV4nH2Z56rruS9/31x7r+z6u674EnubDLV+Wh6Zp0mq1JkmSPHYc5ygMw7XFhmGI4zhHSZI8brVaE9M0T9bD5XIZy7KoVCr7QohHw+FwLauoNE0ZDoeBEOJRpVLZtyzri8HxLz4A6LqObdvIsvxkNBo96Pf7x+uE/jRcOhqNHsiy/MS27RMD479+fVG32yVNUw4PDx8OBgPSNF3L8eFer/fNQfHNgPjn+amOAHzKT3XI41N+qmM8n+enOaj1ddb5KN4fYCYYVkTnAvsAAAAASUVORK5CYII=","iwtail":"data:image/png;base64,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","iwclose":"data:image/gif;base64,R0lGODlhDAAMAJEAAGJh2P///////wAAACH5BAEHAAIALAAAAAAMAAwAAAIdFI5pwe0XYINUoghYsllfP32Yl4DfVT2Z5DzGphQAOw==","gwhite":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHwAAAAwCAQAAAB5jdYiAAAR4UlEQVR4AeWaBXzV+LLHv3V3pe4tVqq0BdriLi1enAquKzjLCnq7ZVn0CiysIetS1oq722Vxd6u7kffJP8nrgV437uNN5ZyczOTkl//IbyZB+j/5gz5GmGOHG74EEoQvbthhhgF6z2r+aZH404fVQx9DTDDHEmtsxI81lphhjCH66L1g2HoYYPqa77Ws4nMFF/Mu510uuLhtFt7YYPwPA0cPQ0yxxhE3vPET1zOYEEIIxBd3HLHGVIb/QoEbPUotO1h8rqZSEvLlt/QiDBdM/37gGmgz2YGWtDublbu/6LykSk1Z/qWL2T9kDulDJCF4Yo85hui9MODG2BBAm8d3JCGhaxhBLA0w+QeAo48x1rhtH1t6WZJqq+8e2/Xx16u+WPPDhlPb7l6UVHl4ZfNyl/Y0wR0rjF4MdLFAFniTqAF3/YgxtMAVo78bOPqYYr+uS/E5Saoq/XGTz0j6k0wPutGDZFIGv3FgvwY+/1HWXMJwxRz9FxbjJjQgTgPusoVxxOGMgcTfBVzAdto9uaZMku5cin6NEfSlMwnEEE1z4mhNNwZPXJFXKAk5dcSiI/5YY/AC05sD4U9uq8A3kUEUDuj9XcDRxwTH4/PkQ/x61up1RtGX1oQTjC/eeONLEM1IoF/43LuPJOmXMyav0Z1gbDB8gSnOikZ5N1XgG0knEvu/B7jIkdh9O/xprSQ9yfVcyBT604pgXLHFAlNMMcMSe7yItO/z8HbOIWaTRlt8scTgvwT4p6T9/cANsBwfUZUvH2DIRuYyjHh8scVYrdiaa5nhOqHTO5MZwAA6Eoozpug/43xGmIrab4nFX6r5QtcYMyx0dHWpR31WYYAhRhjr/BhhR5PcW/WAP382FnXH1wWulAbnK5tk85M3yWISHQnAun6xQh9znAkkjDCCaICFpoO+KIM2OKm1PwB/fHDDAQvl8tXjXLY444GPquuNK3aYY4R+PRpliiV2OOGKGx544IkHbrhghyth9YGr36Ccjbs4Gz+8aSCOb4h+HXB9rGYn1FbL5jN2MZ9BhOPwpwsVhuopO2Gr0EONRWFLg+0jb24oPld8sbqw8ML9g7+826ULofjiqFR8HZ5gnxy0d9yD74rPld0of1B44ca2zbMDE2iCF/aYiqPqklLXJv4fJn+VsW/BjiU5mb+8m5O5c/H++cfn7RyID1H1gOsrZxPpdWzijXV5ByvuF164uyd7vlsrGuOJLSboa8CNcDq5UjauferxCdPpjC/m9WFrK4sxpphoTqxWVOcDE8qvP629tXvfhu+Wn9xaJsKmqiJns3dXQrWKL3KJVaTXrwuqC2vKrubs+N0Pa85vry6XdUvyNq0gkUa4KH4k0q1NavClJWWXpHpSVbp3lXc4IcQ+D1wsjdPRqVUPq/KvbP1x+blfKovl/eVFS9+iJYHYK9AlwBSvJ3+Udz4o4feiGrpg+BfKiPjRWUHL9n6PfpSkx5fGvUZvUfd7+ow8sFsScudmTCoxeAnoRlgviS25IEmXdsenqxwhqcW4qyo/PHHYoTfhIoTk6HTYO6o6r6roo/nRA8yTlmflP5J1qmsn/sgiJpJEFI3qAXfCwsP9UbYk3Trkl0IvetArcqxy/Ke1i1bQniBsFW8Gy65Rcj6XpOOPWcVwwrD7G2mJiHo3z8e7JCn/nv9EhtCTRGKJoz0pe1S6c/uurUwmPbDGZmJ42W1JunSSNFLoSjwxtKSzS9r164runsP0JRxXrHE8MOVpbVVp98n0pzud6BEz5UmuAn3oVmaQTBiBz7l6FG643v1KkooeeY4R35BAK7oEjMsvkHVKyxtOoRWeij+D3R+GKcb7H7KcgTTG+u9gzE6X18m2czYwkQEk0Fgkk8Yk2o6UT1SWrQcZSAReeOcelaSamriFjKU3LQjBD39C6dBtdk2NortgE73kaF/VQ846OdsYz0DaEU0M3VPfVXTyyu0ySSEcfyJ0gKcTg98PY+WtNz5gPP2Q4zqEGPp+tV3R2pxDd4KwRl8CnL58VRJy5DHv05+GWP2NwA2wWtJOPsHyChYwgS40wgkrkYX9SFy6VpKUNYpdQg+ismcLgnSdt8mgrYg3SyxxJJhOObsU3UdFJlPpSPTdPfLWO1/zKn2Iwgcvwkg+owbFkh2kEoU/Yc8Ab2UbVv5AvrR2CxlPV5qIGtA0esClc7LOuQczPyWJhthiIAEuX81WjC8VsYIBNPqbgRvhfO0L2fL8fTJJIw5XjNETkW9FoENSUbEkZNMJxtErVzj0F6fVyuGIodAV9bjPJEmV178lNWKwEnzp3zCNLgRghSlORK5Yrujsu85EWhJEmA6BGUXb34mjPCwgk7G0oyFeyzrc+LymrLLsl8Pt1jOfcbTXiDa4rB6vGFfU2qxjKKHYovc3Obq5U0DZE9ny8B2yGEwzbJXsIOA40/yguo7XClmYMEd5/9uTvEMywVhqCRIT3El8eE8NjCvMfSVLvQg7mE4HvEQmNsM3tI8k5Oxj5tKRJkToAB9DlwMbRVbJZznj6LhlTP5eSco7//lKlzTGMIYhdKIpLpgpru48oZ+kSt8fGUU0jhj8Ra5lJdzZEuc3eil2xx6y9BlfEeyAkPXLNGfng0XfKO/XneMdeuCPuU7I2BG2Z6uy/0wu77+1UXn/yTnm0hkfTAWHcKFFYZ78+cH7vEM3mhGpA3wcvS6KhPqkzGbd77cU3Kopu/Lt9NF0pTvd6ExrogjCFUstqztYN68oUczXX+B12uAhO2y9JtAKR9zxJYBgggnEj0arpip2lwt5//kgwQSv8emSKm7ZfzigvPv6OgueA66HBYEb31MLYCnrBm/QPIUl9Fa8A33sicy9K3++5hRv0JmmzwCfQN9rJxU+MmP/hLXjZwb3IpE2JBJHOA3xwQUbTEWAIQE2NL18VM2XFXaZwg2t0H+OZFpdGlV6tOTXovPyjEv+eXxqwMA3ZmpBYvRbhtAUG/R0WJ6rVbwG3PTH9w8p707m8huSCcLi2Yv0rppiLxSywXhhSamyNfhbkcacMBJtaIS8ROXVnh8whQRCCNcBPpF+F44oWwN28yYptCaCZjTCHzfssdDl6xJgQcCHv5FUWXqQUcTgorvm6O/3LtlQtOPWlxezT+do3rFkLcM6v67ZtfmWdNEP69dZ4Uh0VYW8N7eS72fuUDRLqo1WkiIXTZ1vMMJt2ki1lj/k98za8ovqS7mWc+lOCI7Y4LU4Q/5s7k+8ySCa4UPosyu+L1vZ2nKNRQwijkDcccIGszqWXgfcBDfL1iJ2xJoHZ9KLYN0mBQPMcSKAKDoy5MF9RbP1WiaRUagOJpafZioJuGGk48D2RCrDwB/vsTl8naRKv61kPJtJMKTB3FRl77JfyWKszeiLl5XtAxesx9FBXrnJfQpuPa1dlc0c0mktGpsmOsDHk5S1WNkqq2nwe1IFbbLSXWdd4EpqCd20VlLlxG0misNaaO2CwptxI5AYkrXsG7qZ10k9rEbujWLepgcBWAgbxcqhY1tlb8Y+VjLnzgNl6/trTKMtntpgUFnxD6craTDkc2bRh05mKZ/9rNCagvzt3339u/Pbayprq2et41VS6UgIdtjT+Jms3tW8Z7kaIjlXmUpbvDDHAOqLhChLeNPu3DkN+pdHGUkcnliKVa9rJF0Ipt2ju4pW4294jZS+02qfKtujv2ckkTgqOVOJ8Y9FKFzLYw2zSF22XtGsrAldTX8aCyKh+IYp3sc+lfd9d5mlpNGKJkSTHP/Ge9/+fPT6rcePFMsNO5lDBp1pjBOm2NDomTrejta7v9NQLP6ZoUThqnSRIJBqP0go19ueJs3TCoo0o52nTEfQEl/slAm6envBFGcitSlXk6+YRA+67vhZ2b5XbDmXrgQqQYIBFvjd3CPzqO6fM48hdDRPuqK6746rTKaN5lUYYuPbrOSBJD0p9lvLNLoRjAvuNKUd/Uhj0ndqy5OczdsMpjkNBBxrGv0vc9vEaBKJCkrWgq+yZvKnDCAaL8EQzdUfU4wUT1ac0gw3YntOE6NEIdfvDX+LDoTihSPWmKsDKBeiNOBNtzCaNsSY97ikNo67zpuMow0BIhHZ4fn1NNETbWUeI0mkCVHx6XK7IArSNobRAh8csMEBv7MbJamysv+HzGIQkbiIk3TEl1DiST56SA2SW2SJdXQWlMambgLj/w1T6EA4LRa+J3xQyIHTTcbQljCC8cO7Z/CZwe1ctOkAGuvGh4ToV4/pdL9HDi+YT1uiREHwxhMvGnXuV/hY2Rv2AYOJJohwu5Tjv6ql6lz7KbSmKYEODY8vra2uqli4gdcYSTuCcMGTmNiJWqRn7wyRvaoRAfER17+WpKLc5CxeYQjxeGOJgZjyW4mJT8LHGyRVfr7s+Brt8MMaY+xsm1WoS7XqjNc8uovy1en9j6uqNf3KyhuXD2V/t/zsZw/3lF1a1B43YakvgUYxscGPeIZnrL+qQlMa+At7L2zNydyz8I+/vfVl3mnBjAq2X16ww3I23QjBFXeiGTDv43uCvFZX3btwMfvmT1X5tdVnt8VMJo2BtCUEB8yxxptWpiNWf19cJqp/ye0Tl76/v6u2oqpo+2eeY0ilL63wx1a4oyFmIq/4E2c77OZ9SZUbD8KmEI8PtjidzZJ0JO/aylRCCKdb38Xn70jPyfntSf0Jxwc7TBTgujdlvGlOMhMSVn5w4NzdglLNqLb6yZXcCxe2Hv96eVbU60xnFpPoTxTugr66E0EPRiUv/eSH/QeO7D6dc+iLtfMD+pNMMp2JJRBHMVIyEtBj6cO4iX/4IufA/qO7Tufs+njpHHrRmyQ6EiXyiolIpva4L+twcsGtL+/uf3y1orwOwr0nAro/Hu8lzZgwLLP3+p6bkj8clhk+jBjBKEPpSPrAtRuPbj1/5u6pG9tPrP4yahoDaEczMRdQKKvujTgsaUBD4ulNGlOZwcyAeUkLyWAIfeVERhd5viJmJ22JwFO4jSEWuNCQVnSnPyn0oxedaU8b4mkuJl12yjRWGT2JpJVILwYwUBy1k5yNaUkUIbgLUmmCdXu/4/PKbkhSVdHN/b9sWLdm6LvJH+68UQe98QRaEUQAEXQhhRFiCNKKhmLA6UwAcSSRzivMYDpTSKcfHYjEDweRFnWB64wN3WlIc9rSjSSS6UVX2pNALNFEEkEYTQkRzNdKTFA1Kw+CCSeGWJoTQagcvXjiiKUyO9UdNuJFQyKFbjThhNIQf9yxF3NWE2yWJxZfkaSayq83uo6kLz3pQV/SmL5wW3Wtyvj3M5Bo/PARzh1NFKEE4oYt5phhjRvBRNOGzqJBaUMsTfDWBp8g8eduEjvjRSCNCCWUpjQiSAyMvXDHVWRic4URPWflhJtIgh64iUmsRf15uTL8FbNad1W3gagDYriMIVbLE6vy5WwxaBnjGURnWhBFJC3owsiM9eXVgvhWmLxGe1FB7HDEGWfxzkotv9rZeOCLP9qo27KOxUn8pccCLLDGFjvxIx4MqKuD6NW30maw4scEIx3If1nXWGdma4Jr7lFBow7yFmPoRqTwHDc8CCCGfnM/lYQ0e59kQrDGQPsR3qf3HAYz2QPEdyj7gXrA/9JU9T/2gIflsg4KsGHfC7ISg6doMkwwwRJXwhlwTTCJ0NWkaP1g/Z+/6/74i//BAPvd6iCs10/MoydBWApv0O7ouhO/f48klVUaL3q5gDvlzFOAv3eKt9S2R19nvwPhFw9L0vYzzCKJEKxeFuCOaT2UQWNehf8ahgr6qqQ95eaQ69CuVaWVlTGZjKYtPphJvAzA9bGj6Rm1JbmZl7SM3kThJ/K+nLs92scWXKmtXryOMSQRjhNGLwVwMX3z8+ohujghly9m/mb2OKuWRLRpuTzl3LrqkorC+ZkMpzdxCqd/WYAb40Qz+wEfZQs+/5xUFR36plkq/ehGLP7YiQHZSwBcG3O5EUmSyeRpm7ccPHPt1r07d+7dOn7gl2/fWuw6jD50pw0R+GrNxssCXLnt3IAmtKEf6UxgEhMYzQhSRMuTqHF6BfY/Dvy/TxQ+74A3TYijLZ3oIhqZBGJoRhCeOGAh8vzfL//VwKFuyueKF/4EESx6BS9ctAdG0IOXETg8+/iOeEBI4//8C0QC6f/pz/8AIo102Fp8dtwAAAAASUVORK5CYII=","gwhite5":"data:image/png;base64,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","google3":"data:image/png;base64,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","qsb":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAAAYCAYAAABZY7uwAAADiklEQVR4Ae2XA4xcURSGu7Vt27Z2982aUaPats2ZqRXWQe02Tmojqm1b817N/23+1yzvm7Mo5ybf4s6/OF/OPXNfpvBhMT4U+CRkkCCfIKzcoAEIAdEgHLQEpZhJEwFOT3GHy5jmcOnXglzGR3DP4dYXazM81ZhJE9+/fw8G28BT8JWftwItzYKwKoIoEJsCTUF25sUEufV2QW7jMvieDPcga2AaxGQFq4BqLTNzckGUE09EM1AC5AKFQPV44toCP7Ecl97DkoEOOgj6Yk+DtE4Ot7Ez3mvOVAqy5BhgAigPMoMKYCJ4a0kSC+KxsgRUSqG78oAwZqpK/vlAl14TxX8CEKCPTy6D/Q5WRnPpIdJjFU9O0xQyzeJJCpQKamB1juqHsEoyFwWyeFsAumKpWTiO0Bp1Tp/CTtonFLSNhU+wyU1mbotUUAgLL8E9laRwZot6N5TfZEPB19k9zZWCnHpx5N6aIFtaIOgpCy9vk6vE3GOpoGgWncsLQa2YLWOXZdEFUfDHuKKdbwqrsk1GP/RD7lycTLfeRCDoKwvPbJPLwtwXqSCrKwp5ISiIWRarRnMZeVHwa/AJgsqpsv7TX+ZA7i7AcdTrpqKDKtjkKjP3RCqoJYuubiMnF3MmWb1/ezcOAHSF0V09gzxtOIPuak5PLoGgrSx8ok1uCnObpYJKxRu+eRSCWqqGuWL4drcKRxclO1taTnqRE6+f5DCfKRzSGgt/C5qlkGkB3jHXNjX3oKYsPgyUTKZzLDnRILekgGYTXmVB4Qcp6QqEhftPexV34Wztfp4FndMS+8f4+s02kx+yO0WSlsWTNJkDOQuP1ZR4cjam9qKYnZfAWBLOgeyw9igngjLzSgrQnEZxHLGjlGByA+wGF+LtPQC3wFpIKym/SUOSem3k59ucV+JHDT9QNYXHjWYgd/xOk0pyTMUQxkXR7BJLCo/UEzAPz2PF8f0J7p/T3B4eR5GoQLAFPAZfwBOw2TpWlGOuWypJdu9UWUBRUAYUjj+QTSmUI5dEmk54hmOlN8BjRjCENfefrv88subbO+Q8pqQLyKmvE3KBFSjHXDdBebEgOygplJLwmYM9nYC0epDzkJIuai5PRki6qZBEQX+0JE9tyLlHSafRSYEZKOkGJQkEySW1VuflYAZVMzuIkuZwPz0llaek9BGkeMpvbT2mpDcQEyiTI5ckOGI+fIJ8gtKHH9/5eQq7P5+iAAAAAElFTkSuQmCC","satthumb":"data:image/png;base64,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","openhand":"data:image/x-icon;base64,AAACAAEAICACAAgACAAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAAAEAAAAAAAAAAAAAAgAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAA/AAAAfwAAAP+AAAH/gAAB/8AAA//AAAd/wAAGf+AAAH9gAADbYAAA2yAAAZsAAAGbAAAAGAAAAAAAAA//////////////////////////////////////////////////////////////////////////////////////gH///4B///8Af//+AD///AA///wAH//4AB//8AAf//AAD//5AA///gAP//4AD//8AF///AB///5A////5///8=","closedhand":"data:image/x-icon;base64,AAACAAEAICACAAgACAAwAQAAFgAAACgAAAAgAAAAQAAAAAEAAQAAAAAAAAEAAAAAAAAAAAAAAgAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD8AAAA/AAAAfwAAAP+AAAH/gAAB/8AAAH/AAAB/wAAA/0AAANsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////////////////////////////////////////////////////////////////////////////////////gH///4B///8Af//+AD///AA///wAH//+AB///wAf//4AH//+AD///yT/////////////////////////////8=","pegv3":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAAgCAYAAADwvkPPAAAEe0lEQVR42o2WTWxUVRTHf+feNzMtUyjFVinaCK0g9oMKr/GDWLQkLNRoENGFCSQuXLnSlYnGDQslcefSGCNCDAkkJKIxhaAQkEA6SIBSIQQEJECLtJiZMjPv3XtcvDL0G+7u3Zzzu/97vu4TZlmtHeEnoyWaY0cmsBTnZPj77OncFzPZy3SbYbiq486onHqv27H+BUdjnXJjWNhzzLLjoKU2qytzuRMnHwgLw1UNhZIM7v2sTEuTVy0jqiACkkYv/WPk9S1p5mR0YS534uZ4XzMZVijKr1s3R7Qs8hoXRZwHr+A8xEWRJY1ev3o/Il+U3sm+E2D1TV2pqjSr3nzFaRyJgE4yV+JI5LVup9kMK55cGlbPDJunz3cu9hAljtMvhQieXeKpTvPcjDAFpzprbir7XplyYjD+41x/7mgmCMd2Z1GWgj8vGi4PypFZE1COObxzn5UgjU5VJwRpdNd+K6WIo3eH+tyssEdrtefzHSly540E1YqxgjGCCYQgo5z8y8in21M01Gr3ZF87eWNu3aItMbw4dBJjrnnm+JhoFG5fcBzeJ2z/JcXl2Gg5koVDg9f3zli0HZ3hzpda3bsfrYsJCmh+UMQ7xSsYARMI2TqU+SrbjgXsOmIH+k/nWqeFtSwP9cJ3RaJhCLJw5YAgct/Ex0rTWsXdhXQj2vVBldzOU3PpXK4wIWbPtIerwxYPgsaR4D0sWA4+TjLoHcx/CsSAc8AosqbNUZ3irekSsKGnw0MZUaegQs0TSiqrqAo2UGqbFfVJY2gZuls9TnljCiyKeXtth0+UyJiaSKhfocSjsKD9vkoBXAw9HZ4onkZZdZrFy5Z6jSPBSBJOVSWVFRpWeqrrE4UgGAMuFuY3qDbWaWpZa9hQgbW2hxu72zyUIS3K7+ct1iQd4J2Sbbyvyohy4LwlYxRKyJo2T2BZX4F5ZUNPhwOHXL8tHL1oJuRZ/bhaErh8Szh7zYAfi5tL4mYASjHvrOv0YODbQ5a0nb3PrcD3hy1Y6FnhKd+DLVzclW2q16C2XpUA3X4wIGVn7PJkOljY/YcFA1VzVZsfUx5vDmtNtkrDl9s8WNh/3KIKpWhScwcT67sUo8ZA73GrpGH1ck9Vms6grobje45ZRgoi/VeElGWbVzZXVKSUHw5YNq11xGOHeI+kU/z25a6g58dDlr4Lhvp5ejzo68sVAYlduDGwXHKeJeWYzRUhadi6O8WmVx1EAijlGJznp6H/5MMbI9I0cCbXO2E4DpzJ7QJY3h4+7fy4aBtl8A4Qg0gSSpdMutSZU7kBYGDGeYbi7sFEFMrgvHC3IBW+S0ZiPOvrVImvS5wEyOeFwCp3CkmNAcROYOzZeRCMyqMiMJKHwMBwXiphHHtM/MPARkuRVIbdSEGwFobHXbOcXLA4pf6mgVlrgEwyuwol1BqkUEQlg2ATpTqNkCmwdMCN/qvCx1+n8B5u3hGZVw3f9Fr5uc9gBPqvGjIBNx/qLyhT3xWUbkkGIP2ISvnfvnxVQ1e2OJSY1yzUOH+jrzTZ73/M6/MEVVHjfQAAAABJRU5ErkJggg==","logo2012":"data:image/png;base64,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","logo2013":"data:image/png;base64,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","logo2015L":"data:image/png;base64,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","logo2016L":"data:image/png;base64,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","google4":"data:image/png;base64,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","fav1999":"data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACAAAAAgIAAgAAAAIAAgACAgAAAwMDAAICAgAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8A//3/AP39/wD6/f8A+P3/AP/8/wD9/P8A+vz/AP/7/wD/+v8A/vr/APz6/wD4+v8A+/n/APP5/wD/+P8A+vj/AO/4/wDm+P8A2fj/AP/3/wD/9v8A9vb/AP/1/wD69f8A9PT/AO30/wD/8/8A//L/APnx/wD28P8A///+APj//gD2//4A9P/+AOP//gD//f4A6f/9AP///AD2//wA8//8APf9/AD///sA/v/7AOD/+wD/+vsA9/X7APr/+gDv/voA///5AP/9+QD/+/kA+e35AP//+ADm//gA4f/4AP/9+AD0+/gA///3APv/9wDz//cA8f/3AO3/9wD/8fcA//32AP369gDr+vYA8f/1AOv/9QD/+/UA///0APP/9ADq//QA///zAP/18wD///IA/fzyAP//8QD///AA9//wAPjw8AD//+8A8//vAP//7gD9/+4A9v/uAP/u7gD//+0A9v/tAP7/6wD/+eoA///pAP//6AD2/+gA//nnAP/45wD38eYA/fblAP/25AD29uQA7N/hAPzm4AD/690AEhjdAAAa3AAaJdsA//LXAC8g1gANH9YA+dnTAP/n0gDh5dIADyjSABkk0gAdH9EABxDRAP/l0AAAJs4AGRTOAPPczQAAKs0AIi7MAA4UywD56soA8tPKANTSygD/18kA6NLHAAAjxwDj28QA/s7CAP/1wQDw3r8A/9e8APrSrwDCtqoAzamjANmPiQDQj4YA35mBAOmefgDHj3wA1qR6AO+sbwDpmm8A2IVlAKmEYgCvaFoAvHNXAEq2VgA5s1UAPbhQAFWtTwBStU0ARbNNAEGxTQA7tEwAObZIAEq5RwDKdEYAULhDANtuQgBEtTwA1ls3ALhgMQCxNzEA2FsvAEC3LQB0MCkAiyYoANZTJwDLWyYAtjMlALE6JACZNSMAuW4iANlgIgDoWCEAylwgAMUuIAD3Vh8A52gdALRCHQCxWhwAsEkcALU4HACMOBwA0V4bAMYyGgCPJRoA218ZAJM7FwC/PxYA0msVAM9jFQD2XBUAqioVAIAfFQDhYRQAujMTAMUxEwCgLBMAnxIPAMsqDgCkFgsA6GMHALE2BAC9JQAAliIAAFYTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8AsbGxsbGxsbGxsbGxsbGxd7IrMg8PDw8PDw8PUBQeJXjQYE9PcKPM2NfP2sWhcg+BzTE7dLjbmG03YWaV4JYye8MPbsLZlEouKRRCg9SXMoW/U53enGRAFzCRtNO7mTiAyliw30gRTg9VbJCKfYs0j9VmuscfLTFbIy8SOhA0Inq5Y77GNBMYIxQUJzM2Vxx2wEmfyCYWMRldXCg5MU0aicRUms58SUVeRkwjPBRSNIfBMkSgvWkyPxVHFIaMSx1/0S9nkq7WdWo1a43Jt2UqgtJERGJ5m6K8y92znpNWIYS1UQ89Mmg5cXNaX0EkGyyI3KSsp6mvpaqosaatq7axsQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","fav2009":"data:image/x-icon;base64,AAABAAEAEBAAAAEACABoBQAAFgAAACgAAAAQAAAAIAAAAAEACAAAAAAAAAEAABILAAASCwAAAAEAAAABAAA+VeMAZMbFAH7k/wBGy/4A/8hpAITk/wAsPNkAE8P8AFXc/wBF2f8A/8BRAP+5OwAh0v8Aqev/AExm6QA21v8A/cpwAAXJ/wAa0f8A/8dmAP/GYgCa6f8A/8NZAFzd/wCT5/8A/8VeAP++SgAq1P8ABc3/ADRI3gADy/8AKc7+AFRx7gCktfgA/sBPAP/CVgBx4f8ALdP/AAHM/wBAWeUA/7tBADpP4QCJ5f8APtj/ACg31gCi6v8A/71GAL/v/wBFydoAJTjUAB5s3wC8y6AANsD9ACvG/gBNauwAnbWRAKPJ9QCmvpQALdT/ABojzgBRZOAAue7/ACBJ1wAyRdwAFsX0AD2y8QAXz/8AEhnKAJXo/wBoheEA18B3AJ3JqQAKx/4AIS3SAN/OjgAJyP4A+MFfAPf4/gD4wWAAXnzxABWn7gAdvv0Aat//ACY01QA3St4ADcr2AGrI+gA5xuoAPMv0ADrM/gAny/UAM9D+ADHV/wBWgu4AS9r/AI+n7gClrvAAjsetAEnW/gA0xNwAOdf/ACfT/wCO5v8AJ1LXAJ+m7QBed+4AR2LpABjP/wANyPoAcbT0AAzO/wALN80AW27nAEvG0QAV0P8A4r9xADjS/gA0XNsAPdf/AC4/2gCe6f8ARV/oAP+4NgB1wbYAQNH+ANLz/wAAzP8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf2J0Hx9YMxAQBBMZFgoifxIlaxERMAQTFBkjChooCwt4DSRlJkcQe3tGGRYKGih6JAUYfRcBSh4RQDlOFiIuCxIrGw99ZGNVHhFIexkjGigbXg8MBSpvHH4eEQEUFgouKxcJXAI4Q2wcfh5hExkKGghSCAkqXztQbiYmcXNMNzckAiQXRDxJMmUSckJaVzU0ZhgqAm13LDFBDzobJVtZAxgVKlYnHXcsPgccfh5LB1ENDRVdJykdd1NFfX19fX19Lz0tIGonKT8GZ3YPfHx8A38vLU82eQBUd3V8fHx8fH9/f38hIA4nKVRof39/f39/f39/TSFpDnBgf39/f39/f4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQAA4D8AAOB/AAA=","fav2012":"data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEAAAAhAAAAIQAAACEAAAAhAAAAIQAAACEAAAAhAAAAIQAAACEAAAAhAAAAIQAAACEAAAAhAAAAAAAAACFGmovGS7O60V6Ee71yRyygbUMqmGtDKJmMcF+yhG1eu2pBJ5pjPCSQYTskjmA6Io6SeWr/knlq/wAAACGhtKyvarKV/2jc5f9n3OT+kqOX9bqAYP+9hWb/6OHc//////+2fl3/uYBd/7h+Xv+4fl7/uH5a/7h+W/+uo5z/pbewtmmylf9qs5X/aNzl/3Pf5v+itq7z5NnT///////ay8X/uH9c/7h/Xf+4f13/uYBd/7KqnP6Z0tb/lcPG/6a3sLX///////////////9o2+T/6fHx///////u6+n/xKST/7mAXf+5gF3/r8W//5fh5/+X6u//mujt/6+ytf+lt7CwarOV/2qzlf9pspX////////////d6+z/r8G8+bmAXf+o1tf/luju/5jq7/+e4ur/pc7g/6a82v+vsrX/pbivsWqzlf9qs5X/stHC//v6+v/b5uH/jNTT+5Xp7f+X6vD/m+nu/6Te5v+uzdn/sMPU/63B1/+rvtf/r7K1/6e4sbFqs5b/wt3R/9vn4//7+/v/1ePe/2qzlf+Y4d77nuzw/67c4f+4ytH/jJit/7PF0/+xxNb/r8HX/6+ytf+tvLW5/Pz6/+nw6/9wt5n/cbea/97p4v/P4df/arOV/6Pn5Pyq7vL/ttve/1NSsv9+ipD/s8PP/7PF1P+vsrX/rry2uv7+/v9xt5n/arOV/2qylf9qs5X//Pz8/8Dazf9qspX/ruvp/LHs9f8zJcr/aXF0/2lxdP+hsLn/r7K1/6+9trr+/v7/cLaZ/2qzlf9qs5b/arKV//79/f/r8Oz/arOV/6raw/+Gpen+LBfS/0FDk/9pcXT/aXF0/5mdnv+xvri5/v7+/3C3mf9qspX/arOW/2qzlf/+/v7/8PXy/2qzlf+jzMX/LBjS/ysX0f8sF9L/QEOS/2lxdP+ZnZ7/sr64uf/////S6N3/arOV/2mylf/S6N3////+/9Xi2/9qs5b/LBfS/ywX0v8sF9L/KxfR/ysX0f9pcXT/mZ2e/7LAubT1+Pf//v7+//7+/v/+/v7//v7+//7+/v/+/v7/sNzE/zIr1/8sF9H/IiFe/ywY0v8yJ9b/arKV/5XDxv////8AarKV/2qzlf9qs5X/arOV/2qzlf9qspX/arKV/2mylf9ERdn/KxfR/ywX0v8sF9L/Pj3W/2qzlf////8A////AKzWwB2t2MQXstnCF7TbxBe43McXu9/KF73gzBf///8A////AEpQ2vssF9L/SUza+////wD///8A////AP//AACAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAAP/HAAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAERI8MFkyrJ/oNMDA7DC6vdwyuLzeZ4uC8Y9CLtaKPyzNij8szYk+Ks2JPirNiT4qzYE7J8B9OSi/l29l25x3buKXb2bedDEhu3Q1I7B0NSOwczQhsHM0IbB0NCGvay4dpGsvHqJqLh6iai4eomouHKJkKxqdUCATewAAAB8AAAAWNZd77kK0mf9B39//Qujs/0Po7P9F6ez/haOa/7tjTf+7Y03/umJL/7piS/+6Ykv/umJL/7hgSv/26Ob///////////+tYE7/umBL/7lgSv+5YEr/uWBK/7lgSf+5YEn/uF9I/7hfSP+4Xkf/uF5H/7heR/+2XUb/bTUncAAAABdBrY7/RK+S/0e4nv9H4uL/Surt/0vp7f9N6+7/i6qi/8JtWv/CbVv/wm1b/8JtWf/CbVn/wX9w/////////////////7dzZP++a1b/v2tW/79rVv+/a1b/v2tX/75qV/++alf/vmlX/75pV/++aVf/vmhW/75oVv+LTkKJAAAAF0Wwk/9IsJL/TLSU/0+6oP9Q4+P/Uevu/1Lr7v9W7O//kbCo/8Z4Z//GeGf/xnhn/8J6af/w4N//////////////////vHlt/8R2Zv/Fdmb/xHVl/8R1ZP/EdWT/xHVk/8R1ZP/EdWT/xHVk/8R1Y//Ec2L/xHNi/5+Rot8AAAAXj8W2/0qxlP9PtZf/U7aY/1S9pP9W5OT/Wezv/1rs7/9b7vD/l7ew/8yEdP/HiXv/8eLg///////////////////8/P+/emv/y4Jy/8uCcv/KgXH/yoFx/8qBcf/KgXH/yX9v/8l/b//Jf2//yX9v/7efkv+Z0tH/jd3m+wAAABf++/v/o8zB/1WulP9Utpr/Wbmc/1y/p/9e6OT/Ye/w/2Lv8P9j6+3/rMPC//709v//////////////////////38K9/8uLff/Rjn//0Y5//9CMff/QjH3/0Ix9/9CMff/QjH3/ypKF/666tP+P6On/hvj6/4j4+v+M4u74AAAAF//8/v//////9/j5/77Z0v+Txbf/ebup/2q8qP9j3Nr/ZuDj/7fq7P////////////////////////////bp6f/Olov/1ZiL/9WYi//VmIv/1ZiK/9WYiv/VmIn/xqqd/6PRzf+J9PX/h/j6/4n4+v+M+Pn/jfn6/5Pl7/cAAAAXZLac/5vMvf/O493/9Pf2///////////////////////////////////////////////////////37Ov/06OY/9qilf/bo5f/26KV/9uilf/ZpJf/u8C5/5jl5P+H+Pj/iPj6/4v4+P+O+Pj/jvn6/5H6+v+W7PT/k8Xb2AAAABdYt5v/Wrqd/1y6nf9duZ//aLyi/33Crf+Sx7f/////////////////////////////////5Ozs/9mrof/fraD/4K2h/9+sof/Ttaz/rtPQ/47y8v+I+Pj/ivj5/4z4+P+O+fn/j/n5/5P4+P+a4u3/osfg/6O62v+TqcfCAAAAF1q6nf9dup7/YLuh/2K9ov9lvqT/Z76k/7/d1P///////////////////////////7/s7v987e7/rNnW/+G1q//Ix8D/oOPi/4j3+P+J9/j/i/f5/473+P+P+fn/kfn5/5fz9f+i2+r/qcXb/6jA2v+mv9r/pr7a/5esx8IAAAAXXrme/2C7oP9jvqL/Zb+j/2jApf9qvKT//v////////////////////////+g5OT/f/Dy/4T19/+G9ff/jvLz/4n3+P+L9/n/jPf5/4/3+P+Q+Pn/kvj5/5zr7/+p1OP/rsXZ/63E2f+sw9n/qsHa/6rB2f+nwNr/mK7GwgAAABdhu6H/Y72j/2a/pP9pwKb/bMKo/3S/p///////////////////////sdfK/37PuP+G8O//iPb4/4r3+P+M9/r/jPf5/5D3+P+R+Pn/lfb3/6Tk6v+w0N3/tMrX/7LH2f+xx9j/sMXZ/6/F2f+txNn/rMPZ/6rB2f+ar8bCAAAAF2S9ov9nv6T/aL+l/2q9pP9qu6L/a7ig//X4+P////////////////+Zy7r/gc6z/4fTvf+L8/H/jvf4/5L3+P+T+Pr/l/f4/67g5f+50Nn/uM7X/7fM1/+yx9T/s8rW/7LK2f+yyNn/scbZ/7DF2f+uxNn/q8TZ/5yxx8IAAAAXZ72i/4bDsP/F39j/7fXz/////////////////////////////////8zk3P+Cy7L/iNG4/4rWwf+S9PH/lfr6/5b6+/+Y+vv/qufp/7vR1/+70Nf/us/X/251vv+MnKv/tMvX/7TL1/+zydn/scjX/7HG2f+vxdn/nrPGwgAAABfV6eL///////////////////////////////////////n7+////////////7zb0f+Iz7X/jNS7/4/Zw/+X9fL/nPr7/537/P+f/Pz/r+jr/7zR1/+60Nj/RD7I/1xmff+fsLj/tMrV/7TL1/+0y9f/s8jY/7LI1/+itcbCAAAAF//////////////////////P5d3/f8Os/3vFsP9/xrH/f8ix/7XYzv///////////9Hm3/+Lz7n/kda+/5Xbxv+e9/T/ovz9/6P8/f+m/P3/sunr/7HC2P8jEt7/Nzxf/3B8gv+Roqr/scbR/7bN2f+0ytf/s8nZ/6S3xsIAAAAX////////////////0OXg/3jDq/9+yrH/gcyz/4POtf+FzrX/hs+2/73e0v///////////9Pm4f+Q07z/l9nC/5neyP+k+fX/qf3+/6r9/v+r////hqbn/ycT7f8oJnL/VV5h/3N/hv+DkZj/orS+/7XK1f+2ytj/pbnFwgAAABf///////////z+/v99xKz/fsmx/4LMtP+EzbX/hs62/4jQuP+L0rn/j9K7/////////////////7PXzP+Z2MP/m9vE/5/gzP+r+vf/rf///6////9Za+f/JxPp/x8UrP9NVVn/XGVp/3SBhv97iI//kJ+n/6q+x/+lucTCAAAAF///////////t9nN/33Jsf+BzLT/hc21/4XOtv+I0Lj/i9O5/47UvP+O07z/////////////////8Pj1/5jUvf+f3cX/od7H/6Tizv+w+/f/pOP7/ycZ2f8lE97/JBHc/zQ5XP9WX2L/Y21w/3aDh/9+ipH/iJee/5iqsssAAAAX//////////+Ix7L/gMuy/4TOtv+Gz7f/idC3/4vSuf+O1Lv/kNW9/5HVvv//////////////////////n9K//6HeyP+j38j/pN/J/6rl0f9cbuX/IxLZ/yMS2P8kEdz/Hxeq/1FYXf9eZmr/aHR2/3eFiP+CkJX/kqKnzQAAABf/////+Pz7/33Gr/+Fzrb/h8+3/4nQuP+M0rr/j9O7/5HVvv+T1sD/ktW+//j8+/////////////////+s1sf/o9/I/6Xfyf+n4Mr/f6LP/yMS2/8kEtv/IxHZ/yQR3P8kEdz/KS14/11laP9mb3L/cn5//3uIjP+PnqLNAAAAF//////4/Pv/gsqz/4fPt/+J0Lj/i9G5/43Tu/+R1b3/kta//5TXwP+b1sH//////////////////////67Wx/+l38n/p+DK/5rKzf8sItn/JBfe/yUX3f8kFd3/IxLZ/yQR3P8kEdz/P01s/2RtcP9ueHr/e4aJ/42bns0AAAAX//////j8+/+FzLT/itC5/4vRuf+O0rv/kdS8/5PWwP+U18D/mNjB/7jg0///////////////////////pdPB/6jhy/+j2Mz/Ul3Z/ych3v8nJtv/Jyfl/yQR3P8kEdz/JBfX/yQR3P8mH77/YnuN/4CLjv+CjpL/jJuezQAAABf/////+Pz7/4jMtv+L0br/jtK8/5HUvf+T1L//ldjB/5fYwv+Y2MP/5/Tv//////////////////b7+f+g2ML/qeLM/3OQ1/8qKeH/KDHe/yo45/8rONH/Ki+F/zE2uf8rK+r/Jhvg/yUT4/9ZbtH/uOnr/7LEx/+er7HIAAAAF///////////jc23/43Tu/+S1b3/lNW+/5bWv/+X2cL/mdrD/7Ddzf//////////////////////wd3T/6jgyv+t483/W3Ld/ys44P8tQeP/Kz/k/y05if8nKzT/JipV/zA95P8nJ+T/Jxvf/0pS5/+4////u+7w/67AwsQAAAAX///////////M5d7/kNS8/5TVvv+V1sD/mNnC/5raw/+h2cX/+f78/////////////////+n08P+i1sD/rOPN/6/kzv9nht7/LkLh/zFL4/8wTuX/JjOS/yswX/8qOJD/LEHj/ykz4/8oI9//T1rk/7j///+4////tufo7AAAABeg2ML////////////Q5+D/m9bE/5jYwf+Y18H/sN3O//f9+///////////////////////u9vO/77k1v+w4s7/seXQ/5G92f8/V+T/LUvd/zhf5P8yVNr/K0XA/zBN4f8vRuT/LDrf/ygo3v92mer/uf///7j///+58vL4AAAAF47Quf+Xy7j/1uji////////////9fv6//v//v////////////////////////////////////////////z//v+949X/tebS/4qz3v8zV+H/MFrb/zxq4/85Ze7/NFXl/y5F3f8sO+H/XnHc/7Xk2/+4/vv/uP///7v29P8AAAAUkNS9/5PVv/+S077/kMu3/6HLvf+Qy7f/kMu3/5DLt/+Qy7f/kMu3/5DLt/+Qy7f/kMu3/5DLt/+g2ML/oNjC/6DYwv+x3Mn/t+jV/4644P9BbOP/OWXf/zZd4P8zUuH/NEzj/2eD4v+769b/u+vW/7vt2/+4/vv/uffy/wAAAAuk3sn/ltfA/5jYwf+a2ML/nNnE/53Zw/+h2cT/otnG/6Pbx/+l3Mj/qN3J/6reyv+s4M3/ruHO/6/hz/+y49D/tOTQ/7Xm0f+66NT/vOnW/53K3/9sl+H/WoHg/2GE4v+GrOD/t+XY/7zr1/+869f/vOvX/7zu3P/D8+v1AAAAA7nd0Xq15NX/teTT/7fm1P+459T/u+fW/73o2f+96dj/wOra/8Pq2v/D69v/xezd/8bs3f/I7t7/ye/g/8zw4P/N8OD/zvDh/8/x4v/Q8uL/0PLi/9Dy4v/Q8uL/0PLi/9Dy4v/Q8uL/0PLi/9Dy4v/Q8uL/0fHj6LTPxSj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AMAAAAOAAAABgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAACAAAAAgAAAAMAAAAH/////","fav2014":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAwBQTFRFrszyPZD0wMDA+NvYzeTXisuq4F1Srq6u7e3tQYn0hy4pP4jt3lFFqcdQqMdP76ultbW1gSwoQbBu79p7MatrmNCz1Ug8QIXsNqxtjcyrLalr3ldM6paPbsGROKxmZL2IstrFUrZ/10s/PIrt1kk9Oa1tOq1mMqplKqdk3lRJGaFf2Es/2Ek8QIbttT82P4fttD00tD41/95H/95I8vLy3Es+3Es/HKJhw8PD3Ek83UxAHqNi3U1A/95J3U5C/91GH6Ni/91FPo/0I6RjJaZj/95GqshSP4703U1BP4/0GqJgJqZjwsLCIaRi3U5BIKRiQIz0gCwnP430MKlkQYr0KadkPo30P4z0G6JgJ6ZjLKdktsCHPpD009PTIqRjJaVjLqllPY/0t8GHJ6ZkqshRQYz0P5D0IaRj/91E+uaHr8ryu7u70tLSP5H0NKplNqtl5ubmKKdkpdW8N6xm39/f8PDwG6JhO65uz8/PQIr0762oQYv05eXlJKVjLahkPY70JKRjPYnts7OztsCGPpH03U9DP69t5u3p7u7u5u7proqH4ODg6LNFy2dfH6Jh9NZO5OTkrcTqXbqIHKBgQYPsXbqHr87zO61sl9CzKqhqPI/05+fnwN/PP69qx6Kf+dlDrNi91UxA1NTUOq506urqcMGR8+i3ecSauGRdPIvtO4ztv7+/0NDQ00g8xpGN1ZaRvt/OWbl9s7yAVLeG3IB4VriH+NzZy1hOrKWlRLFuSbN2roJ+/NxH3lVJr8vyzL28t8GIw19X0XRBHqJi7dDNH6JiyUxCqchQ31lNHaJiy+PX2U1CymBYMapkzuTXVbh99M9Gz0Y72engl2ZLs315uXp1k86sQI700E1C+9tI1U9Ez1I/r8ny5bi06pGKNKxs1pVbQIv0kc6rmtG0xebRy1NJz1dNrZ+etra2xlJJqnpg31ZLWX9UrsvywVhCKKZkw1hP21BFqNa9q9e9PK5s8tRN5e3pz1xTvb29d8Sa3t7e/t1IHaNi3Eo98fHx////VMCZsAAAAQB0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AFP3ByUAAALsSURBVHjabNFlWFNRGMBxOiUGiHRJSSjcXWLEmAsZjjFwG45OASUFlRCkw25ssRW7G7sLuxPs7tyG7z138vhh76c9z/+395znXJUeZaNuo9UxQMtGHX6qKOsVZ0JCgvz9/TqMlIOKDi4JZI1GysBuazqXSwJZH3UAT7ftMzFp+jrPxeKRmZmV1YLXjfQorpOvrzMA2kMAna6udoUFbsLUePcMdk02Q6uRznXSo1D0nAG8AbDE1a5k9c2url/x4gw2K/ukNZ3OHUihxMT4APgEwM6uZNkX24m4o7uYx2bxp92l06N6gTmAwkJ7vOniWnyW+2heSrLg+G0AcEQMHEGjXQFQUGCP2wpL8blwQk0y4+w1uGOIk68PXJJG2wnAzW1/86XSLg0LWMDiM6RvzwMICvL3A+D1AIBQKOz83HwVOpuVLAiWzn4fpXgnGe0H8VCpqRMmuGjglnG8KqJLDaYsVyyQbTpBgPh4x8UaliCqiAOkQ0LvHPt3wjr0LcTi790f4ngOW1nZjGDo1D+X75EnnNqLQFwc3s1jp/R14JOdih187Eks8DpQhwCbXYwXa84/txL1UCqGmZZdIBZ81M5FgMVi7dLU3AEZdSpmmpS31BMWTDJWQ4DPFwgEREb7qdjIoqSksj0y2Svt3EgEgmGgSgMUHceLkvI2y2jXjdUCEZCiCUAdIzqIvMPm5i9yI0kQQE4m8XfsSCt0ubxy4/Nn2j//A+MkmUTG0vPzW6HL5TOmHq3bEEgCiUQCHSrGSc/PyopQIcDYLTdeqinAUJjTROakNyRmRUSEI6GzAq7QCww4MGEJDYlM6OG33hErWn4HKoCHhwEnDCYhkezDhkcfInbIJweS7+BhGIa6qiqTyUR9xPhRSIwhgeFgYqCnQY9FXSRSCATaiF6PeizqT0QiXV0kdBCYnpOTU6+6MK26GvXoclG5Lsx9AIsQWPOtbfv69vb2/rW1tfr6+oO8vb37wcyZuaqypafnrwADAIImCi/KO69rAAAAAElFTkSuQmCC","fav2015":"data:image/x-icon;base64,AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAADx8fEAPeD+OkDb/Mqmrpra9IlI//SJSP/0iEf/9IhH//SIR//0iEf/9IhH//SIR//0iEb/9IhG//SIRv/0iEb/9IdG//SHRv/0h0b/9IdG//SHRf/0h0X/9IdF//SGRP/0hkT/9IZE//SGQ//0hkP/8amB0fDw7a3x8fEm8fHxAD3g/jpD2fz3RN3//0HZ+/ymrpPw9IlI//SJSP/0iUj/9IlI//SJSP/0iEf/9IhH//SIR//0iEf/9IhG//SIRv/0iEb/9IhG//SHRv/0h0b/9IdG//SHRf/0h0X/9IdF//SGRP/0hkT/9IZE//Knfezt7Oz68fHx//Hx8e/x8fEmR9DKr0Xd//9F3f//Rd3//0La+/yrrI/69IlJ//SJSP/0iUj/9IlI//SJSP/0iUj/9IhH//SIR//0iEf/9IhH//SIRv/0iEb/9IhG//SIRv/0h0b/9IdG//SHRv/0h0X/9IdF//SGRP/uonf57e3s+vHx8f/x8fH/8fHx/+bm5qZeoRX1StPR30Xd//9F3f//Rd3//0La+/yurJH/9IlJ//SJSf/0iUn/9IlI//SJSP/0iUj/9IlI//SJSP/0iEf/9IhH//SIR//0iEb/9IhG//SIRv/0h0b/9IdG//SHRv/0h0X/86d6/+zr6/vx8fH/8fHx//Hx8f/o6Ojhzc3N+V+hGP9foRj/S9DK50bd//9G3f//Rt3//0Ta+v2urJH/9IlJ//SJSf/0iUn/9IlJ//SJSf/0iUj/9IlI//SJSP/0iEf/9IhH//SIR//0iEf/9IhG//SIRv/0h0b/9IdG//Ooe//s6+r88fHx//Hx8f/x8fH/5ubm7NLS0v/S0tL/X6EZ/1+hGf9foRn/SM7E7kbd//9G3f//Rt3//0fZ+f6urJH/9IpJ//SKSf/0iUn/9IlJ//SJSf/0iUn/9IlI//SJSP/0iUj/9IhH//SIR//0iEf/9IhG//SIRv/zqHv/6+no/fDw8P/w8PD/8PDw/+Hh4fTT09P/09PT/9LS0v9foRn/X6EZ/1+hGf9foRn/S8y/9Ebe//9G3v//Rt7//0fZ+f6urJH/9IpJ//SKSf/0ikn/9IlJ//SJSf/0iUn/9IlI//SJSP/0iUj/9IhH//SIR//0iEf/86h7/+vp6P7u7u7/7e3t/+3t7f/i4uL50dHR/9LS0v/T09P/09PT/2CiGv9gohr/YKIa/2CiGv9gohr/Tc6890be//9G3v//Rt7//0fa+v6vrZL/9IpJ//SKSf/0ikn/9IpJ//SJSf/0iUn/9IlJ//SJSP/0iUj/9IlI//OofP/s6uj+7u7u/+zs7P/q6ur/2tra/M/Pz//Q0ND/0dHR/9PT0//T09P/YKIa/2CiGv9gohr/YKIa/2CiGv9gohr/Tc25+0fe//9H3v//Rt7//0jd/P+vrZL/9IpK//SKSf/0ikn/9IpJ//SJSf/0iUn/9IlJ//SJSP/zqXz/8e/t/+7u7v/t7e3/6urq/9fX1/7Jycn/y8vL/83Nzf/Q0ND/0tLS/9PT0/9hohv/YaIb/2GiG/9hohv/YaIb/2GiG/9gohr/TMq3/kfe//9H3v//R97//0jd/P+vrZL/9IpK//SKSv/0ikn/9IpJ//SKSf/0iUn/86l9//Hv7v/w8PD/7u7u/+rq6v+sr9n/lprK/8XFxf/Gxsb/ysrK/87Ozv/R0dH/0tLS/2GiHP9hohz/YaIc/2GiG/9hohv/YaIb/2GiG/9hohv/Ts26/0fe//9H3v//R97//0nd/P+vrZL/9IpK//SKSv/0ikn/9IpJ//Opff/x7+7/8fHx/+/v7//s7Oz/29vb/3+E0P91fc//wMDA/8LCwv/Hx8f/y8vL/8/Pz//R0dH/YaIc/2GiHP9hohz/YaIc/2GiHP9hohz/YaIc/2GiG/9hohv/Ts26/0je//9H3v//R97//0nd/P+vrZL/9IpK//SKSv/zqX3/8u/u//Ly8v/x8fH/7u7u/93d3f/IyMj/Y2zS/1tk0/+8vLz/vr6+/8LCwv/Jycn/zc3N/9HR0f9iox3/YqMd/2KjHf9iox3/YaIc/2GiHP9hohz/YaIc/2GiHP9hohv/Ts26/0je//9I3v//R97//0nd/P+vrZL/9Kp+//Lv7v/y8vL/8fHx/+/v7//h4eH/ysrK/8DBxP9DT9j/P0za/7Kyuv+7u7v/wMDA/8bGxv/MzMz/0NDQ/2KjHf9iox3/YqMd/2KjHf9iox3/YqMd/2KjHf9hohz/YaIc/2GiHP9hohz/Ts26/0je//9I3v//R97//0nd/f+t6vX/8vLy//Ly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","fav2020":"data:image/x-icon;base64,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","mi":{"bookmark":" ","close":" ","directions":" ","directions_bike":" ","directions_bus":" ","directions_car":" ","directions_transit":" ","directions_walk":" ","help":" ","history":" ","language":" ","layers":" ","link":" ","my_location":" ","people":" ","place":" ","print":" ","public":" ","rate_review":" ","satellite":" ","settings":" ","share":" ","swap_vert":" ","terrain":" ","timeline":" ","traffic":" "},"gl2016":"data:image/png;base64,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","ddStart":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAtxJREFUeAGtlkO0ZFkQRb9t27ZtG5O2u79SrcKsbGtctm1jVrZtu2Y36sQ302etnby580XEk4GS+IM/wTywuJMFoBkEG2gQKzAWPDexMCa3cHsKyvWgoDwPcotwIFNLY8J3r8BkYKtKFghOWTqaUUZzJP20plhIjtYK2Yl6YiTHasVP64tFliSKrF0tWHwRRAwlCwEPfJKd6bct5UJxooEF1Hqopg/8GX/3x/YK4Z/pztJnIAb0iSU47ZPiQq0Ha4TkeN0A0UBxHUkO14qAbA+WXgF2vYWjrZzN6PetFd2yLGm0GtJaatpVKWw9rVg6vUvmCe5zX7iUrsXh5T68iFJ+DVMqleM3Bf/HEQ8RBLLwexNzI/plfYnAPw4QAqViydEa+mNbuTCzNuF1f7FwhmuYffsEsWBIoTKx9ESd8Ih14u/nsHARN1bG5SoV9iWmIaBP2SEl3sQuFi7WhzC0l3CWPkr2jGsveS4Lf2gfygbthtKGofBObmZjyuuaWOgNHmUrYkiu5W5TODKB174EIaA9Y6yczTH+Ct5KzXbs3VVdO/YM0B0bcMk/y50kh2r4hKBS1nakXSiCi7xYdgs4gT4J59KxgI9T0XZYqRCDqBcRVb4sewHiwKBJAu9Sfgvj3ijtW7Y8mmVfQC5Qmm8B1c3J5PPgwL6dqKNvF+cLYzMjFkqAWlnmFGhLTfurBXrVt9TjdcI3zY1lBw00SAB4myWN6lM6b3HVlDTBFYAsoFGm2XpYUdO+qu4B8RGBkzDLtgGN4wvel41Nbt8yyfHa9t4ZGhqysAxolRV84mAhl576exjLzgGt02iOY/R3HEFcrluEPQvH6yJ0AW9rZmXQb5vLhJGpEQszgU45ltkWSbWQ4vUTYK2rcA6fedL+imDhXqBzmjxinPh2hIUz9CEss3GzIDtvaxb+qQ9hkpGJEXUOpFQfwlAgAIF0fQjdwMdOYYg+hObgOngA7IHSfAXLiZ+EcHMKogAAAABJRU5ErkJggg==","ddEnd":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAAABGdBTUEAAK/INwWK6QAAAttJREFUeAGklgOMLVkQht8b27aNtce2bdu2bQRrRxuuzThr27a9XfvXoMdX/Sff4NbpL7dOtc7JiDOoApvglj22QS1wBwpHD0yAr/U1NekyW2vK8nanbHCFnQ0ZaGkSat+BOWAIZMYVPGdroE9LEVfRp41lAg20CDTSTgz//XlTubARFUKOhgYsfhX4nCXzAJ/EujjSt21VAo11Eg22EvU1HWWwhbj2Y0ctpXm4svQrEHBcpguej3N1pL/6momGRNHZYM2/kGd4urH0DWAExIzZo82v22sEUaYI6ODHrnrBzcSIpUv7Mlvw8Wr0NdyKuHjs6kspzNHuVLgmSnHMdQmRxEMEriws0NPUoE+bK3jTxYV8IGqnwjVRiGO+RWemOtpcq2bh8sU2VuIAlBYyw20Uurt+nYU3p3q6Eo10qC4c7aBCPy9i144wDZOiUWnCIn9vUbh6ia3UltspzMmeaxssLORL7LOWShWH0kzfdYhDqWGhPfhsKzZMtdMG7d6cFM2yb4EH2Mm4A07sbztqBbF1RcCV8nN3g+BhYszCZSDGALyWjmn/ixuA2LoM0Crvu7A33feAGTgSb/BZga8nrtM2ov5m2UIMoibYj2XfgCBwai4CP01cczn2pvNsGfZ6MyaUZX+AECAzeecxySeKMvkeeFKGb/9KTZGgp6HBwkagUG4PsDSnP3obheOtszDRzZlljwOF4wJ+XIsOOXoFYd/uy01hGXMVUCqLrrjP/d7TIH5LvgnEujqx7B6gdBzBL3dlJPBe7lyar9UUkdr58yyMBSrlTr5xsJBbnwi5nGUvAZWTYaajQ9+31xC3e5mdNQunpAgtwI+PF6TTN23VpK2uzsIrgaQ8sxJ5DT1ekMGyL4C+VOF6RaAvzYVfycKHgeTUhDja8euIeEeRmlhnY0PyMjNhYRWQnIu01NX2BxIDJMcTCIDA5UByrMCvgIAHkBxt8Db4BPw/fkKKAcqj4hv5aDBTAAAAAElFTkSuQmCC","greenA":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAADMElEQVR4AWLACSboyANxMhBPAuIFQLwQyk4GyxEECIO4gLiRZZLuJyD9X2SW0U/hWUb/ofgnSAwo9xFI1wMxJyHDFFkn6V4DadIDtFYOsHI2URj+rm3btm2v/r+2bbuNa9s2gtq23aiK6zaq29PzXq85yZPMnXnPM7q7uzuf+lwU0/DrMjl6XxRREs8hY7U8+ana3fJEpPnSpPc+GzJ+92bRMC7WRC8WI8s177g2XFFmZ7Es6Qkf73fvCyy7JtOJXhdEhBqufcQO29ZC3Ad1PFPDQakSseIgcvKzVznX8XQ1jg9mNMn8eIW3uQeKqDevOOyqVI7+J2uJU+QZ5Ux1s7OU5nufF1HO/iKyZAdcEHZheKUaGsoBRbL6xVCsKIjKp6VSQJqHykwHroUDLggXeK3L+D70Ck+qAEf9b3k+9TtRSzaOVtRjf4XKHBxwQbjZbU0aDb0sVaJuVhY5+do3/x1bF0QpHcNVZl3ZAVezcAgPKhJW5Eu4u6y+MQB/Y5cqs62Fi3zWZ9CQSxI5uu8rJzyGP99bayAsm5KilIcDLgi7MtThRLVcILlDGHakVFgwIgG7lhtrz7VwwAVhAD/555x9RTTkoqSJhp1MTkFfju57G3beYWNx8xhq+SP7BS4BzXp58hys0ONMHQ3mAEQQoq8K7DymLojQRw1q4Wj9SXG0Wpb8OnZbLg2+INEL1KAWDsXPcwy2XS89L9EJZHFdqFX3jZPOgZ+JO/Jo0HmxRpBBFjWCpua4MqVv/ffhznwadE6sEswhU5/VpTmtSj3lsy5DrRBz7mvSrunzMxDK9/krcTsf/axYDozxI/xBRtCn8Q52u6xOpYEsaQ3G/NZnHBP0bksSg/jS/0RvzaWBZ1jGoM9jf8M2ZScIhjTPNel3Azdk0sDTIkDo+6/PfCEY2oI2ZI3Faw5gGUA/aXvecoOFLPC0Xpb8d8ApEQHuU/G+4jTBmOaxJv1L3p4iAl5r078Jxja+txvhm7IJ8GM8M1oYtTlnc8jGLAKJ2/IOGS2M3Zo7nl+bQBz3jRbyrvAzSyBzV8EAo4UsimoS8n2mm0LozVAjXqYQ2pixDHDfWlv8H4JiKPd9OJuJAAAAAElFTkSuQmCC","greenB":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAYAAABfqvm9AAADGUlEQVR4Aa2VA4wsWRSG69m27dd297Ntc2zPBGvbY9szwdq2vdEqXts6+/+Vrkr1WDf5UjcHX100lE7H3WsXgEiQDSpBFedqjLkeDopGg2uGZpt+wlOmFtv/nFJslyB/Mobcj3heBUZ1J1s0LNv0EZvMDX4Jf3avJL18IISwZ/eICTnWDMsxf9jpapFYOvge09czSh3/hEGUiOauuAgxa9HzFXoXt5WNGpJt+gDb+yfsGcheOtAjLj6zR9iD3vfgGGkUXgXkxBM7Ubhf5VCuX5AJYdys0bL1MivzOice38Htkys02Sy84Utv63oJwxsTX9xPNCGfOu7IFVpMrwt7eo94Wtbzor6ki8LTAG/aKQko0DgYFBpjZI5tirggNsaOo5cOuii8fVqx44+EF5A0cDAnKDTEIh/ZpW57902ukDihgy4KKyYV2iTheSQMHMxWhVyRzoixw2TR+pnMt2MiHHTpwngEjWhCV8QKnZW756mxzZda29UbhXfOKHFI/HP7Qjh4j4/N7eKB5DVcabs4HXRReAbI8Ud29Ei46wZnu/gx9NJBF4VzcOXfe5rXS/yz+3Q0IZ8au653ytSl47n1kFr24iv7A10Kx/Ac8818w/kndkscCsiBoNAIt7oCsvAHd+p17GEvHcZvythh2ebPV1Z7Je6Zfb2CPeylo+33eQWXrUqf3tcjWMvjYm9nvzh2FPy1ttYnsU/v7RLWsJY9SldjbJ4lAkVirvNL7FN7O4Q51qi1PRnj8q2PzSh2dCpkbnKh7aXe/A0sxHn+vbYGW39ybwiM4RL+ZY3Sm4EVNEwosEoMJEYYm1XieKinHuMq5+HQ/11e5ZWYJyADnCP236Jy9xqlL2Nqof3NuaVOiXl8jwrns0ucnyh9HfNKXRm8zWjICOemGl9On4UQTB2ebf4v+jEIAeayoXmDTenPmFJo/8HXuF7ItCL770p/B87tlcXlbiG4jI/6LVxW4alYUOYSsrbad1+/hSurvFm4bSGrMO+3EKtS/2aJsz4Q3W8hRMs0Ic7TPhDC6ZoQTBsI4YhBkBHMh3dX/j/NiBidxCfDOAAAAABJRU5ErkJggg==","ddVia":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAbklEQVR4AZWRxxGAIBREOdkFZ8qiQvqwHrMnXJ45687Az9lskOl5vVyvhyKj38HqlXrx/NDbbUYcnXMxhBDruoZK3gZQwc+OF9gE4EdvZLoAepzxG4eh9AXQ44zfj8y/ev61jc97VhHz6YLJMb0BCR3NHHabnbcAAAAASUVORK5CYII=","bluedot":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAADBklEQVR4nLWVTU8bVxSGn2vPmCbIBgNOIwKLpioC2hRQK6tRPpbZIbGIhJR1l/lJ+QPsUDZddUerCiFVLapAQVTUgPmwje2xPeOZ8czNYs4VE8eqVLUd6V3MvaPn3HvOe84oRjyZba2AUQLQw4o3lB5mqPSLADMiK6WsrAHEQAQMUoqBOB1ADUGzAsoBn6SUk3UEFAD9lAJZjwxcDUFzwBgwDhSAvOiu7CEQF+iIHKAH+LIXxRtKm1OYq48JsAiURFPAhOwhgDZwA9QkYFYCxJL3yErlNScnLQKzwDx9f0lf18u6drVI86qA14KsdtS92UP1+Ze7FEsHgC0BI6PMto5VZltn5DR5YAZ4ADzUrfZTfVzZXJ57ZOdnoeND8xTcdy280x8Iov1QvXi1pT77agf4EzgH6pIePyN5tqRIeaCE6y7pg4PNJ2uP7Pvr0FiB83m4mIJ2cZIg/zV05mz99s0mjYslSVleGBagRoGn9FmlvDD9nZ1dhso4VPPQHpOEqXaS4uwDaBdsvf9zWeowEmwcMQ5M6LPjxTuTUHGg2gS3DlxLuXrnibNUDP40+ui3RSmucU4WUJaAjStsYIzGWaHrQuMvgfYlg9Uj8FwIfBgE4Ftwc1WQGhmvZwz448dzcKrQceVT7xJ6DnS7iXo98DwIAojjkQhLfBcn9yMEfHK24578VGRiGnKDxEV+PwF2uom6LkQOTJYcbpvDtLc24Eg2eoCj5h4eBnu/PKb/DeQUqAgGYQLuudDqJtexa6gvnh0m1cQVRpQGDyRqF2iohbW9cO/Hb7mybOz55NsohH4fep7k6BI+7Ydq5dmulLUj1RgAOpMCeyRtWePe/B9q/fstckchzh7UKnBZh1oTOtdgn8BcK1QvX29Rmj0gae0PwEpa2gLukMyJGUxL1y+W9O87Zf3u10VurgtoDZMlRy2sHqrV57sCPQWqJF3nyAEHZrplxWoG/k+GUA1opqBhvKEiYzfjCl8+MMV0SFpjnNth83dj07jifx70Q/D/9tc0IsC/+pm+Bz0JiTMMwUQLAAAAAElFTkSuQmCC","kit":{"more":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE4IDEyIj48ZGVmcz48L2RlZnM+PGc+PHBhdGggZD0iTTAgMGgxOHYyaC0xOHoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iIzYxNjE2MSIvPjxwYXRoIGQ9Ik0wIDVoMTh2MmgtMTh6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM2MTYxNjEiLz48cGF0aCBkPSJNMCAxMGgxOHYyaC0xOHoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iIzYxNjE2MSIvPjwvZz48L3N2Zz4=","search":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDE4IDE4Ij48ZGVmcz48L2RlZnM+PGc+PHBhdGggZD0iTTEyLjUwMCAxMS4wMDAgTDExLjcxMCAxMS4wMDAgTDExLjQzMCAxMC43MzAgQzEyLjQxMCA5LjU5MCAxMy4wMDAgOC4xMTAgMTMuMDAwIDYuNTAwIEMxMy4wMDAgMi45MTAgMTAuMDkwIDAuMDAwIDYuNTAwIDAuMDAwIEMyLjkxMCAwLjAwMCAwLjAwMCAyLjkxMCAwLjAwMCA2LjUwMCBDMC4wMDAgMTAuMDkwIDIuOTEwIDEzLjAwMCA2LjUwMCAxMy4wMDAgQzguMTEwIDEzLjAwMCA5LjU5MCAxMi40MTAgMTAuNzMwIDExLjQzMCBMMTEuMDAwIDExLjcxMCBMMTEuMDAwIDEyLjUwMCBMMTYuMDAwIDE3LjQ5MCBMMTcuNDkwIDE2LjAwMCBMMTIuNTAwIDExLjAwMCBMMTIuNTAwIDExLjAwMCBaIE02LjUwMCAxMS4wMDAgQzQuMDEwIDExLjAwMCAyLjAwMCA4Ljk5MCAyLjAwMCA2LjUwMCBDMi4wMDAgNC4wMTAgNC4wMTAgMi4wMDAgNi41MDAgMi4wMDAgQzguOTkwIDIuMDAwIDExLjAwMCA0LjAxMCAxMS4wMDAgNi41MDAgQzExLjAwMCA4Ljk5MCA4Ljk5MCAxMS4wMDAgNi41MDAgMTEuMDAwIEw2LjUwMCAxMS4wMDAgWiIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSIjYjJiMmIyIi8+PC9nPjwvc3ZnPg==","dir":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48L2RlZnM+PGc+PGc+PHBhdGggZD0iTTIxLjcxMCAxMS4yOTAgTDEyLjcxMCAyLjI5MCBDMTIuMzIwIDEuOTAwIDExLjY5MCAxLjkwMCAxMS4zMDAgMi4yOTAgTDIuMzAwIDExLjI5MCBDMS45MTAgMTEuNjgwIDEuOTEwIDEyLjMxMCAyLjMwMCAxMi43MDAgTDExLjMwMCAyMS43MDAgQzExLjY5MCAyMi4wOTAgMTIuMzIwIDIyLjA5MCAxMi43MTAgMjEuNzAwIEwyMS43MTAgMTIuNzAwIEMyMi4xMDAgMTIuMzIwIDIyLjEwMCAxMS42OTAgMjEuNzEwIDExLjI5MCBMMjEuNzEwIDExLjI5MCBaIE0xNC4wMDAgMTQuNTAwIEwxNC4wMDAgMTIuMDAwIEwxMC4wMDAgMTIuMDAwIEwxMC4wMDAgMTUuMDAwIEw4LjAwMCAxNS4wMDAgTDguMDAwIDExLjAwMCBDOC4wMDAgMTAuNDUwIDguNDUwIDEwLjAwMCA5LjAwMCAxMC4wMDAgTDE0LjAwMCAxMC4wMDAgTDE0LjAwMCA3LjUwMCBMMTcuNTAwIDExLjAwMCBMMTQuMDAwIDE0LjUwMCBMMTQuMDAwIDE0LjUwMCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM2NzlkZjYiLz48cGF0aCBkPSJNMC4wMDAgMC4wMDAgTDI0LjAwMCAwLjAwMCBMMjQuMDAwIDI0LjAwMCBMMC4wMDAgMjQuMDAwIEwwLjAwMCAwLjAwMCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg==","place":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNyIgdmlld0JveD0iMCAwIDEyIDE3Ij48ZGVmcz48L2RlZnM+PGc+PHBhdGggZD0iTTYuMDAwIDAuMDAwIEMyLjY4MyAwLjAwMCAwLjAwMCAyLjY2MCAwLjAwMCA1Ljk1MCBDMC4wMDAgMTAuNDEzIDYuMDAwIDE3LjAwMCA2LjAwMCAxNy4wMDAgQzYuMDAwIDE3LjAwMCAxMi4wMDAgMTAuNDEzIDEyLjAwMCA1Ljk1MCBDMTIuMDAwIDIuNjYwIDkuMzE3IDAuMDAwIDYuMDAwIDAuMDAwIEw2LjAwMCAwLjAwMCBaIE02LjAwMCA4LjAwMCBDNC44OTYgOC4wMDAgNC4wMDAgNy4xMDQgNC4wMDAgNi4wMDAgQzQuMDAwIDQuODk2IDQuODk2IDQuMDAwIDYuMDAwIDQuMDAwIEM3LjEwNCA0LjAwMCA4LjAwMCA0Ljg5NiA4LjAwMCA2LjAwMCBDOC4wMDAgNy4xMDQgNy4xMDQgOC4wMDAgNi4wMDAgOC4wMDAgTDYuMDAwIDguMDAwIFoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iI2IyYjJiMiIvPjwvZz48L3N2Zz4=","zoom":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MSIgaGVpZ2h0PSI2OSIgdmlld0JveD0iMCAwIDQxIDY5Ij48ZGVmcz48ZmlsdGVyIGlkPSJmMSIgeD0iLTUwJSIgeT0iLTUwJSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSI+PGZlRHJvcFNoYWRvdyBkeD0iMCIgZHk9IjEiIHN0ZERldmlhdGlvbj0iMiIgZmxvb2QtY29sb3I9IiMwMDAwMDAiIGZsb29kLW9wYWNpdHk9IjAuMyIvPjwvZmlsdGVyPjwvZGVmcz48Zz48cGF0aCBkPSJNOCA2IGgyNSBhMiAyIDAgMCAxIDIgMiB2NTMgYTIgMiAwIDAgMSAtMiAyIGgtMjUgYTIgMiAwIDAgMSAtMiAtMiB2LTUzIGEyIDIgMCAwIDEgMiAtMiB6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNmZmZmZmYiIGZpbHRlcj0idXJsKCNmMSkiLz48cGF0aCBkPSJNMTUgNDdoMTF2M2gtMTF6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM2NjY2NjYiLz48Zz48cGF0aCBkPSJNMTUgMTloMTF2M2gtMTF6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM2NjY2NjYiLz48cGF0aCBkPSJNMTkgMTVoM3YxMWgtM3oiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iIzY2NjY2NiIvPjwvZz48cGF0aCBkPSJNMTEuNTAwIDM0LjUwMCBMMjkuNTAwIDM0LjUwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSJub25lIiBzdHJva2U9IiNlNmU2ZTYiIHN0cm9rZS13aWR0aD0iMSIvPjwvZz48L3N2Zz4=","loc":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MSIgaGVpZ2h0PSI0MSIgdmlld0JveD0iMCAwIDQxIDQxIj48ZGVmcz48ZmlsdGVyIGlkPSJmMiIgeD0iLTUwJSIgeT0iLTUwJSIgd2lkdGg9IjIwMCUiIGhlaWdodD0iMjAwJSI+PGZlRHJvcFNoYWRvdyBkeD0iMCIgZHk9IjEiIHN0ZERldmlhdGlvbj0iMiIgZmxvb2QtY29sb3I9IiMwMDAwMDAiIGZsb29kLW9wYWNpdHk9IjAuMyIvPjwvZmlsdGVyPjwvZGVmcz48Zz48cGF0aCBkPSJNOCA2IGgyNSBhMiAyIDAgMCAxIDIgMiB2MjUgYTIgMiAwIDAgMSAtMiAyIGgtMjUgYTIgMiAwIDAgMSAtMiAtMiB2LTI1IGEyIDIgMCAwIDEgMiAtMiB6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNmZmZmZmYiIGZpbHRlcj0idXJsKCNmMikiLz48Zz48Zz48cGF0aCBkPSJNMjEuMDAwIDI3LjAwMCBDMjQuMzE0IDI3LjAwMCAyNy4wMDAgMjQuMzE0IDI3LjAwMCAyMS4wMDAgQzI3LjAwMCAxNy42ODYgMjQuMzE0IDE1LjAwMCAyMS4wMDAgMTUuMDAwIEMxNy42ODYgMTUuMDAwIDE1LjAwMCAxNy42ODYgMTUuMDAwIDIxLjAwMCBDMTUuMDAwIDI0LjMxNCAxNy42ODYgMjcuMDAwIDIxLjAwMCAyNy4wMDAgWiIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSJub25lIiBzdHJva2U9IiNkMWQxZDEiIHN0cm9rZS13aWR0aD0iMSIvPjxwYXRoIGQ9Ik0yMS4wMDAgMjUuMDAwIEMyMy4yMDkgMjUuMDAwIDI1LjAwMCAyMy4yMDkgMjUuMDAwIDIxLjAwMCBDMjUuMDAwIDE4Ljc5MSAyMy4yMDkgMTcuMDAwIDIxLjAwMCAxNy4wMDAgQzE4Ljc5MSAxNy4wMDAgMTcuMDAwIDE4Ljc5MSAxNy4wMDAgMjEuMDAwIEMxNy4wMDAgMjMuMjA5IDE4Ljc5MSAyNS4wMDAgMjEuMDAwIDI1LjAwMCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM2NjY2NjYiIHN0cm9rZT0iI2ZmZmZmZiIgc3Ryb2tlLXdpZHRoPSIxIi8+PHBhdGggZD0iTTIwIDEzaDJ2MmgtMnoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iI2QxZDFkMSIvPjxwYXRoIGQ9Ik0yMCAyN2gydjJoLTJ6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNkMWQxZDEiLz48cGF0aCBkPSJNMjcgMjBoMnYyaC0yeiIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSIjZDFkMWQxIi8+PHBhdGggZD0iTTEzIDIwaDJ2MmgtMnoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iI2QxZDFkMSIvPjwvZz48L2c+PC9nPjwvc3ZnPg==","peg":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDEwIDE4Ij48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9ImczIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUuMDAxNzEiIHkxPSItNS42ODI5NSIgeDI9IjUuMDAxNzEiIHkyPSIxOCI+PHN0b3Agb2Zmc2V0PSIwLjI0NjQ1MiIgc3RvcC1jb2xvcj0iI2ZmYmYwMCIgc3RvcC1vcGFjaXR5PSIxIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZmZkNTAwIiBzdG9wLW9wYWNpdHk9IjEiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iZzQiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iNSIgeTE9IjYiIHgyPSI1IiB5Mj0iOSI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjY2Y4NDFiIiBzdG9wLW9wYWNpdHk9IjEiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNlMzcxMDAiIHN0b3Atb3BhY2l0eT0iMSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxnPjxwYXRoIGQ9Ik00LjM0MCAxOC4wMDAgTDQuMzQwIDEzLjA0NyBMNS43NTggMTMuMDQ3IEw1Ljc1OCAxOC4wMDAgTDcuMDAwIDE4LjAwMCBMNy4xMTMgOS41OTMgQzcuMTEzIDkuNTkzIDkuMjExIDEzLjQ0MyA5LjIxMSAxMy40NDMgQzkuMjExIDEzLjQ0MyAxMC4wMzcgMTMuMDQyIDkuOTk3IDEyLjkxNyBDOC45MzUgOS41OTMgNy43ODMgNi4wNDIgNy43ODMgNi4wNDIgTDUuMDAyIDYuMDUwIEwyLjIyMSA2LjA0MiBDMi4yMjEgNi4wNDIgMS4wNjggOS41OTMgMC4wMDcgMTIuOTE3IEMtMC4wMzMgMTMuMDQyIDAuNzkzIDEzLjQ0MyAwLjc5MyAxMy40NDMgQzAuNzkzIDEzLjQ0MyAyLjg5MCA5LjU5MyAyLjg5MCA5LjU5MyBMMy4wMDMgMTguMDAwIEw0LjM0MCAxOC4wMDAgWiBNNS4wMDAgNi4wMDAgQzYuNjU3IDYuMDAwIDguMDAwIDQuNjU3IDguMDAwIDMuMDAwIEM4LjAwMCAxLjM0MyA2LjY1NyAwLjAwMCA1LjAwMCAwLjAwMCBDMy4zNDMgMC4wMDAgMi4wMDAgMS4zNDMgMi4wMDAgMy4wMDAgQzIuMDAwIDQuNjU3IDMuMzQzIDYuMDAwIDUuMDAwIDYuMDAwIFoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0idXJsKCNnMykiIHN0cm9rZT0iIzRkMzkwMCIgc3Ryb2tlLXdpZHRoPSIxIiBzdHJva2Utb3BhY2l0eT0iMC41NSIvPjxwYXRoIGQ9Ik0zLjAzMCA2LjAxNCBDMy4wMzAgNi4wMTQgNC4wMzEgOC45NTEgNS4wMTkgOC45NDUgQzYuMDA4IDguOTM5IDYuOTc3IDUuOTkwIDYuOTc3IDUuOTkwIEwzLjAzMCA2LjAxNCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9InVybCgjZzQpIi8+PC9nPjwvc3ZnPg==","apps":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE2IDE2Ij48ZGVmcz48L2RlZnM+PGc+PHBhdGggZD0iTTAgMGg0djRoLTR6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM0ODU4NzMiLz48cGF0aCBkPSJNMCA2aDR2NGgtNHoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iIzQ4NTg3MyIvPjxwYXRoIGQ9Ik0wIDEyaDR2NGgtNHoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iIzQ4NTg3MyIvPjxwYXRoIGQ9Ik02IDBoNHY0aC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSIjNDg1ODczIi8+PHBhdGggZD0iTTYgNmg0djRoLTR6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM0ODU4NzMiLz48cGF0aCBkPSJNNiAxMmg0djRoLTR6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM0ODU4NzMiLz48cGF0aCBkPSJNMTIgMGg0djRoLTR6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM0ODU4NzMiLz48cGF0aCBkPSJNMTIgNmg0djRoLTR6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM0ODU4NzMiLz48cGF0aCBkPSJNMTIgMTJoNHY0aC00eiIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSIjNDg1ODczIi8+PC9nPjwvc3ZnPg==","pin":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSI0MCIgdmlld0JveD0iMCAwIDIyIDQwIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9Imc1IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjExIiB5MT0iMCIgeDI9IjExIiB5Mj0iNDAiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ZiNzQ2NyIgc3RvcC1vcGFjaXR5PSIxIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZjM0NDNiIiBzdG9wLW9wYWNpdHk9IjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48Zz48cGF0aCBkPSJNMTAuMjUzIDQwLjAwMCBMMTAuMjUzIDM4LjA0OSBDOS45MDggMzUuNjc0IDkuMjY0IDMxLjkyOCA4LjMxNyAyOS4xNTggQzcuMTEzIDI1LjY0MCAzLjQzMCAxOS42MDMgMi4wMzQgMTcuMzc0IEMwLjc1MyAxNS41NzYgMC4wMDAgMTMuMzc2IDAuMDAwIDExLjAwMCBDMC4wMDAgNC45MjUgNC45MjUgMC4wMDAgMTEuMDAwIDAuMDAwIEMxNy4wNzUgMC4wMDAgMjIuMDAwIDQuOTI1IDIyLjAwMCAxMS4wMDAgQzIyLjAwMCAxMy4zNzggMjEuMjQ1IDE1LjU4MCAxOS45NjIgMTcuMzgwIEwxOS45NjIgMTcuMzgwIEMxOC41MjIgMTkuNjU5IDE0LjgyOSAyNS42NjUgMTMuNjM0IDI5LjE1OCBDMTIuNjg2IDMxLjkyOCAxMi4wNDIgMzUuNjc0IDExLjY5NyAzOC4wNDkgTDExLjY5NyA0MC4wMDAgTDEwLjI1MyA0MC4wMDAgTDEwLjI1MyA0MC4wMDAgWiIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSJ1cmwoI2c1KSIgc3Ryb2tlPSIjYjczODMwIiBzdHJva2Utd2lkdGg9IjEiLz48cGF0aCBkPSJNMTEuMDAwIDE2LjAwMCBDMTMuMjA5IDE2LjAwMCAxNS4wMDAgMTQuMjA5IDE1LjAwMCAxMi4wMDAgQzE1LjAwMCA5Ljc5MSAxMy4yMDkgOC4wMDAgMTEuMDAwIDguMDAwIEM4Ljc5MSA4LjAwMCA3LjAwMCA5Ljc5MSA3LjAwMCAxMi4wMDAgQzcuMDAwIDE0LjIwOSA4Ljc5MSAxNi4wMDAgMTEuMDAwIDE2LjAwMCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM1YzE0MTAiLz48L2c+PC9zdmc+","pointer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMSIgaGVpZ2h0PSIyMSIgdmlld0JveD0iMCAwIDIxIDIxIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9Imc2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjYuMDYwNDciIHkxPSI0Ljk4ODgxIiB4Mj0iMTQuNjQxNSIgeTI9IjE2LjU4MzMiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2ExYTFhMSIgc3RvcC1vcGFjaXR5PSIxIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNjk2OTY5IiBzdG9wLW9wYWNpdHk9IjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48Zz48cGF0aCBkPSJNMTAuNTAwIDIxLjAwMCBDMTYuMjk5IDIxLjAwMCAyMS4wMDAgMTYuMjk5IDIxLjAwMCAxMC41MDAgQzIxLjAwMCA0LjcwMSAxNi4yOTkgMC4wMDAgMTAuNTAwIDAuMDAwIEM0LjcwMSAwLjAwMCAwLjAwMCA0LjcwMSAwLjAwMCAxMC41MDAgQzAuMDAwIDE2LjI5OSA0LjcwMSAyMS4wMDAgMTAuNTAwIDIxLjAwMCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiNmZmZmZmYiIHN0cm9rZT0iIzNmNDU1MSIgc3Ryb2tlLXdpZHRoPSIxIiBzdHJva2Utb3BhY2l0eT0iMC4yIi8+PHBhdGggZD0iTTEwLjUwMCAxOC4wMDAgQzE0LjY0MiAxOC4wMDAgMTguMDAwIDE0LjY0MiAxOC4wMDAgMTAuNTAwIEMxOC4wMDAgNi4zNTggMTQuNjQyIDMuMDAwIDEwLjUwMCAzLjAwMCBDNi4zNTggMy4wMDAgMy4wMDAgNi4zNTggMy4wMDAgMTAuNTAwIEMzLjAwMCAxNC42NDIgNi4zNTggMTguMDAwIDEwLjUwMCAxOC4wMDAgWiIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSJ1cmwoI2c2KSIvPjxnPjxnPjxwYXRoIGQ9Ik00LjAwMCA0LjAwMCBMMTguMDAwIDQuMDAwIEwxOC4wMDAgMTguMDAwIEw0LjAwMCAxOC4wMDAgTDQuMDAwIDQuMDAwIFoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0ibm9uZSIvPjwvZz48L2c+PGc+PGc+PHBhdGggZD0iTTEwLjUwMCA1LjAwMCBDOC41NjUgNS4wMDAgNy4wMDAgNi43MjEgNy4wMDAgOC44NTAgQzcuMDAwIDExLjczOCAxMC41MDAgMTYuMDAwIDEwLjUwMCAxNi4wMDAgQzEwLjUwMCAxNi4wMDAgMTQuMDAwIDExLjczOCAxNC4wMDAgOC44NTAgQzE0LjAwMCA2LjcyMSAxMi40MzUgNS4wMDAgMTAuNTAwIDUuMDAwIEwxMC41MDAgNS4wMDAgWiBNMTAuNTAwIDEwLjAwMCBDOS42NzIgMTAuMDAwIDkuMDAwIDkuMzI4IDkuMDAwIDguNTAwIEM5LjAwMCA3LjY3MiA5LjY3MiA3LjAwMCAxMC41MDAgNy4wMDAgQzExLjMyOCA3LjAwMCAxMi4wMDAgNy42NzIgMTIuMDAwIDguNTAwIEMxMi4wMDAgOS4zMjggMTEuMzI4IDEwLjAwMCAxMC41MDAgMTAuMDAwIEwxMC41MDAgMTAuMDAwIFoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iI2ZmZmZmZiIvPjwvZz48L2c+PC9nPjwvc3ZnPg==","dir34":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNCIgaGVpZ2h0PSIzNCIgdmlld0JveD0iMCAwIDM0IDM0Ij48ZGVmcz48L2RlZnM+PGc+PGc+PHBhdGggZD0iTTMwLjc1NiAxNS45OTQgTDE4LjAwNiAzLjI0NCBDMTcuNDUzIDIuNjkyIDE2LjU2MSAyLjY5MiAxNi4wMDggMy4yNDQgTDMuMjU4IDE1Ljk5NCBDMi43MDYgMTYuNTQ3IDIuNzA2IDE3LjQzOSAzLjI1OCAxNy45OTIgTDE2LjAwOCAzMC43NDIgQzE2LjU2MSAzMS4yOTQgMTcuNDUzIDMxLjI5NCAxOC4wMDYgMzAuNzQyIEwzMC43NTYgMTcuOTkyIEMzMS4zMDggMTcuNDUzIDMxLjMwOCAxNi41NjEgMzAuNzU2IDE1Ljk5NCBMMzAuNzU2IDE1Ljk5NCBaIE0xOS44MzMgMjAuNTQyIEwxOS44MzMgMTcuMDAwIEwxNC4xNjcgMTcuMDAwIEwxNC4xNjcgMjEuMjUwIEwxMS4zMzMgMjEuMjUwIEwxMS4zMzMgMTUuNTgzIEMxMS4zMzMgMTQuODA0IDExLjk3MSAxNC4xNjcgMTIuNzUwIDE0LjE2NyBMMTkuODMzIDE0LjE2NyBMMTkuODMzIDEwLjYyNSBMMjQuNzkyIDE1LjU4MyBMMTkuODMzIDIwLjU0MiBMMTkuODMzIDIwLjU0MiBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM2NzlkZjYiLz48cGF0aCBkPSJNMC4wMDAgMC4wMDAgTDM0LjAwMCAwLjAwMCBMMzQuMDAwIDM0LjAwMCBMMC4wMDAgMzQuMDAwIEwwLjAwMCAwLjAwMCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9Im5vbmUiLz48L2c+PC9nPjwvc3ZnPg==","close":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMCIgaGVpZ2h0PSIxMCIgdmlld0JveD0iMCAwIDEwIDEwIj48ZGVmcz48L2RlZnM+PGc+PHBhdGggZD0iTTAuMDk3IDAuMTcyIEw5LjA2OSA5LjE0NCIgZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSJub25lIiBzdHJva2U9IiNjY2NjY2MiIHN0cm9rZS13aWR0aD0iMiIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDQuNTgyNzkgNC42NTc5KSBzY2FsZSgtMSAxKSB0cmFuc2xhdGUoLTQuNTgyNzkgLTQuNjU3OSkiPjxwYXRoIGQ9Ik0wLjA5NyAwLjE3MiBMOS4wNjkgOS4xNDQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjY2NjY2NjIiBzdHJva2Utd2lkdGg9IjIiLz48L2c+PC9nPjwvc3ZnPg==","imagery":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTYiIGhlaWdodD0iNDEiIHZpZXdCb3g9IjAgMCAxNTYgNDEiPjxkZWZzPjxmaWx0ZXIgaWQ9ImY3IiB4PSItNTAlIiB5PSItNTAlIiB3aWR0aD0iMjAwJSIgaGVpZ2h0PSIyMDAlIj48ZmVEcm9wU2hhZG93IGR4PSIwIiBkeT0iMSIgc3RkRGV2aWF0aW9uPSIyIiBmbG9vZC1jb2xvcj0iIzAwMDAwMCIgZmxvb2Qtb3BhY2l0eT0iMC4zIi8+PC9maWx0ZXI+PGxpbmVhckdyYWRpZW50IGlkPSJnOCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIyMi4wMDE3IiB5MT0iNi4zMTcwNSIgeDI9IjIyLjAwMTciIHkyPSIzMCI+PHN0b3Agb2Zmc2V0PSIwLjI0NjQ1MiIgc3RvcC1jb2xvcj0iI2ZmYmYwMCIgc3RvcC1vcGFjaXR5PSIxIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZmZkNTAwIiBzdG9wLW9wYWNpdHk9IjEiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iZzkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiB4MT0iMjIiIHkxPSIxOCIgeDI9IjIyIiB5Mj0iMjEiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2NmODQxYiIgc3RvcC1vcGFjaXR5PSIxIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjZTM3MTAwIiBzdG9wLW9wYWNpdHk9IjEiLz48L2xpbmVhckdyYWRpZW50PjwvZGVmcz48Zz48cGF0aCBkPSJNOCA2IGgxNDAgYTIgMiAwIDAgMSAyIDIgdjI1IGEyIDIgMCAwIDEgLTIgMiBoLTE0MCBhMiAyIDAgMCAxIC0yIC0yIHYtMjUgYTIgMiAwIDAgMSAyIC0yIHoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0iI2ZmZmZmZiIgZmlsdGVyPSJ1cmwoI2Y3KSIvPjxnPjxwYXRoIGQ9Ik0xMzAuNzM2IDE5LjkzNiBMMTM0LjY0MSAxNi4wMjIgTDEzOC42NTggMTkuOTA5IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzY2NjY2NiIgc3Ryb2tlLXdpZHRoPSIyIi8+PHBhdGggZD0iTTEzMC43MzYgMjUuOTM2IEwxMzQuNjQxIDIyLjAyMiBMMTM4LjY1OCAyNS45MDkiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjNjY2NjY2IiBzdHJva2Utd2lkdGg9IjIiLz48L2c+PGc+PGltYWdlIHg9IjQ1IiB5PSIxMyIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE1IiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIiBocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUNRQUFBQWVDQVlBQUFCRTRieFRBQUFBQVhOU1IwSUFyczRjNlFBQUJ2eEpSRUZVV0FsdGw5bVNGRVVVaGs5VlpYVlBMekNBSWpkZStmQStpdy9nbFZlR1lhaEJBRHJBT04yMStuLy95UnFHQ0pPcFhNNzZueVdyaStiSFg2WTFOSmhhTmhyc0c2OXJMTnF4YnpSdGRCMDFkQkt4eWNVOERrZ3YwRkxvY2VXNDJjRE9VMnZidVpGQUFZU1ZOd3NyN0NaYUEyalNrV2JrVml4cUxIcGF5WEJhTmJIQ21pc3RkVVhVc0gxTWFqTnIyV1FiS2JKSDN3SElBT2V5NjFJSXo0YUNaZjBaZ0FRc3BjbFlFR0JVUGdZZ2JlUlpHL1prelVETjBDU0VwcU9nOFg5N1dEeUZxZE5raDVwYVpjajdLZ0RmZHBHcHRHMURKbURDNXlGUzd6VmhBMkNVM0ZrUUp3dUtERkxiRUY5SFU2UlRPR0FJSjQzTDVXMm1HcG9lQm91ZDFJTlZiQ1dOd1RkQXJlWnRlbHJSQTB4VjFYbHJCWk1NaURaQXp4bXlYVTJzMURtenBHeHBUNVRZd3BuM09vSWJKeGpCelpJUXFrc0VObm9LYjVscFVmSlFUMkt2bmhJeEYwaUFRSVJQQm1zK0tUckxNODBMYmRZTUlGcHYxYWFsRHRBeWZLMHFoR2sxVTJJVDBCTzNFcmVCWEcwblpWcmJTZDhDbExYbENFSU0xTW9aT0hDSWNKRXpuT3JQTXA2OXovTXFwUXlERmtod1gyV2hxbGxHUWJEeUFOcVZxUHpTaTVsMmNWcXZkNGFXS3RVTE1tMmpXQ3JheExYcEVvNEVONERZMUg0N3NtRy9tYlhKYXJjdXdMR1FtdnBMWkc3cWRZblczVm12ZW8zbVVRTy9zcjQxSVJuRG1jUWVCMXYzbHhpbVEyQ3ZoVE9yWFVDMmNxNjBRcUVoM1JlNmFvdit0U2hxM3lnYk5tWkRDYzZ5c21Zak5tcy9NdnNsZXBPbHN6bkVPVFRPdkY2K29sZmVKb05EWjhoR1JBVVlUQXJoWXFodkVxYm9OS3dpQUF4U2VwOFN0Tjh4N0t4cnkxOUFFaEJ5WWpxNERReWtiVlFWSDBtR0xsbjJqVytMeVdrY0kzWlVvMDJBSXRXMCtTd2hRREUyUG14anQ1eXgyQlNsZmVxOEtubkpFTkpXNGMxb1FVMG81V0FEbFpVcnpzVVVSVTdVK3BVdVBycWlQVGFyREZqckVVdzE2QnVLcFF3V21hM0hMS0dKL2tIQ0dYSWR6TUZoT2c0MU53UGNDSnR1SFF1S2t5dDhlSnhkTnUwb1RiNlhkSUJaOWRJNkIzNjhnYWVkemNnS1B4ZVNMWTdTV3B5VkRiTGdSc2wrZ2RVQXpwbW9ScXE4UFNGckYzSkNxblFzcGhDSWxIWE8wTENqdmVXMXdZK1lITGtzL3ZtU1hoRWlkTVJJb2JTdlBZMWdUaHBGYmNFQlZDeWpwR0dmVW5MRDJ2TWE4eXk1Q2c2QnBXWjdVOHJTSXlLZWJXRXNtNkZNUytMM0lqdTRwQ3V5YXlTNGdiRDN4MWdkbVdYRnovSndIOW1qcjcxQWJhVjJiT2hya0JkY1V3aytWeGpnZCthMGxvZjdUMUg2dmVEeVlaUmhVYktNSWpVODQ3Mk83Slo2RU4yL1JYS1RZMXQxY2pCZmducktkdytKbFI2cXFwYnk2ODgveGZuYk4zRjYvanAyaDJmUmRMM0lnRk9FQXBhbFJNRVYxemxUMjVFRmZLbFdmSFp1WDVDY2NjSkRMdHc0dGZ5R2FnUmswaHNKWnN2Z2dTeVZ6My85Rm5kdmY0L0QrVFlPdDk5Rk9iK0svdmd5eXY0Y3E3cDBtbFVJZ2VOQndkbVJaZDY2VHJuV25lUncxZ21Zd1ZnV0Z3SXFCcjVGRW1qT1NPWWdTOENXV1FNazJITFk5VUVmVGZmL3hJZVBmMGV6TzBaL2VobkhWMitpbkY1RXV6dEhXMVJTQ1UvV2pPamw1U0tndmxhaXpVMzJWa1lOWkZ6Ymw1Y2krUTVra3UwcitFbnA3UlJWZ3QwQ1hwUnRDZXk3TG1ZSnlLVUV4aGp2L295SHk0Zm9iczVSanEvMDNNYjV4WGR4UGh4amtPOUpYM0dQRWNzUjJYTnV0SUtaTEZUL3lpSjJZVk4rWlpYYm8zWFV6WnNXZmkrbHJ5YnZTaGVEREFzODc0OVd0MktNbllEeG8ycGo0eERMOUNHRys3dVkxUFQ5NVgyMHR5OWphay94RVB0b3lGclRxWFRLQm1IcUQ4L3VDTzF0VTg3NXNPTlBidHhuWUVNUU9nQWRURjBuY2NxODZqOHZJblNaTzBkVDFOZzA4ekNORWxGRTQwTTh2UHNqaG8vdlkycjZHSnNTdTlNM3NmUTNzWGJIbU1wT0R0VG0yR0N3Z0VCbk56NUg2RXh1Y0dWU1BISmpZV2lTNTBWYTl1b2gxVTNuRXRNMEtUdmNzTTZHYUdKdURSOW1UcTJ5dU8vbWFLY2xybS92RkxJeTJ1MVUwdWZxN0dmeGIreWkyVCtMUmZaOE8rV090M0R0cU1TWjBMd1gyN2hKVlVycGx2VjZ6MU1pU3Jlb3BoMlJ5Y0k4S21aZG02SXlya3A5b3dZc0xUOEtOR2FKNHk3aU9neng2ZE83Nks4ZjQzQnoxSGVVYm1XdjIzbDhFV001eGFBZkVWNlcvTWNCcHpTOUcxNTdjTlY4MnFZSjJwVkZ2Zkw1Y2xXd0pmYnFsYmJ2MUxTVWtZN1g3ZWgwRy9yZVYxNkJpMDYyQkhLZDRuUzRrZDAxeG1HTWFiaVBnMG85WFI2aVh6OHFTN3U0bG1OY3UzUDh1d3BZcS9lYk1tMFFLcEVyQjFCWjhPMFVZVm5VMUpNNiszUlVId2pFUDUvdVJGd1U3VDRPKzBQMC9TNHV3eVhLVFJNNy9lcVJYeUxNSlBaYW03alIrd3JkUWFEdzBsSkdaZUE2WDZJZkwzR2E3K0pXZlRjME4zRnA5ZWhDektFQTB4SjRCREo3N2Z0dlR3SWtWT3YxcWd6b1JxaEhyc3FZcWhUSDQ4R2x2Tm52WWxSelQrSUJnQjdybEtxUmJ0Vm9lVU5xZFBxUThXZXY2UFFNeFJrRWRKWDl0cDNWWGRjNERuZXF3RDdHZGgvM3E0TFZNeXpxWFprWXh6RitlUDBtL2dPcG9DcHU4M2Z2R3dBQUFBQkpSVTVFcmtKZ2dnPT0iLz48aW1hZ2UgeD0iNjYiIHk9IjEzIiB3aWR0aD0iMTgiIGhlaWdodD0iMTUiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiIGhyZWY9ImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQ01BQUFBZUNBWUFBQUNtUGFjcUFBQUFBWE5TUjBJQXJzNGM2UUFBQ0psSlJFRlVXQWs5bDl1VzQwZ1JSVlBLbE9STFZWK0FnY1hpYS9rTEh2Z25udmdFNElFMTAxTTMyNUpTS2ZZT0ZlTnF0eTBwTStORXhJa1Q0ZTd2Zi92cjN1Y2hwVktTcjI1UHFkVTFiWHZqczNKblQzVzlwWEU0cHpMbU5KYk1zeVYxUFk5eVNsdXI2WHptV2M3cGZyK3pmRXZYeTNNYU9ITlpIeW5ua3VxMnBXVmJ1WGZtOE1iNmE2cDE0ZjdPdmlrOU9MLzBPWlh2Zi9oekdPUS9rR0FCTUd1ZCtlQkxhdnpqMi9ZRklFUEtuVXY2dE84MWRYNEhqQnM2THJoTTNhbmcwNUI2QUdUdVhjdUo3Mk9jNmRrTjQ3NzZ2Z1BFaVoyZXRhZHB1Z0I2U3VWMGVlSkdZMEhtd0RnZCsydHMwcHAzTWNPYktMSE9rL2N3M3ZIdHVPWUxTMW9hSnE4eDVtVXEyRDlBOWdEUmFJOGpzZDgxY2RZUjNweDlUbkxHOFU5eHFFY2ZMei9iYjRhNjNSQjBZVURRN3RyTnBldDcxdUZ0d08zL3YvL3pHTy82ajlzNm1XTVBSc1BPNTZjSWVHcGsvU3pEK0QwTzdnS0FtekhJUnY4T2dDeDBrd2U3aWR6dlJDSEFlQTNkZk40Wk9WN0hIdGE3SlloMWZOZWJ6empGS3RjZUdSRE13VmQ0QTZsY0J2RUVjSVQ0SUs0QWRYZ25iWEpnbDdocDQ5NFcwQU80cDdMR05BR05aNmF6cGczZVpVZ3N6SzdqczMxR04wRHJNTkVKMG1uYmM2MmhmdUFjQ0lrQlAzc2U1SDNtd0h2cXRqdVpXQWpHTFoybWljcmhHbUNtdmpYQXR6V2lKYWs1TWxEdHpiMk42cG01dy8yK3NINWcvUTY0akVPVmlHQ0hQWDEvWVkycE45SnladjJSdHZ1L1UxOWZBRU5wdGtkRVltKzNBTGR4YmJrK2VLU25GRHp1QnhyQUFReXZCUk9HaU5yTzJuaHB3MVR4VEFZYWhLQUkvTmwxeEQvVHlEdGtCTEFsL2ZvUHdQeUxtbjlOUThFVCtMSnVoQTIwSFJYV05rTk9hdENoa1h0ckZTenBNeFlZNm5vaXlzRlc0MFlVQlhYc0U1Z2VRMTlLdlFQSmIwQzV2eHN0Z01ncnRhcG5YN20vL3BPTEQ3YTREMzFBRitibEJhRmIwakNNbWt3TDR0ZTNJZDBlYitnRGtkQlRJdER6Zk44ZXBIRU5mYkVLWVRqaFBvVUQ2cFhwbUtacmFxczhCRGlHZXNKa1BYbDJBQVNRakN1VjFHeUdEUUxXRmJHckFFTWZrTnBVdVpmeElDTlFldmo0ZUUyWDRSQTJTM3J6RDYvV0NyOVE1c3hiaGYyNC9lQU1TQ3ZnL29Sek9GSGdYSENsUk9RTFlCcHJyYWg0cGhyZlAwTmI4Ujd0T2NnRi9CNGxEV1dGZ0tRenZNbW5NVzNZR3dicUdjQXJjdCt4YmlSYXRwUk8zWkd3MitIeE1KNHhTZVhSWGhxcDJTeU1EVkRRWUJ3dVJFOUhhQmtENS9SaktyLzgrRThhVDljSStiWVFHU3lQNkg0dVd6clJReHA5eGNyZDZnMVBxQjVLZE9HQVJocDNQTE9FdDJVaGZWMjYwSk4wSU1Ndm8yeWtMT2s4Q1B5RDlFMmMxOUxiQnpRWUsrdS8wYi91c1VaU2x5dEE4b21XMEdGMDNRSHdKVXFaWFNTRzhvdHdVZnA0bmd0OGVyeW55dHR3RmJ5WjRBM2VVQ3BycWdzTmRiend2ZUU1dmNaMndMN1NYZEpLYnh2RzV5QjE2Y1lBM0VIc3ZaMEI5VHNpQk5nLy92NHZ3V1E5cWxjWVQ2cTIrc1NoRXh2cDJJclhPQVlSRytyN2RQcVc1dm1WMEcvcG9oT2tHWTd5SnAxOGx3ZDllU0tWTkVraXRCRkJnV1drV2hKYmFjOWZWWDAyNGU3VCtTdDdNN29FRjhlSjBzS0k4d0FLbUNvSGpvT0ZpM0N0NzRCaVBJQVg1a3FTN29BNGowK3BQM0U4NGQ5M2VFVGFySXh4SWsyY3BLNjRRV2QwVWgzaEN1OXY3RGtUeld2d1JrcW9WUXYwTU9xbEtXNkVUYUpaV2N0eVQ2ZlRGNjdWbVVielFqZnNWWnkvd3g5WlhnSnN6eHp5U29rREVnUVp3RkZmcEZmbklxTE9TR3pzUTZtVmV5S0ZqYnJzd1RzakU4VkJsQnJ6VGVuY3dFdkNXV1pkeG5DMzRnWE1wN1NYK2taZnNtd2hIMzNGVkJsaW5FVW9JUytHcks2ZENvbk9acGZuSlhrM1N0NlhsV1JFTkQ2UTA4cDlsYWJqWEJWOW1kK2dDaHdMeFlVODlndFRNMDBPUkJnU0RCdUdPQlRSUzBhUC9xSUdBZEtVT2tTeExUaTNBMUtqQ2xySWZYd1hDb1VCajR5MFNod05ONFlzU2g1SDdGdGhzd2NNckVvbkZWUFBDS2tlTllUc1RKWHB2dU9rZzFEREcwblp3WEFqT0pLV0ZmNnNmQWVXYW9JRDNDY0NqWWhwZklDNGNtZUxrVVNCaEVORWhybmxFTmhZUlR3QmFZUnBHaUpVYVJWNTkxSWRPQy9wTnZxU2xhQWlWN2hndWV1MVk0UnpzVHNjTDFiYVFVK1pEd0NNQ01PckhpS1pWa2RNeGMxR0VhQ0ppZzFGVUtwM1UvUWc3MDU2eTZOS1FoYmdrU1ExUWtkN1AzSTd6L1lRU1d6RWFKS0dIQUJIS3ZSZndtcDBpeW94dlRaYXdWaUZSZy9MbEMyS1M1bnI4V3piWWFjQ1dObWJUYWtLdkJJZTA3TFpQVGxrWFI3cCtma25TTXdaQ05hRDlPeHNHcEJ2cWJtejlnREVjVllLYVYySlZpSFVEN3owRjRFdk5XZnNyK0dnTTVPL0JsWWJMaUJYUzVtSU94SFlJTy92UDBJUXl3SktyU2pySzlKc1Y0WmxwSWxVRUFHWmoxWDlJSlVqQjMwUTFqT0hVaTM4bWRxbUFSeUpIc1JhZ1NmbW5QdjhJSFgyb2tlb2M2Tm5uVkY0RzYvZ1puUXNLNDV5aTZwaHFvVGgvVGt0OTNlNHZISFFGYTE1QUd3T2I4RVEzdG1qbkQyZ09DRzE1MllPclBIYlp5RjFHejJJRDBEeWV3bXRRbFVBd0ZEMm9GS0ozTG9nQ1dScy9IVEUzeDBUcWJPemoveFVLUUFxSjFxODFzN2xPVVRKYXRsQmJiUWszY2g4WXhWa2hIRXNwQXJ2SW9jK3crdUZQbldKUTAwYkp0Q2M5ckJQZmFRVHp4VTZxMnB5REFHd0RwZ2VlOTZJa25memUvVENBU0V0cDB4L1FTTjY1aGNadmxBbE1qdmF2K1dtMkFIV2FDSElpTllVSVpZakk4UFl5TDVNaUN0ckV4cFY0YzFBQ3Qzdkd0WFlmZXJKQWhVS2tXbGRwYjlKRDFveGVUYVZGWXJFTUYvU09XVW11WjVoUmMrblRIZGQwUmp1N1Z5djl4a0RkTjdITVM2b25rYktjVlRTM0prQUsrWHRxNWhDK0RQQ2hWVWdnR0JWckt2UXdMU1lPdHRIL01TTm45SlNnRlBuanpmbGc0TXBNdzdjQURFemZhL01LQjBwWE80VnVZYk1HSTQxM0QvbUdIOUhPNERaS3M1NCtzSytWNGhmR1VPK005M2QwdTNqMTVoekpUbUxJL1VMRkxCenY3NzhsK3JpZC9mMUo5TDlEWHNVVDYxOWVubjVtYkF5WXhCV1ZWU2hNalUzWm1NN3F4N09iemZ5YlBkRy81MlZpeUYyUU1jQnhDMVBYeGtEcUJDaWRBRU0yMUJuM29pYzU2MFVpSXJsWU9hY1VtVTdhWnFwT1BsWjZQai9Bd21Fa2xzQkdkejhBQUFBQUVsRlRrU3VRbUNDIi8+PGltYWdlIHg9Ijg3IiB5PSIxMyIgd2lkdGg9IjE4IiBoZWlnaHQ9IjE1IiBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJub25lIiBocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUNNQUFBQWRDQVlBQUFBZ3FkV0VBQUFBQVhOU1IwSUFyczRjNlFBQUNvUkpSRUZVU0EwbGwxZHY0K2dWaGwrS1RTVFZyT0kyYlpPZDNVMkNRYTQydjNSL1Q2NENCTWxGa0tzZ000dHBPOFVlVzdaRVNoUjd5Zk14Z0EzMWo2ZTg1M2tQclgvKzlaZCtjM0dseFd5bEwzZTNlandlMWR1T0R0bFJXVm5xNW1hcktxdjE1R0tobjEvOXFPWFpRdi81NzMvVmpWd1ZkYXZrV0txcUtnWGpRTWRES2xtOW9ra294N1BrMkphT3g0UG04N25xdWxKUlpKcE9BZ1d1cnlBWTgvMkRidThmRkU2bTh0eVJSdGJZMC81MDBQdXZINVRtSjZYcFFVVlpxR2xhV1phanplWkNoK05lMlNsVGxoZTZ1ZDBxcXhwVlhhKzJkelNaekFna1V0TjJHazhtZk5ZU1FLYXVzbFNWRGVkbG5OWEx0ajNaanFkVFZpck5Ua3JTdlVRQTNpUlN3dlZQVlM0bkpuSnJaTXVTcllvZjhhZldYS3p1VmZMbys2NWUvdjUzbW9lZUxOdmxBcldpNllMUEd5VjV5dXRLWFNkMW5ORDNOczlORUwwcXQ5WnFOWlY3Ym9zNGxXY1pBWEYrMHlucmEvV09yOUdvbHpNZXFTczZraXZsSk1kY05zRzRucS9lNGdPQzZSdEx1KzFSRHcrUHVyNWM2ZG5sUm9FMzB0Z0x5Q3JYdys2Umk1c0xpd1JhQW1zMWlXYUtZMzV6ZDZmTDFVWi8rdUVuemlwMC8vQ05pcHRLTndUYlUrVllpL1ZjZHVDcW82Vys0K2d5dkNUZ1drNFl6cFhUbmhOdGlLS3A2cUpDQnltSDdsWGxqYnplMVl2cjUrUmREb0htZkg0OFZlcmxrc1JJV1laZW9vREFPdHBieXJWSCt1SGxkOXFjemZUcnUwOVV3NkVDUWlPZVpvdTVuTURXaVArS1JFemxpNktVMVhJYXlUcW1LcjRmeVBjNmhmNllmQzN0dDN0ZGI4NkdiTlBEVHUvZXZkR3JWMzlRZ3VBZTR6MzlydEJJaGVCRzZ0R0lLUEdwSnhEWDF2TFpKWUlOOWJpL1U5TlZhdEdkUzZ1Ym5nbzJwYUpacFBpVUlOaXhHdHFUSHVoTTMybE50WnlxTHNteVE0UUU0dlNhZW1QOStkWDM2R2lreVd5aFg5L21xcWhLakxBckxueXpmVkJSb1I4NVpFSUM0NUMyZG1naTVhSWpCU0ZWNGhkN05OSnh4cEdwakthelFXTnhHbk5HTmt6YzVmVmF4eVpWR3ppNk9KdnJmRDJWNHppdXN1SWtpeEo3YmtnUTR0RlRRZXZ1SDc0TUFqTUNqN2xZazdmMFdhcmJCcEdYT2xzc1NNSm5taG5oRkRFVGJCaUZPcEI1VVRKRktMZG52QzBQYlhGK1hlZnk3VmJMdWE5bDFHbnVPWHAydnFZakpHZDFjdHEySGNiWUJHVjYyRkhxc2lqUVFLdFRucXRXSzMvczZ1N2hEZzIxZW5yMVJGOCs4NXllejZpbTBVaUpqbkpZNU1NUWoxYm5aY3lqdEppT1ZYYUZxdllnUDZxWXJvVVdZMHVYeXhERmpVZ2lGSmNoOEpyS0VVeEJWZWlUYXBpUUlkejVZaVlDVm0ybXBFTGh2SEFwbC9tc0xqdTlldjY5cmhCOTE0Z0xUUFN3M3l2dUt6MTVNZEZ5UFZFNHJlU09LNDBScVJkVVNoTTBsaWREMjA5VmdyNHNMV2ZQcUJLZGNFd3lnY1lrVUpyUmRqeFA0NUV2VTZFa09WQ0h2ZGFiSlgzdnlNNVdpQVlxS2hXZ3BackFiNzY4MS9PbkY1VDZURFdsTFhxb3VuRVVMU0p4bExieEp6VldxNnp4OWJCTmdWbEJwUXFKU3NSbHFnbVE5VnhYSGduT0FzRFptQzQ0dW5tNGtkT1RvdEZFUkphSFk4TC9VV2ZMaFN6WDBwaldnUUcxUE8vSUhvb3JyWGE2ZzZxSDdnYU1CM0tta0xrZ0NRcXN6S0tkbitTTlZ4RFlqQzFpTmUxZ29sSUViZGpnK1F1VmtEVnZDOVZnbzRGcEIwUGsvQ0Nucm10WTRPb0FucTBSQVFRaGgrU3d3OVdNYVNyNDBtalU4QnJJT1VmNXFEL2p5b2Y5bzl6VVI3QXo3USttRFlnSXFEV3R4OGd5MG95MWdad1ovNEwyR2pvUGs5ZlpBeDQ4eW1oQjRBd2JLQUJpQ3RFZFFLTWVGWldvdlNLd2dGSDFhSWtGSFp1bXhvOE9takNhYnVncXZiM0hqNkMxWTdnMGhkRDM2TXFXNHk3d21VWjVrY0FXZTBoc1pMbUswTmFPYXUvM082YXFINElwbWNJZXZSamlXODZVWUdnai9ObmhmODRFYzZ2QnVZOUhESFRseHgxWmhlRGFveUtiOVpwS1UxYWNlVHBkL1IvL1pGcFhKMXE3MHBoSk14cUpUMXZFT0paRHl3TWN1emM0U0I2b21rbG1oV0VtVkljeFI3QXBVa2p1dm1wRVJ4d20wa3p0T0lBenA4eUlpM2J6T0tGRnJjY2t1TDFXeXpFWHg4eklhTWRFMkg1RTVVcnRFOE9RU2x4VlM4T2podFdnUHFHYkVnZGY2OXNPTnVIT1kvQS92SWVwUmdFYUJEWWx3Q3RoZ2g4dXRNSHBTemhrMWFDQnFZMGZFem5IK0lBQitwcUM3S3VMTlZuNG1rMjhRYmlIOUVGMzhTTTZBZUZrWXh6WGhrT0xhSTZPYkl5MVZ0Mk50S2ZFSXlmVTIvZnY5Zm5tVjYxWFYyam5STHM5UlZhazkrLyt3UjZ6R2RhTnBPYWlUSVZOTWpWYWNXeGJIOTk4dysrK2dSRkUrK0xKQlpXWWdlOGpWU2sxWTdKOHZDTTlQdXFFRFlSV29EdzlhVWRnSGtFN2xObzRiazJ2VHlkc2dHUk1xOU1Uc0lQaUlabmIxa1JlR0xHY2ZhUTFIall4MCtjUEh6UlpySFRPRm5CLyt4c0J6Z2N6am5jN1hULzdUczdQUDMrSDVUOUY5ZEtubTF1ZGFNR1k3SXZDMFg2M1ZieExkTXdkaE1zSzRjN0EvZzV2QVhpQmp6RjY4dVV4c1M1ajIxRFpTMXBaRFJYb01GTHp2ZldjTWVlMzVzWEZab1grUm1xcVZOT1FiWThLa1pOKyt1TkxiYzQzY2lJd2JZOHF2dHFDZE15UWJPZlRNN0tIdkxTaXdBSjJENSsxM0Z6ajJna0FPN0dQckprRWkwazRVbks4N1hSa0drOWtPbU95cGlDZXFoR0x4LzZ6b0NLRmVVRmcwWXRya29IWThUMjBQaCtteldIcURHQlBlSjhEQU5uS0NwVjF4aHRtT2ZwTnIzNzhpNExaVW5jM1h5bnRWeVVjM2xzK1lzM0pzbWRaT3JMbjJNUHFPRVlYQnUzR3dhT1FCTWpXWUdJRTZIeW14UVRXRmlrUXRkbWJDczNaZHlQd1ljNEoyWnROa0puWnQ3R01rVzlQMU9CTGg0UTMwRVhDRmxma0pXMXFkUGR0U3pDZllJcWg4NUcyeGV3alp4cHhjTW9CK1Fuc1dqYmU0bEhOK1dDYWhqVTl1MHREZ0JsQkYzbW1GbjZOWVZmSStKWmxQa3pXRHAxOCtQQmErM2czQkR5RlNUQ1A4Y1I3R2tadUVtNjAydFFFOFZVclhzK1dseHJQcGxxd0toajNqVDl1dGJwYWF6bWVVWTJNTzRVelRSRjd6V2hiRnBZQjVrUGZ0QWxwd0krU0pNMDJhQWdQaXdFa3ZCcm9iQUlZNmY1K1J5dm5tZ1lqSk9IS2V2dnZYL29Tb05sUU5UT1pvcDNBOThYR3FoSkkvZTFmZjlkaWM2NERaY3p3cEFBL3F0QUs4TmRpenNLTnE3T293U01iT3pBYWd5V3NxeFpHVmd3d2kzQjhxZzU1SGNiWi9KdUpOTlhPMklFbVRKd05WTTJDNTN5OGZRMHRBZHhzTTh6K0xESkdsdXZONTlmcStOSHErWVl2OXV3dUU4MVhhMzM2OElaeHpEVmRMQWtDRnpWbUI3UXdHdUFGMXRrRUhaaGpXbVYyNndwUEsvTjZhSTI1MVZrc3BzZ0VMV0dhTTV6ZlpwenNrVE1NanBOUWlUaitvdmJ4cTU2dW5zRURYeCszSDVXeWFwWWNsaHZhTW42ejZUbVZPeWpoRGlBTVpod085S2hFVGp2TitKZE1nd2tzQ0Zmc3prQ1JiZm91LzZvOHljRkZ4bXJhODFrRUFqeFdFbFkydXpaK1RndnRZZE04Y3RmZ0pHMnVEN2R2MlZYYVlkbTVPcjlRWE1RczB0enJZR0pBbC9kcEcvdk83bkdMeU56QlIyak1vSUg0RUNOVzQ3aFRwWHVveTQxWjI3TFdnd1d6T0prVnhLeWpTUWFsRFcyV0s2eXUwNGpLSEhkSHBieEpXbmdqM3BUQWlIQzZsalB6R0syeGJwSjdGUUFyUTN4anhPaEZlQWcyMzFMaU13d3ZHaTlaSDNaa05OWCtZUWNTVG5yNjVDV0NOUGRhci9YSUxYTEwzYVF4NFBsMHlkcmFRT2tqM01ubG9yRUw3bERqZUt2OTQ5MnczaWJiYjdwODlselhXQWpkOG5XK2VxSHp6WE4rMW1yTHJVbkdXUGVvdmNkM2JyNTlvclRjZXh0WXBZKzROSlhpTHVDNGovVmc3cFBSV0JDWWxjTFI5Wk9uQ05vRjlkd3ZEWXMrbXg0V0VVNERYVDI5MVBMeUVrWWRsTlZ3aHl2SDkrelNHZmRNV0VpODNlcC9aYTRaL3V2ZzlUNEFBQUFBU1VWT1JLNUNZSUk9Ii8+PC9nPjxwYXRoIGQ9Ik0zNy41MDAgNi40NjggTDM3LjUwMCAzNC41MzIiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZjFmMWYxIiBzdHJva2Utd2lkdGg9IjEiLz48Zz48cGF0aCBkPSJNMjEuMzQwIDMwLjAwMCBMMjEuMzQwIDI1LjA0NyBMMjIuNzU4IDI1LjA0NyBMMjIuNzU4IDMwLjAwMCBMMjQuMDAwIDMwLjAwMCBMMjQuMTEzIDIxLjU5MyBDMjQuMTEzIDIxLjU5MyAyNi4yMTEgMjUuNDQzIDI2LjIxMSAyNS40NDMgQzI2LjIxMSAyNS40NDMgMjcuMDM3IDI1LjA0MiAyNi45OTcgMjQuOTE3IEMyNS45MzUgMjEuNTkzIDI0Ljc4MyAxOC4wNDIgMjQuNzgzIDE4LjA0MiBMMjIuMDAyIDE4LjA1MCBMMTkuMjIxIDE4LjA0MiBDMTkuMjIxIDE4LjA0MiAxOC4wNjggMjEuNTkzIDE3LjAwNyAyNC45MTcgQzE2Ljk2NyAyNS4wNDIgMTcuNzkzIDI1LjQ0MyAxNy43OTMgMjUuNDQzIEMxNy43OTMgMjUuNDQzIDE5Ljg5MCAyMS41OTMgMTkuODkwIDIxLjU5MyBMMjAuMDAzIDMwLjAwMCBMMjEuMzQwIDMwLjAwMCBaIE0yMi4wMDAgMTguMDAwIEMyMy42NTcgMTguMDAwIDI1LjAwMCAxNi42NTcgMjUuMDAwIDE1LjAwMCBDMjUuMDAwIDEzLjM0MyAyMy42NTcgMTIuMDAwIDIyLjAwMCAxMi4wMDAgQzIwLjM0MyAxMi4wMDAgMTkuMDAwIDEzLjM0MyAxOS4wMDAgMTUuMDAwIEMxOS4wMDAgMTYuNjU3IDIwLjM0MyAxOC4wMDAgMjIuMDAwIDE4LjAwMCBaIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9InVybCgjZzgpIiBzdHJva2U9IiM0ZDM5MDAiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLW9wYWNpdHk9IjAuNTUiLz48cGF0aCBkPSJNMjAuMDMwIDE4LjAxNCBDMjAuMDMwIDE4LjAxNCAyMS4wMzEgMjAuOTUxIDIyLjAxOSAyMC45NDUgQzIzLjAwOCAyMC45MzkgMjMuOTc3IDE3Ljk5MCAyMy45NzcgMTcuOTkwIEwyMC4wMzAgMTguMDE0IFoiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZmlsbD0idXJsKCNnOSkiLz48L2c+PC9nPjwvc3ZnPg=="},"pegfly":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAkCAYAAACXOioTAAAEyUlEQVR42u2XW2wUZRTHf2dmdmfX3ZbeWFoKVRGjLb1gh0IQiD4gweBDTSBGSTQxRmNCxJiIUfHJBxOVGJ/QB/FS1OAN7xEtIJUEiGwBgYIocqm0QGlZSi97mZnjw1bQBsJu0Tf+jyfzze/7zvmf883ANY1RcqUHqmudB4GbgITAtx374r/+p6C6Budlz+Ppux2PKeXKuUHhh90GXX1yqKRAnW072geuGjStztlw2xR/QctTaUXA9xBDgDD6yUZTnm8JUFqo0W072gdzBVmjA/UNTnNlqS5oeS6t6fOIqiAoCpARWTzXU1XkhQ8CO4DaXEHG6EAyw0svLs3gDlyE/H10QUmlRJbM9zQ2TqdV1zrXjxkkcKtT7auvXID8WwrDyF3TfYB7xgwKBxUMUJXLFtVXKI4owLgxg84nhfQAIqKXXKAIhoke6hKA38YMClqsa/nRImihOsqUiiCi4COte0wO7It/fDWpe/jV9RYnekXswAhLBAQME4KWsOQVm6QyVFPvDDTNaJyeC8gcHeju7s5UTa745q1W69GiqMrNFWCZoJ5B4rDL9nVJFhYb+vhUNxirILjpqBnoPd395ZgnQ029s7dUtXZ5RYZyY0DTw76IbxEtC1NYpUy8Q/DOqC5aY8tgSpp374p/kVfDAkytceYsnObVrrovo12H0XR/xFCFyjshEIbOVgiVQSYAaxenmf+2/fmV5qZxGWtFiovAj8L4RgwxVNVTvJTiDivhmHDusGIVIOWTVR+Z6VFd56zNG+R6dPf2g2Eg6kGsCfEz2S2rQjimnNkluMOCGUOWz81o1NaldQ3O5LxA55N0HusxQLMJMW0oqQHfzw4Gu1gIlSid34GYYJTDinkuKY/P8gL1Ho8nDnULRFEvmX15tArMYJatvhKdBL4LPbuEQAHS7HhaWaQzahucutxrBAylAQ9J92drrF62nVDAB7tEiExUzu2DoycFJiDLZrqkPVbnBVLlJElI9SlijnSCXrSWXayICOOqlK82m1hRaJ7laXFY51TXObGcQUBXYlDwhiE1PDJ6Lm4CVbBLFcOGRAK+3mJilMH99R4iPJszSITOkwkhbMPGXwyMEW9cWOFDqBRcDxZV+zzxTkBTg0gkDKrU5AwKWBzb3ykUxVQ/ajOxgqgYwsBxMEbaPFSSdWJ1sY8KMu2Z0NBrbdbBcWFdmvMIaprROCmZkc7iAuXISeH4m0lNgwyeyNo9VApiwNkDgjWsLNsU5MMdZoTenUN5meHnne1/7t0Tl7at7XKdzevvb7HEMsAugv4jgmGB+kKoTElmYGmty40x3Z/fCBolX1mzod3ACKCBAkHTSuKUgCihMsHzhdkxXx+b7d4wtcbZk9M1cSn19XSfOquVK59c4Jq+CV4/vNdmMdfx8XzBsqH/tMi8Sb4mPCnvMyqtnlPdm/M+EUDE5o2WnyxMAasQaib4On+lTTCoFExULZqqnB9Gmm9xSbo0jCl1AK7P6g1xAyOEWgXQWOHLH2ck3bTc5tMtphSWQ6Ra2HDMwjbJ5HQfXUq/d8Q7UMdb32qa987ziMcNbIv0zvZ2e2XKeXfF2sADwMGwzfdVJbqiI9+P/H/q9lmNpb0Dsirj8lAgyInxEa3bur397LV/pf9VfwEILPoG+N+37wAAAABJRU5ErkJggg=="};
}
return ugfMapsArt.c;
}
function ugfMapsWanted() {
const h = window.location.host;
const p = window.location.pathname || "";
if (h !== "www.google.com" && h !== "maps.google.com") {
return false;
}
if (h === "www.google.com" && !/^\/maps(\/|$)/.test(p)) {
return false;
}
// Directions, Street View, My Maps, embeds and the rest stay Google's: Gplex
// hands those to the real app rather than half-doing them
if (/^\/maps\/(d|contrib|timeline|embed|preview|api|reserve|vt|about|lists|saved|_)(\/|$)/.test(p)) {
return false;
}
// Street View opens in Gplex's own viewer; photos and the rest stay Google's
if ((/,\d+(\.\d+)?a,/.test(p) || /!1e1\b|!3m\d+!1e3/.test(window.location.href) ||
/[?&](map_action=pano|layer=c(&|$)|cbll=)/.test(window.location.search || "")) && !ugfMapsStreetFromUrl()) {
return false;
}
// and Maps inside a frame (Gplex's Street View runs Google's viewer in one) is left alone
try {
if (window.top !== window.self) {
return false;
}
} catch (e) {
return false;
}
let on = null;
try {
on = window.localStorage.getItem("UGF_MAPS_ON");
} catch (e) {}
return on !== "false";
}
// Which Google Maps a layout gets. Maps began in February 2005, so everything
// older shows the 2005 beta. The old-browser (legacy) layouts get classic Maps,
// which is what Google kept serving to old browsers.
function ugfMapsEra() {
const l = String(layout || "2015");
if (l === "2022") {
return "m2022";
}
if (l === "2019") {
return "m2019";
}
if (["2015", "2016", "2016C", "2018", "2018M"].indexOf(l) > -1) {
return "m2015";
}
if (l === "2014") {
return "m2014";
}
if (["2012", "2013", "2013L", "2015L", "2016L"].indexOf(l) > -1) {
return "m2011";
}
if (l === "2010N") {
return "m2010";
}
if (l === "2007" || l === "2009") {
return "m2007";
}
if (l === "2006") {
return "m2006";
}
return "m2005";
}
function ugfMapsYear() {
if (UGF_LATE2015) {
return "2015";
}
const m = String(layout || "").match(/(\d{4})/);
const y = m ? parseInt(m[1], 10) : 2015;
return String(Math.max(2005, y));
}
// The tile colours for each period, as the tile server's style rules.
// 2015 is sampled straight off the map in the UI kit; 2016-2018 is the lighter
// map with yellow highways and wide white main roads.
function ugfMapsPalette() {
// late 2015 and early 2016 still had the 2015 map; the lighter one came on 25 July 2016
const l = (UGF_LATE2015 || UGF_EARLY2016 && String(layout) === "2016") ? "2015" : String(layout || "2015");
const set = function(rules) {
return rules.join(",");
};
const oldIcons = ["s.t:2|s.e:l.i|p.v:off", "s.t:4|p.v:off"];
if (l === "2022") {
return ""; // the present-day map as Google draws it
}
if (["2016", "2016C", "2016L", "2018", "2018M", "2019"].indexOf(l) > -1) {
return set([
"s.t:5|s.e:g.f|p.c:#ffebe9e5", "s.t:6|s.e:g.f|p.c:#ffaadaff", "s.t:40|s.e:g.f|p.c:#ffc0ecae",
"s.t:49|s.e:g.f|p.c:#fffdd964", "s.t:49|s.e:g.s|p.c:#ffe8b74a",
"s.t:50|s.e:g.f|p.c:#ffffffff", "s.t:50|s.e:g.s|p.c:#ffd9d6cf", "s.t:50|s.e:g|p.w:2.2",
"s.t:51|s.e:g.f|p.c:#ffffffff", "s.t:51|s.e:g.s|p.c:#ffe0ddd6", "s.t:2|s.e:l.i|p.v:off"
]);
}
if (["2013", "2013L", "2014", "2015", "2015L"].indexOf(l) > -1) {
return set([
"s.t:5|s.e:g.f|p.c:#ffe8e4dc", "s.t:6|s.e:g.f|p.c:#ffa3ccff", "s.t:40|s.e:g.f|p.c:#ffcadfaa",
"s.t:49|s.e:g.f|p.c:#fff99c24", "s.t:49|s.e:g.s|p.c:#ffe49309",
"s.t:50|s.e:g.f|p.c:#fffee068", "s.t:50|s.e:g.s|p.c:#ffeac452",
"s.t:51|s.e:g.f|p.c:#ffffffff", "s.t:51|s.e:g.s|p.c:#ffd8d4cb", "s.t:2|s.e:l.i|p.v:off", "s.t:4|s.e:l.i|p.v:off"
]);
}
if (["2007", "2009", "2010N", "2012"].indexOf(l) > -1) {
return set([
"s.t:5|s.e:g.f|p.c:#fff2efe9", "s.t:6|s.e:g.f|p.c:#ff99b3cc", "s.t:40|s.e:g.f|p.c:#ffc9dfaf",
"s.t:49|s.e:g.f|p.c:#fffcc563", "s.t:49|s.e:g.s|p.c:#ffd69a3a",
"s.t:50|s.e:g.f|p.c:#fffff4a4", "s.t:50|s.e:g.s|p.c:#ffd8c874",
"s.t:51|s.e:g.f|p.c:#ffffffff", "s.t:51|s.e:g.s|p.c:#ffc9c9c9", "s.e:l.t.f|p.c:#ff222222", "s.e:l.t.s|p.c:#ffffffff"
].concat(oldIcons));
}
// 2005-2006: the original map - pale yellow roads, orange-yellow freeways with
// a dark edge, the grey-blue water
return set([
"s.t:5|s.e:g.f|p.c:#fff2efe9", "s.t:6|s.e:g.f|p.c:#ff99b3cc", "s.t:40|s.e:g.f|p.c:#ffc9dfaf",
"s.t:49|s.e:g.f|p.c:#fffdd35c", "s.t:49|s.e:g.s|p.c:#ffb5842b",
"s.t:50|s.e:g.f|p.c:#ffffffa1", "s.t:50|s.e:g.s|p.c:#ffc0b16f",
"s.t:51|s.e:g.f|p.c:#ffffffff", "s.t:51|s.e:g.s|p.c:#ffbfbfbf", "s.e:l.t.f|p.c:#ff222222", "s.e:l.t.s|p.c:#ffffffff"
].concat(oldIcons));
}
function ugfMapsLang() {
try {
return String(navigator.language || "en").split("-")[0] || "en";
} catch (e) {
return "en";
}
}
function ugfMapsTileUrl(type, x, y, z) {
// "m,traffic" and the like: a base map with Google's own overlay drawn in
const parts = String(type).split(",");
const extra = parts.slice(1).join(",");
type = parts[0];
const style = (type === "m" || type === "p") ? ugfMapsPalette() : "";
// From zoom 17 in, the "m" roadmap stops telling highways, main roads and side
// streets apart - every road comes out as plain "road" in today's blue-grey and
// the era colours have nothing to hold on to. The "r" roadmap is the same map
// with the road classes kept all the way in, so the styled map uses that.
if (type === "m" && style) {
type = "r";
}
const retina = (window.devicePixelRatio || 1) > 1.4 ? "&scale=2" : "";
return "https://mt" + ((x + y) % 4) + ".google.com/vt/lyrs=" + type + (extra ? "," + extra : "") + "&x=" + x + "&y=" + y + "&z=" + z +
"&hl=" + encodeURIComponent(ugfMapsLang()) + retina +
(style ? "&apistyle=" + encodeURIComponent(style) : "");
}
// ---- the map ---------------------------------------------------------------
function ugfMapsCreate(host, opts) {
const T = 256;
const m = { z: 4, type: "m", ov: [], minZ: 2, maxZ: 21, markers: [], moveFns: [], clickFns: [], zoomFns: [] };
let cx = 0;
let cy = 0;
host.innerHTML = ugfTT("");
host.classList.add("ugf-maps-canvas");
host.tabIndex = 0;
const pane = document.createElement("div");
pane.className = "ugf-maps-pane";
host.appendChild(pane);
const overlay = document.createElement("div");
overlay.className = "ugf-maps-overlay";
host.appendChild(overlay);
// routes are drawn in one SVG under the markers
const SVGNS = "http://www.w3.org/2000/svg";
const routeSvg = document.createElementNS(SVGNS, "svg");
routeSvg.setAttribute("class", "ugf-maps-route");
overlay.appendChild(routeSvg);
m.routes = [];
// The route is drawn once per zoom level, for the view and a screen's worth
// round it, and dragging only slides it along; it is redrawn when the zoom
// changes, the routes change, or the map is dragged out of the drawn area.
// (Redrawing thousands of points on every frame of a drag is what made the map
// crawl with directions up.)
let routeBuilt = null;
m.routesVer = 0;
const routeGroup = document.createElementNS(SVGNS, "g");
routeSvg.appendChild(routeGroup);
const buildRoutes = function(left, top, s, w) {
while (routeGroup.firstChild) {
routeGroup.removeChild(routeGroup.firstChild);
}
const x0 = Math.round(left - s.w * 0.75);
const y0 = Math.round(top - s.h * 0.75);
const x1 = x0 + Math.round(s.w * 2.5);
const y1 = y0 + Math.round(s.h * 2.5);
routeSvg.setAttribute("width", x1 - x0);
routeSvg.setAttribute("height", y1 - y0);
m.routes.forEach(function(rt) {
if (!rt.pts || rt.pts.length < 2) {
return;
}
// world pixels for every point, worked out once per zoom level
if (rt._pz !== m.z) {
rt._xs = new Float64Array(rt.pts.length);
rt._ys = new Float64Array(rt.pts.length);
rt.pts.forEach(function(q, k) {
const p = project(q.lat, q.lng, m.z);
rt._xs[k] = p.x;
rt._ys[k] = p.y;
});
rt._pz = m.z;
}
const xs = rt._xs;
const ys = rt._ys;
// the copy of the world nearest the view, from the route's first point
const shift = -Math.round((xs[0] - left - s.w / 2) / w) * w;
let d = "";
let open = false;
let lx = 0;
let ly = 0;
for (let k = 0; k < xs.length; k++) {
const x = xs[k] + shift;
const y = ys[k];
if (k > 0) {
const px = xs[k - 1] + shift;
const py = ys[k - 1];
// leave out stretches nowhere near the drawn area
if (Math.max(x, px) < x0 || Math.min(x, px) > x1 || Math.max(y, py) < y0 || Math.min(y, py) > y1) {
open = false;
continue;
}
if (!open) {
d += "M" + (px - x0).toFixed(1) + " " + (py - y0).toFixed(1);
open = true;
lx = px;
ly = py;
}
// and points that land on the same pixel as the last one
if (k < xs.length - 1 && Math.abs(x - lx) < 1.5 && Math.abs(y - ly) < 1.5) {
continue;
}
d += "L" + (x - x0).toFixed(1) + " " + (y - y0).toFixed(1);
lx = x;
ly = y;
}
}
if (!d) {
return;
}
(rt.layers || []).forEach(function(ly2) {
const path = document.createElementNS(SVGNS, "path");
path.setAttribute("d", d);
path.setAttribute("fill", "none");
path.setAttribute("stroke", ly2.color);
path.setAttribute("stroke-width", ly2.width);
path.setAttribute("stroke-opacity", ly2.opacity === undefined ? 1 : ly2.opacity);
path.setAttribute("stroke-linecap", "round");
path.setAttribute("stroke-linejoin", "round");
if (ly2.dash) {
path.setAttribute("stroke-dasharray", ly2.dash);
}
if (rt.onclick) {
path.setAttribute("class", "hit");
path.addEventListener("click", function(ev) {
ev.stopPropagation();
rt.onclick();
});
}
routeGroup.appendChild(path);
});
});
routeBuilt = { z: m.z, ver: m.routesVer, x0: x0, y0: y0, x1: x1, y1: y1, w: s.w, h: s.h };
};
const drawRoutes = function(left, top, s, w) {
const b = routeBuilt;
if (!b || b.z !== m.z || b.ver !== m.routesVer || b.w !== s.w || b.h !== s.h ||
left < b.x0 + s.w * 0.25 || left + s.w > b.x1 - s.w * 0.25 || top < b.y0 + s.h * 0.25 || top + s.h > b.y1 - s.h * 0.25) {
buildRoutes(left, top, s, w);
}
// moved as one layer by the graphics card, so a drag repaints nothing
routeSvg.style.transform = "translate3d(" + Math.round(routeBuilt.x0 - left) + "px," + Math.round(routeBuilt.y0 - top) + "px,0)";
};
let front = null;
let back = null;
const ws = function(z) {
return T * Math.pow(2, z);
};
const project = function(lat, lng, z) {
let s = Math.sin(lat * Math.PI / 180);
s = Math.max(-0.9999, Math.min(0.9999, s));
const w = ws(z);
return { x: (lng + 180) / 360 * w, y: (0.5 - Math.log((1 + s) / (1 - s)) / (4 * Math.PI)) * w };
};
const unproject = function(x, y, z) {
const w = ws(z);
const n = Math.PI - 2 * Math.PI * y / w;
return { lat: 180 / Math.PI * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))), lng: x / w * 360 - 180 };
};
const size = function() {
return { w: host.clientWidth || 800, h: host.clientHeight || 600 };
};
const setPx = function(x, y) {
const w = ws(m.z);
const s = size();
cx = ((x % w) + w) % w;
// keep the poles from sliding into view past the edge of the world
const half = Math.min(s.h / 2, w / 2);
cy = Math.max(half, Math.min(w - half, y));
};
const layer = function(z) {
const d = document.createElement("div");
d.className = "ugf-maps-layer";
d._tiles = {};
d._z = z;
d._pending = 0;
// Tiles are placed from where the view was when the layer was made, not
// from the corner of the world: past zoom 16 the world is wider than the
// 33 million pixels a browser can position anything at, and tiles placed
// that far out all pile up in one corner - which is what left the map
// blank close in.
d._ox = Math.round(cx);
d._oy = Math.round(cy);
pane.appendChild(d);
return d;
};
const place = function() {
const s = size();
const left = cx - s.w / 2;
const top = cy - s.h / 2;
const w = ws(m.z);
m.markers.forEach(function(mk) {
const p = project(mk.lat, mk.lng, m.z);
let x = p.x - left;
// the copy of the world nearest the view
x -= Math.round((x - s.w / 2) / w) * w;
mk.el.style.left = Math.round(x - mk.ax) + "px";
mk.el.style.top = Math.round(p.y - top - mk.ay) + "px";
});
if (m.routes.length || routeGroup.firstChild) {
drawRoutes(left, top, s, w);
}
};
// The tile server has nothing worth showing past zoom 20 - out of town the
// roads simply stop being drawn and the map goes blank - so the last two
// steps in are zoom 20's tiles, enlarged, the way Maps itself overzooms.
const NATIVE = 20;
const draw = function() {
const s = size();
const tz = Math.min(m.z, NATIVE);
const k = Math.pow(2, m.z - tz);
const D = T * k;
const n = Math.pow(2, tz);
const left = cx - s.w / 2;
const top = cy - s.h / 2;
const kind = m.type + (m.ov.length ? "," + m.ov.join(",") : "");
// (a long pan - round the world at the date line - starts a fresh layer
// too, so nothing in it strays far from its origin)
if (!front || front._z !== m.z || front._type !== kind ||
Math.abs(cx - front._ox) > 4e6 || Math.abs(cy - front._oy) > 4e6) {
if (front) {
if (back) {
back.remove();
}
back = front;
}
front = layer(m.z);
front._type = kind;
}
const want = {};
const tx0 = Math.floor(left / D) - 1;
const tx1 = Math.floor((left + s.w) / D) + 1;
const ty0 = Math.max(0, Math.floor(top / D) - 1);
const ty1 = Math.min(n - 1, Math.floor((top + s.h) / D) + 1);
for (let ty = ty0; ty <= ty1; ty++) {
for (let tx = tx0; tx <= tx1; tx++) {
const key = tx + "/" + ty;
want[key] = true;
if (front._tiles[key]) {
continue;
}
const img = document.createElement("img");
img.className = "ugf-maps-tile";
img.draggable = false;
img.alt = "";
img.style.left = (tx * D - front._ox) + "px";
img.style.top = (ty * D - front._oy) + "px";
if (k > 1) {
img.style.width = D + "px";
img.style.height = D + "px";
}
front._pending++;
const lay = front;
img.onerror = function() {
// one retry through another of the tile servers, then leave the gap
if (!img._retried) {
img._retried = true;
const src = img.src;
setTimeout(function() {
img.src = src.replace(/\/\/mt(\d)\./, function(a, d) {
return "//mt" + ((parseInt(d, 10) + 1) % 4) + ".";
});
}, 400);
return;
}
img.style.visibility = "hidden";
img.onload();
};
img.onload = function() {
if (img._done) {
return;
}
img._done = true;
lay._pending--;
img.classList.add("in");
if (lay === front && lay._pending <= 0 && back) {
back.remove();
back = null;
}
};
img.src = ugfMapsTileUrl(kind, ((tx % n) + n) % n, ty, tz);
front.appendChild(img);
front._tiles[key] = img;
}
}
Object.keys(front._tiles).forEach(function(key) {
if (!want[key]) {
front._tiles[key].remove();
delete front._tiles[key];
}
});
front.style.transform = "translate(" + Math.round(front._ox - left) + "px," + Math.round(front._oy - top) + "px)";
if (back) {
const k = Math.pow(2, m.z - back._z);
back.style.transform = "translate(" + (back._ox * k - left) + "px," + (back._oy * k - top) + "px) scale(" + k + ")";
}
place();
const ll = unproject(cx, cy, m.z);
m.lat = ll.lat;
m.lng = ((ll.lng + 540) % 360) - 180;
m.moveFns.forEach(function(fn) {
try {
fn();
} catch (e) {}
});
};
const api = {
el: host,
project: project,
unproject: unproject,
view: function() {
return { lat: m.lat, lng: m.lng, z: m.z, type: m.type };
},
setView: function(lat, lng, z) {
if (z !== undefined && z !== null) {
m.z = Math.max(m.minZ, Math.min(m.maxZ, Math.round(z)));
}
const p = project(lat, lng, m.z);
setPx(p.x, p.y);
draw();
},
// zoom about a point on screen (the middle when none is given), with the
// old tiles scaled into place until the new ones arrive
zoomTo: function(nz, sx, sy) {
nz = Math.max(m.minZ, Math.min(m.maxZ, Math.round(nz)));
if (nz === m.z) {
return;
}
const s = size();
if (sx === undefined) {
sx = s.w / 2;
sy = s.h / 2;
}
const k = Math.pow(2, nz - m.z);
const fx = cx + (sx - s.w / 2);
const fy = cy + (sy - s.h / 2);
const old = front;
m.z = nz;
setPx(fx * k - (sx - s.w / 2), fy * k - (sy - s.h / 2));
if (old) {
old.style.transition = "transform .22s ease-out";
setTimeout(function() {
old.style.transition = "";
}, 260);
}
draw();
m.zoomFns.forEach(function(fn) {
try {
fn(m.z);
} catch (e) {}
});
},
zoomIn: function() {
api.zoomTo(m.z + 1);
},
zoomOut: function() {
api.zoomTo(m.z - 1);
},
panBy: function(dx, dy) {
setPx(cx + dx, cy + dy);
draw();
},
panTo: function(lat, lng) {
const p = project(lat, lng, m.z);
const sx = cx;
const sy = cy;
let dx = p.x - sx;
const w = ws(m.z);
dx -= Math.round(dx / w) * w;
const dy = p.y - sy;
const t0 = performance.now();
const step = function(t) {
const f = Math.min(1, (t - t0) / 350);
const e = f < 0.5 ? 2 * f * f : 1 - Math.pow(-2 * f + 2, 2) / 2;
setPx(sx + dx * e, sy + dy * e);
draw();
if (f < 1) {
requestAnimationFrame(step);
}
};
requestAnimationFrame(step);
},
setType: function(t) {
m.type = t;
draw();
},
// routes: [{ pts: [{lat, lng}], layers: [{color, width, opacity, dash}], onclick }]
setRoutes: function(list) {
m.routes = list || [];
m.routesVer++;
place();
},
// the traffic, transit and cycling layers (one at a time, as in Maps)
setOverlay: function(name) {
m.ov = name ? [name] : [];
draw();
},
overlay: function() {
return m.ov[0] || "";
},
fit: function(points, pad) {
if (!points.length) {
return;
}
if (points.length === 1) {
api.setView(points[0].lat, points[0].lng, Math.max(m.z, 15));
return;
}
const s = size();
pad = pad || 60;
let z = m.maxZ - 4;
for (; z > m.minZ; z--) {
const ps = points.map(function(q) {
return project(q.lat, q.lng, z);
});
const xs = ps.map(function(q) { return q.x; });
const ys = ps.map(function(q) { return q.y; });
if (Math.max.apply(null, xs) - Math.min.apply(null, xs) < s.w - pad * 2 &&
Math.max.apply(null, ys) - Math.min.apply(null, ys) < s.h - pad * 2) {
break;
}
}
let la = 0;
let ln = 0;
points.forEach(function(q) {
la += q.lat;
ln += q.lng;
});
api.setView(la / points.length, ln / points.length, z);
},
addMarker: function(mk) {
overlay.appendChild(mk.el);
m.markers.push(mk);
place();
return mk;
},
removeMarker: function(mk) {
const i = m.markers.indexOf(mk);
if (i > -1) {
m.markers.splice(i, 1);
}
mk.el.remove();
},
clearMarkers: function() {
m.markers.slice().forEach(api.removeMarker);
},
screenToLatLng: function(sx, sy) {
const s = size();
const ll = unproject(cx + sx - s.w / 2, cy + sy - s.h / 2, m.z);
ll.lng = ((ll.lng + 540) % 360) - 180;
return ll;
},
metersPerPixel: function() {
return 156543.03392 * Math.cos(m.lat * Math.PI / 180) / Math.pow(2, m.z);
},
onMove: function(fn) {
m.moveFns.push(fn);
},
onClick: function(fn) {
m.clickFns.push(fn);
},
onZoom: function(fn) {
m.zoomFns.push(fn);
},
redraw: function() {
draw();
}
};
// dragging, with a little glide when let go
let drag = null;
let glide = 0;
host.addEventListener("pointerdown", function(ev) {
if (ev.button !== 0 || ev.target.closest(".ugf-maps-marker, .ugf-maps-iw, .ugf-maps-ctl, .hit")) {
return;
}
cancelAnimationFrame(glide);
drag = { x: ev.clientX, y: ev.clientY, sx: ev.clientX, sy: ev.clientY, t: performance.now(), vx: 0, vy: 0, moved: false };
try {
host.setPointerCapture(ev.pointerId);
} catch (e) {}
host.classList.add("dragging");
});
host.addEventListener("pointermove", function(ev) {
if (!drag) {
return;
}
const dx = ev.clientX - drag.x;
const dy = ev.clientY - drag.y;
const now = performance.now();
const dt = Math.max(1, now - drag.t);
drag.vx = dx / dt;
drag.vy = dy / dt;
drag.x = ev.clientX;
drag.y = ev.clientY;
drag.t = now;
if (Math.abs(ev.clientX - drag.sx) + Math.abs(ev.clientY - drag.sy) > 3) {
drag.moved = true;
}
api.panBy(-dx, -dy);
});
const end = function(ev) {
if (!drag) {
return;
}
const d = drag;
drag = null;
host.classList.remove("dragging");
if (!d.moved) {
const r = host.getBoundingClientRect();
const sx = ev.clientX - r.left;
const sy = ev.clientY - r.top;
const ll = api.screenToLatLng(sx, sy);
m.clickFns.forEach(function(fn) {
try {
fn(ll, sx, sy, ev);
} catch (e) {}
});
return;
}
let vx = d.vx * 16;
let vy = d.vy * 16;
if (performance.now() - d.t > 80 || Math.abs(vx) + Math.abs(vy) < 2) {
return;
}
const step = function() {
vx *= 0.9;
vy *= 0.9;
api.panBy(-vx, -vy);
if (Math.abs(vx) + Math.abs(vy) > 0.5) {
glide = requestAnimationFrame(step);
}
};
glide = requestAnimationFrame(step);
};
host.addEventListener("pointerup", end);
host.addEventListener("pointercancel", end);
let wheelAcc = 0;
let wheelAt = 0;
host.addEventListener("wheel", function(ev) {
ev.preventDefault();
const now = performance.now();
wheelAcc += ev.deltaMode === 1 ? ev.deltaY * 30 : ev.deltaY;
if (Math.abs(wheelAcc) < 60 || now - wheelAt < 200) {
return;
}
const r = host.getBoundingClientRect();
api.zoomTo(m.z + (wheelAcc < 0 ? 1 : -1), ev.clientX - r.left, ev.clientY - r.top);
wheelAcc = 0;
wheelAt = now;
}, { passive: false });
host.addEventListener("dblclick", function(ev) {
if (ev.target.closest(".ugf-maps-marker, .ugf-maps-iw, .ugf-maps-ctl, .hit")) {
return;
}
const r = host.getBoundingClientRect();
api.zoomTo(m.z + 1, ev.clientX - r.left, ev.clientY - r.top);
});
host.addEventListener("keydown", function(ev) {
if (ev.target !== host) {
return;
}
const k = ev.key;
if (k === "ArrowLeft") { api.panBy(-100, 0); }
else if (k === "ArrowRight") { api.panBy(100, 0); }
else if (k === "ArrowUp") { api.panBy(0, -100); }
else if (k === "ArrowDown") { api.panBy(0, 100); }
else if (k === "+" || k === "=") { api.zoomIn(); }
else if (k === "-" || k === "_") { api.zoomOut(); }
else { return; }
ev.preventDefault();
});
window.addEventListener("resize", function() {
draw();
});
if (opts && opts.lat !== undefined) {
m.z = Math.max(m.minZ, Math.min(m.maxZ, opts.z || 4));
const p = project(opts.lat, opts.lng, m.z);
setPx(p.x, p.y);
}
return api;
}
// ---- where to look, and what Google found ---------------------------------
// /maps/@37.77,-122.41,13z, /maps/place/Name/@..., /maps/search/pizza/@...,
// the old ?q= and ?ll=&z= addresses, or the last view for a bare /maps
function ugfMapsParseUrl() {
const href = window.location.href;
const path = decodeURIComponent(window.location.pathname || "");
const out = { kind: "view", q: "", name: "" };
const at = path.match(/@(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),(\d+(?:\.\d+)?)(z|m)/);
if (at) {
out.lat = parseFloat(at[1]);
out.lng = parseFloat(at[2]);
const v = parseFloat(at[3]);
out.z = at[4] === "z" ? v : Math.round(Math.max(3, Math.min(20, 27 - Math.log(v) / Math.LN2)));
}
const sv = ugfMapsStreetFromUrl();
if (sv && (sv.lat || sv.lng)) {
out.lat = sv.lat;
out.lng = sv.lng;
out.z = 17;
}
if (sv) {
out.street = sv;
}
let m = path.match(/^\/maps\/place\/([^/@]+)/);
if (m) {
out.kind = "place";
out.name = m[1].replace(/\+/g, " ");
}
// directions: /maps/dir///@.../data=...!3e, or ?api=1&origin=&destination=
if (/^\/maps\/dir(\/|$)/.test(path)) {
out.kind = "dir";
const segs = [];
(window.location.pathname || "").replace(/^\/maps\/dir\/?/, "").split("/").some(function(seg) {
if (/^@/.test(seg) || /^data=/.test(seg)) {
return true;
}
let t = seg;
try {
t = decodeURIComponent(seg.replace(/\+/g, " "));
} catch (e) {}
segs.push(t);
return false;
});
if (segs.length > 2 && segs[segs.length - 1] === "") {
segs.pop(); // the slash at the end
}
const qs0 = window.location.search || "";
const qp = function(k) {
const mm = qs0.match(new RegExp("[?&]" + k + "=([^&]*)"));
return mm ? decodeURIComponent(mm[1].replace(/\+/g, " ")) : "";
};
out.from = segs.length > 1 ? segs[0] : qp("origin");
out.to = segs.length > 1 ? segs[segs.length - 1] : (segs[0] || qp("destination"));
const md = href.match(/!3e(\d)/);
const tm = { driving: 0, bicycling: 1, walking: 2, transit: 3 }[qp("travelmode")];
out.mode = md ? parseInt(md[1], 10) : (tm !== undefined ? tm : 0);
return out;
}
m = path.match(/^\/maps\/search\/([^/@]+)/);
if (m) {
out.kind = "search";
out.q = m[1].replace(/\+/g, " ");
}
const pin = href.match(/!3d(-?\d+(?:\.\d+)?)!4d(-?\d+(?:\.\d+)?)/);
if (pin) {
out.pin = { lat: parseFloat(pin[1]), lng: parseFloat(pin[2]) };
}
const qs = window.location.search || "";
const q = qs.match(/[?&]q=([^&]+)/);
if (q && out.kind === "view") {
out.kind = "search";
out.q = decodeURIComponent(q[1].replace(/\+/g, " "));
}
const ll = qs.match(/[?&]ll=(-?[\d.]+),(-?[\d.]+)/);
if (ll && out.lat === undefined) {
out.lat = parseFloat(ll[1]);
out.lng = parseFloat(ll[2]);
const z = qs.match(/[?&]z=(\d+)/);
out.z = z ? parseInt(z[1], 10) : 13;
}
return out;
}
function ugfMapsMine(el) {
return !!(el && el.closest && el.closest('#ugf-maps, [id^="ugf-maps-"]'));
}
// Read what the hidden app came up with: one place, or a list of them. Every
// result carries its position in its link (!3d!4d), which is what
// this goes by rather than anything Google words differently per language.
function ugfMapsHarvest(done) {
let tries = 0;
let lastSig = "";
let stable = 0;
const clean = function(t) {
return String(t || "").replace(/\s+/g, " ").trim();
};
const iv = setInterval(function() {
tries++;
const path = window.location.pathname || "";
if (/^\/maps\/place\//.test(path)) {
const u = ugfMapsParseUrl();
let h1 = null;
document.querySelectorAll("h1").forEach(function(h) {
if (!h1 && !ugfMapsMine(h) && clean(h.textContent)) {
h1 = h;
}
});
if (!h1 && tries < 16) {
return;
}
clearInterval(iv);
const get = function(sel) {
const el = [].filter.call(document.querySelectorAll(sel), function(e) {
return !ugfMapsMine(e);
})[0];
return el ? clean(el.textContent) : "";
};
const web = [].filter.call(document.querySelectorAll('a[data-item-id="authority"]'), function(e) {
return !ugfMapsMine(e);
})[0];
const pos = u.pin || (u.lat !== undefined ? { lat: u.lat, lng: u.lng } : null);
done({
kind: "place",
items: pos ? [{
name: h1 ? clean(h1.textContent) : u.name,
lat: pos.lat, lng: pos.lng,
lines: [get('[data-item-id="address"]'), get('button[jsaction*="category"]'),
get('[data-item-id^="phone"]')].filter(Boolean),
web: web ? web.getAttribute("href") : "",
href: window.location.href.split("?")[0]
}] : []
});
return;
}
const seen = {};
const items = [];
document.querySelectorAll('a[href*="/maps/place/"]').forEach(function(a) {
if (ugfMapsMine(a)) {
return;
}
const href = a.getAttribute("href") || "";
const p = href.match(/!3d(-?\d+(?:\.\d+)?)!4d(-?\d+(?:\.\d+)?)/);
if (!p || seen[href]) {
return;
}
seen[href] = true;
let name = clean(a.getAttribute("aria-label") || a.textContent);
if (!name) {
const m = href.match(/\/maps\/place\/([^/]+)/);
name = m ? decodeURIComponent(m[1]).replace(/\+/g, " ") : "";
}
const card = a.closest('[role="article"]') || a.parentElement;
const lines = [];
String(card ? ugfMapsReadText(card) : "").split("\n").forEach(function(t) {
t = ugfMapsClean(t);
if (t && t !== name && t.length < 90 && lines.indexOf(t) === -1 &&
!/^(directions|website|call|share|save|order online|reserve a table|·)$/i.test(t)) {
lines.push(t);
}
});
items.push({ name: name, lat: parseFloat(p[1]), lng: parseFloat(p[2]), lines: lines.slice(0, 3),
href: href.split("?")[0] });
});
const sig = items.map(function(i) {
return i.href;
}).join("|");
if (items.length && sig === lastSig) {
stable++;
} else {
stable = 0;
}
lastSig = sig;
if ((items.length && stable >= 3) || tries > 60) {
clearInterval(iv);
done({ kind: items.length ? "list" : "none", items: items.slice(0, 20) });
}
}, 400);
}
// Google's app is hidden (visibility), and hidden text reads back empty through
// innerText - so read a copy laid out, off screen, inside Gplex's own page.
function ugfMapsReadText(el) {
const host = document.querySelector("#ugf-maps") || document.body;
const box = document.createElement("div");
box.setAttribute("style", "position:fixed;left:-99999px;top:0;width:400px;visibility:visible;");
box.appendChild(el.cloneNode(true));
host.appendChild(box);
let t = "";
try {
t = box.innerText || "";
} catch (e) {}
box.remove();
return t;
}
// The classic (2011-2013 style) header logo, the same one Gplex's results pages
// show for the layout, cut out of Google's own sprite so it has no white box behind
// it on the grey header.
function ugfMapsHeadLogo() {
const A = ugfMapsArt();
const l = String(layout || "");
if (l === "2012") {
return ' ';
}
if (l === "2015L") {
return ' ';
}
if (l === "2016L") {
return ' ';
}
return ' ';
}
// The tab icon Maps had in each period: Google's own "G" until Maps got an icon
// of its own, the map with the red pin (2009), the "g" and pin (2012), its flat
// redraw (2014), the folded Material map (Sep 2015) and the 2020 pin.
function ugfMapsFavicon() {
const A = ugfMapsArt();
const l = String(layout || "2015");
if (l === "2022") {
return A.fav2020;
}
if (["2016", "2016C", "2018", "2018M", "2019"].indexOf(l) > -1) {
return A.fav2015;
}
if (l === "2014" || l === "2015") {
return A.fav2014;
}
if (["2013", "2013L", "2015L", "2016L"].indexOf(l) > -1) {
return A.fav2012;
}
if (["2009", "2010N", "2012"].indexOf(l) > -1) {
return A.fav2009;
}
return A.fav1999;
}
function ugfMapsSetFavicon() {
const href = ugfMapsFavicon();
if (!href) {
return;
}
ugfApplyFavicon(href);
// Google puts its own icon back as the app loads, so keep ours on top
const mo = new MutationObserver(function(muts) {
for (let i = 0; i < muts.length; i++) {
for (let j = 0; j < muts[i].addedNodes.length; j++) {
const n = muts[i].addedNodes[j];
if (n.nodeType === 1 && n.tagName === "LINK" && /icon/.test(n.getAttribute("rel") || "") && !ugfIsOurFavicon(n)) {
ugfApplyFavicon(href);
return;
}
}
}
});
mo.observe(document.head || document.documentElement, { childList: true, subtree: true });
ugfKeepFavicon(function() {
return href;
});
let ticks = 0;
const iv = setInterval(function() {
ugfApplyFavicon(href);
if (++ticks > 30) {
clearInterval(iv);
}
}, 500);
}
// Searching, done by Gplex itself: the same request Google's app makes for its
// result list (www.google.com/search?tbm=map), read straight into Gplex's own
// list - so a search never reloads the page or passes through Google's app, and
// there is no way for it to end up on the modern page. null means the request did
// not work out, and the caller falls back to letting Google's app search.
function ugfMapsClean(t) {
// Google puts icon-font glyphs (the wheelchair, the dot) in its text
return String(t || "").replace(/[-]/g, "").replace(/\s*·\s*(·\s*)+/g, " · ")
.replace(/^\s*·\s*|\s*·\s*$/g, "").replace(/\s+/g, " ").trim();
}
function ugfMapsFetch(q, v, size, done) {
if (window.location.host !== "www.google.com") {
done(null);
return;
}
const w = Math.max(320, Math.round(size.w || 1024));
const h = Math.max(240, Math.round(size.h || 768));
const mpp = 156543.03392 * Math.cos(v.lat * Math.PI / 180) / Math.pow(2, v.z);
const pb = "!4m8!1m3!1d" + (mpp * h * 4.35).toFixed(2) + "!2d" + v.lng.toFixed(6) + "!3d" + v.lat.toFixed(6) +
"!3m2!1i" + w + "!2i" + h + "!4f13.1!7i20!10b1";
const url = "/search?tbm=map&authuser=0&hl=" + encodeURIComponent(ugfMapsLang()) +
"&q=" + encodeURIComponent(q) + "&pb=" + encodeURIComponent(pb);
ugfMapsGet(url, function(t, why) {
let res = null;
if (t !== null) {
try {
res = ugfMapsParseSearch(ugfMapsJson(t));
} catch (e) {
why = "unexpected reply (" + e.message + ")";
}
}
if (!res) {
console.log("[Gplex] Maps: search request failed (" + why + "), letting Google's app search");
}
done(res);
});
}
// Google's replies start with )]}' to stop them being run as script
function ugfMapsJson(t) {
t = String(t || "");
const i = t.indexOf("[");
if (i < 0) {
throw new Error("no data in the reply");
}
return JSON.parse(t.slice(i));
}
// One request to Google, by whichever way gets through from a userscript: its own
// fetch, the page's fetch, then XMLHttpRequest. cb(text) or cb(null, why).
function ugfMapsGet(url, cb) {
const ways = [];
let own = null;
try {
own = typeof fetch === "function" ? fetch : null;
} catch (e) {}
if (own) {
ways.push(["fetch", own]);
}
try {
const pw = typeof unsafeWindow !== "undefined" ? unsafeWindow : null;
if (pw && pw !== window && typeof pw.fetch === "function" && pw.fetch !== own) {
ways.push(["page fetch", pw.fetch.bind(pw)]);
}
} catch (e) {}
ways.push(["XMLHttpRequest", null]);
const why = [];
const next = function(i) {
if (i >= ways.length) {
cb(null, why.join("; "));
return;
}
let settled = false;
const ok = function(t) {
if (!settled) {
settled = true;
clearTimeout(timer);
cb(String(t), "");
}
};
const bad = function(r) {
if (!settled) {
settled = true;
clearTimeout(timer);
why.push(ways[i][0] + ": " + r);
next(i + 1);
}
};
const timer = setTimeout(function() {
bad("timed out");
}, 15000);
const f = ways[i][1];
if (f) {
try {
f(url, { credentials: "include" }).then(function(r) {
if (!r.ok) {
throw new Error("HTTP " + r.status);
}
return r.text();
}).then(ok).catch(function(e) {
bad((e && e.message) || "failed");
});
} catch (e) {
bad(e.message);
}
return;
}
try {
const x = new XMLHttpRequest();
x.open("GET", url, true);
x.withCredentials = true;
x.onload = function() {
if (x.status >= 200 && x.status < 300) {
ok(x.responseText);
} else {
bad("HTTP " + x.status);
}
};
x.onerror = function() {
bad("network error");
};
x.send();
} catch (e) {
bad(e.message);
}
};
next(0);
}
function ugfMapsIsPlace(a) {
return Array.isArray(a) && a.length > 18 && Array.isArray(a[9]) && typeof a[9][2] === "number" &&
typeof a[9][3] === "number" && typeof a[11] === "string" && a[11] !== "";
}
function ugfMapsParseSearch(d) {
let found = [];
// the result list: one entry per place, the place itself at [14]
const list = d && d[0] && Array.isArray(d[0][1]) ? d[0][1] : [];
list.forEach(function(r) {
if (Array.isArray(r) && ugfMapsIsPlace(r[14])) {
found.push(r[14]);
}
});
if (!found.length) {
// otherwise take the first place anywhere in the answer
const walk = function(a, depth) {
if (found.length || !Array.isArray(a) || depth > 14) {
return;
}
if (ugfMapsIsPlace(a)) {
found.push(a);
return;
}
for (let i = 0; i < a.length; i++) {
walk(a[i], depth + 1);
}
};
walk(d, 0);
}
const seen = {};
const items = [];
found.forEach(function(a) {
const key = String(a[10] || a[11] + a[9][2]);
if (seen[key]) {
return;
}
seen[key] = true;
const lat = a[9][2];
const lng = a[9][3];
let addr = "";
if (Array.isArray(a[2]) && a[2].length) {
addr = a[2].filter(function(x) {
return typeof x === "string";
}).slice(0, 2).join(", ");
}
addr = addr || (typeof a[39] === "string" ? a[39] : "") || (typeof a[18] === "string" ? a[18] : "");
if (!Array.isArray(a[13]) && typeof a[18] === "string" && a[18] !== a[11]) {
addr = a[18]; // a town or a street, not a business: its full name reads best
}
let phone = "";
try {
phone = a[178][0][1][0][0] || a[178][0][0] || "";
} catch (e) {}
let cat = Array.isArray(a[13]) && typeof a[13][0] === "string" ? a[13][0] : "";
let rating = "";
try {
if (typeof a[4][7] === "number") {
rating = a[4][7].toFixed(1) + (typeof a[4][8] === "number" ? " (" + a[4][8] + ")" : "");
}
} catch (e) {}
let web = "";
try {
web = typeof a[7][0] === "string" && /^https?:/.test(a[7][0]) ? a[7][0] : "";
} catch (e) {}
const name = ugfMapsClean(a[11]);
const lines = [];
[addr, phone, [rating, cat].filter(Boolean).join(" · ")].forEach(function(l) {
l = ugfMapsClean(l);
if (l && l !== name && lines.indexOf(l) === -1) {
lines.push(l);
}
});
items.push({
name: name, lat: lat, lng: lng, lines: lines, web: web,
href: "https://www.google.com/maps/place/" + encodeURIComponent(name).replace(/%20/g, "+") +
"/@" + lat.toFixed(7) + "," + lng.toFixed(7) + ",17z" +
(a[10] ? "/data=!4m5!3m4!1s" + a[10] + "!8m2!3d" + lat + "!4d" + lng : "")
});
});
return { kind: items.length === 1 ? "place" : (items.length ? "list" : "none"), items: items.slice(0, 20) };
}
// Directions, done by Gplex itself: the request Google's app makes for a route
// (www.google.com/maps/preview/directions), read into Gplex's own panel and drawn
// on Gplex's map. mode: 0 driving, 1 bicycling, 2 walking, 3 transit.
// (a function, not a const: this part of the script is reached before a const
// this far down would exist)
function ugfMapsDirPb() {
return "!6m61!1m5!18b1!30b1!31m1!1b1!34e1!2m4!5m1!6e2!20e3!39b1!6m32!32i1!49b1!63m0!66b1!85b1!114b1!149b1!206b1!209b1!212b1!215b1!216b1!222b1!223b1!232b1!234b1!235b1!246b1!253b1!260b1!262b1!266b1!270b1!271b1!273b1!277b1!280b1!281b1!291m0!294b1!302i300!303i100!10b1!12b1!13b1!14b1!16b1!17m1!3e1!20m5!1e0!2e3!5e2!6b1!14b1!46m1!1b0!96b1!99b1";
}
function ugfMapsPbText(s) {
return String(s).replace(/\*/g, "*2A").replace(/!/g, "*21");
}
function ugfMapsRoute(from, to, mode, v, size, done) {
if (window.location.host !== "www.google.com") {
done(null, "not on www.google.com");
return;
}
const w = Math.max(320, Math.round(size.w || 1024));
const h = Math.max(240, Math.round(size.h || 768));
const mpp = 156543.03392 * Math.cos(v.lat * Math.PI / 180) / Math.pow(2, v.z);
const pb = "!1m2!1s" + ugfMapsPbText(from) + "!6e0!1m2!1s" + ugfMapsPbText(to) + "!6e0" +
"!3m12!1m3!1d" + (mpp * h * 4.35).toFixed(2) + "!2d" + v.lng.toFixed(6) + "!3d" + v.lat.toFixed(6) +
"!2m3!1f0.0!2f0.0!3f0.0!3m2!1i" + w + "!2i" + h + "!4f13.1" +
ugfMapsDirPb().replace("!20m5!1e0!", "!20m5!1e" + (parseInt(mode, 10) || 0) + "!") + "!15m1!7e81";
const url = "/maps/preview/directions?authuser=0&hl=" + encodeURIComponent(ugfMapsLang()) + "&pb=" + encodeURIComponent(pb);
ugfMapsGetRoute(url, done);
}
// the reply for a directions request (ours, or the one Google's page asked for)
function ugfMapsGetRoute(url, done) {
ugfMapsGet(url, function(t, why) {
let res = null;
if (t !== null) {
try {
res = ugfMapsParseRoute(ugfMapsJson(t));
} catch (e) {
why = "unexpected reply (" + e.message + ")";
console.log("[Gplex] Maps: directions reply began: " + String(t).slice(0, 160));
}
}
if (!res) {
console.log("[Gplex] Maps: directions request failed (" + why + ")");
}
done(res, why);
});
}
function ugfMapsStripTags(s) {
return String(s || "").replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/'/g, "'")
.replace(/"/g, '"').replace(/\s+/g, " ").trim();
}
function ugfMapsParseRoute(d) {
const root = d && d[0];
if (!root) {
return { ok: false, routes: [] };
}
const pt = function(a) {
return Array.isArray(a) && typeof a[2] === "number" && typeof a[3] === "number" ? { lat: a[2], lng: a[3] } : null;
};
// the two ends, as Google understood them
const ends = [];
(Array.isArray(root[0]) ? root[0] : []).forEach(function(wp) {
let found = null;
const walk = function(a, depth) {
if (found || !Array.isArray(a) || depth > 6) {
return;
}
if (typeof a[0] === "string" && pt(a[2])) {
found = { name: a[0], lat: a[2][2], lng: a[2][3] };
return;
}
a.forEach(function(x) {
walk(x, depth + 1);
});
};
walk(wp, 0);
ends.push(found);
});
const lines = Array.isArray(root[7]) ? root[7] : [];
const routes = [];
(Array.isArray(root[1]) ? root[1] : []).forEach(function(r, ri) {
if (!Array.isArray(r) || !Array.isArray(r[0])) {
return;
}
// one route in a shape this does not know should not cost the others
try {
const s = r[0];
const steps = [];
const rides = [];
const isStep = function(a) {
return Array.isArray(a) && Array.isArray(a[2]) && ((Array.isArray(a[14]) && a[14].length && a[14].every(function(f) {
return Array.isArray(f) && Array.isArray(f[1]) && typeof f[1][0] === "string";
})) || (typeof a[1] === "string" && /^ 12) {
return;
}
// transit: a ride, with its line, where it heads, and where you get on and off
if (Array.isArray(a[5]) && Array.isArray(a[5][0]) && typeof a[5][0][0] === "string" &&
Array.isArray(a[5][1]) && typeof a[5][1][0] === "string") {
let line = "";
let kind = "";
let head = "";
let when = "";
// the heading is in pieces: 4 the vehicle, 5 the line, 7 where it heads
((a[0] && Array.isArray(a[0][14])) ? a[0][14] : []).forEach(function(f) {
if (!Array.isArray(f)) {
return;
}
const txt = Array.isArray(f[1]) && typeof f[1][0] === "string" ? f[1][0]
: (Array.isArray(f[2]) && typeof f[2][3] === "string" ? f[2][3] : "");
if (f[0] === 4) {
kind = txt;
} else if (f[0] === 5) {
line = txt;
} else if (f[0] === 7) {
head = txt;
}
});
line = (kind && kind !== line ? kind + " " : "") + line;
try {
when = String(a[0][3][1] || "");
} catch (e) {}
const tm = function(stop) {
const t = (Array.isArray(stop[3]) ? stop[3] : stop[2]) || [];
return typeof t[2] === "string" ? t[2].replace(/\u202f/g, " ") : "";
};
const on = a[5][0];
const off = a[5][1];
rides.push(line);
steps.push({
text: (line || "Transit") + (head ? " toward " + head : ""),
note: on[0] + (tm(on) ? " " + tm(on) : "") + " to " + off[0] + (tm(off) ? " " + tm(off) : "") +
(typeof a[5][2] === "number" ? " (" + a[5][2] + " stops)" : ""),
dist: "",
time: when,
at: pt(on[4]),
transit: true
});
return;
}
// a long route comes in sections: a summary line ("Get on I-95 N...")
// with the turns under it - the turns are what the list shows
if (isStep(a[0]) && Array.isArray(a[1]) && a[1].some(function(x) {
return Array.isArray(x) && isStep(x[0]);
})) {
walk(a[1], depth + 1);
return;
}
const frags = Array.isArray(a[14]) && a[14].length && a[14].every(function(f) {
return Array.isArray(f) && Array.isArray(f[1]) && typeof f[1][0] === "string";
}) ? a[14] : null;
if ((frags || (typeof a[1] === "string" && /^ 0, routes: routes, from: ends[0] || null, to: ends[ends.length - 1] || null };
}
// Where Google's own page put the view when it loaded: for an address with no
// position in it, that is the area Google places you in from your connection.
// ipOnly: only when the address itself gave no position.
function ugfMapsAppView(ipOnly) {
let st = null;
try {
const w = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
st = w.APP_INITIALIZATION_STATE;
} catch (e) {}
let v = null;
try {
if (st && Array.isArray(st[0]) && Array.isArray(st[0][0])) {
v = st[0][0];
} else {
[].some.call(document.scripts, function(sc) {
const m = /APP_INITIALIZATION_STATE\s*=\s*\[\[\[\s*([-\d.eE]+)\s*,\s*([-\d.eE]+)\s*,\s*([-\d.eE]+)/.exec(sc.textContent || "");
if (m) {
v = [parseFloat(m[1]), parseFloat(m[2]), parseFloat(m[3])];
return true;
}
return false;
});
}
} catch (e) {}
if (!v || !isFinite(v[0]) || !isFinite(v[1]) || !isFinite(v[2]) || v[0] <= 0) {
return null;
}
if (ugfMapsAppView.first === undefined) {
ugfMapsAppView.first = /@-?\d/.test(window.location.pathname) ? "url" : "ip";
}
if (ipOnly && ugfMapsAppView.first === "url") {
return null;
}
const lat = v[2];
const lng = v[1];
// the view is given as a distance across it; turn that back into a zoom
const z = Math.log(156543.03392 * Math.cos(lat * Math.PI / 180) * 768 * 4.35 / v[0]) / Math.LN2;
return { lat: lat, lng: lng, z: Math.max(3, Math.min(17, Math.round(z))) };
}
function ugfMapsToast(shell, text) {
let t = shell.querySelector("#ugf-maps-toast");
if (!t) {
t = document.createElement("div");
t.id = "ugf-maps-toast";
shell.appendChild(t);
}
t.textContent = text;
t.classList.add("on");
clearTimeout(ugfMapsToast.t);
ugfMapsToast.t = setTimeout(function() {
t.classList.remove("on");
}, 4000);
}
// ---- the page --------------------------------------------------------------
function ugfMapsEsc(s) {
return String(s === undefined || s === null ? "" : s).replace(/[&<>"']/g, function(c) {
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c];
});
}
function ugfMapsSearchUrl(q, v) {
return "https://www.google.com/maps/search/" + encodeURIComponent(q).replace(/%20/g, "+") +
"/@" + v.lat.toFixed(6) + "," + v.lng.toFixed(6) + "," + v.z + "z";
}
// A place as directions want it: its name and address when it has them (which
// reads well in the box and finds the right spot), otherwise its position
function ugfMapsDirLabel(item) {
if (!item) {
return "";
}
if (item.name && item.name !== "Dropped pin" && item.lines && item.lines[0]) {
return item.name + ", " + item.lines[0];
}
return item.lat.toFixed(6) + "," + item.lng.toFixed(6);
}
function ugfMapsDirUrl(item, from) {
const enc = function(t) {
return encodeURIComponent(t).replace(/%20/g, "+").replace(/%2C/g, ",");
};
const label = ugfMapsDirLabel(item);
return "https://www.google.com/maps/dir/" + (from ? enc(label) + "/" : "/" + enc(label));
}
function ugfMapsStreetUrl(lat, lng) {
return "https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=" + lat.toFixed(6) + "," + lng.toFixed(6);
}
// A Street View address, in any of its spellings:
// /maps/@lat,lng,3a,75y,210h,90t/data=!3m6!1e1!3m4!1s!2e0...
// /maps/@?api=1&map_action=pano&viewpoint=lat,lng&heading=&pitch=&pano=
// the old ?layer=c&cbll=lat,lng&cbp=12,heading,,zoom,pitch
function ugfMapsStreetFromUrl() {
const href = window.location.href;
let path = window.location.pathname || "";
try {
path = decodeURIComponent(path);
} catch (e) {}
const qs = window.location.search || "";
const q = function(k) {
const m = qs.match(new RegExp("[?&]" + k + "=([^&]*)"));
try {
return m ? decodeURIComponent(m[1]) : "";
} catch (e) {
return "";
}
};
const num = function(v, d) {
const n = parseFloat(v);
return isFinite(n) ? n : d;
};
let m = path.match(/@(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),[\d.]+a(?:,([\d.]+)y)?(?:,(-?[\d.]+)h)?(?:,(-?[\d.]+)t)?/);
if (m) {
// photos (!1e2), satellite (!1e3) and the like are not Street View
if (/!1e[02-9]\b/.test(href) && !/!1e1\b/.test(href)) {
return null;
}
const pano = (href.match(/!1s([\w-]{10,})!2e0/) || [])[1] || "";
return { lat: num(m[1], 0), lng: num(m[2], 0), heading: num(m[4], 0), pitch: m[5] ? num(m[5], 90) - 90 : 0, pano: pano };
}
if (/[?&]map_action=pano\b/.test(qs)) {
m = q("viewpoint").match(/(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)/);
if (!m && !q("pano")) {
return null;
}
return { lat: m ? num(m[1], 0) : 0, lng: m ? num(m[2], 0) : 0, heading: num(q("heading"), 0), pitch: num(q("pitch"), 0), pano: q("pano").replace(/[^\w-]/g, "") };
}
m = q("cbll").match(/(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)/);
if (m) {
const cbp = q("cbp").split(",");
return { lat: num(m[1], 0), lng: num(m[2], 0), heading: num(cbp[1], 0), pitch: -num(cbp[4], 0), pano: q("panoid").replace(/[^\w-]/g, "") };
}
return null;
}
// ---- Street View, inside Gplex --------------------------------------------------
// Google's own panorama viewer (the one Google hands out for embedding, keyless and
// on www.google.com itself) opens in the map, as Street View did from 2008 on:
// in the map pane beside the results on classic Maps, over the whole page from the
// new Maps of 2013. Its present-day overlays are taken off; the panorama, the
// arrows to walk along and Google's attribution stay.
function ugfMapsStreetEmbedUrl(lat, lng, at) {
at = at || {};
const f = function(n) {
return (Math.round((n || 0) * 100) / 100).toString();
};
const tail = "!2m2!1d" + lat.toFixed(6) + "!2d" + lng.toFixed(6) + "!3f" + f(at.heading) + "!4f" + f(at.pitch) + "!5f0.7820865974627469";
return "https://www.google.com/maps/embed?origin=mfe&pb=" + (at.pano
? "!6m8!1m7!1s" + at.pano + tail
: "!6m7!1m6" + tail);
}
function ugfMapsStreetView(shell, era, lat, lng, name, at) {
const modern = ["m2014", "m2015", "m2019", "m2022"].indexOf(era) > -1;
const old = shell.querySelector("#ugf-maps-sv");
if (old) {
old.remove();
}
const sv = document.createElement("div");
sv.id = "ugf-maps-sv";
sv.setAttribute("era", era);
const where = lat.toFixed(6) + ", " + lng.toFixed(6);
const title = name && name !== "Dropped pin" ? name : "Street View";
const bar = modern
? ''
: '';
sv.innerHTML = trusted_policy.createHTML(bar + '');
sv.querySelector(".t").textContent = title;
sv.querySelector(".c").textContent = where;
const frame = sv.querySelector("iframe");
frame.src = ugfMapsStreetEmbedUrl(lat, lng, at);
// take Google's present-day overlays off the viewer once it has drawn them
const hide = [".gm-iv-address", ".gm-iv-container", ".gm-fullscreen-control", ".gm-iv-profile-link",
'button[title="Keyboard shortcuts"]', 'button[aria-label="Keyboard shortcuts"]'];
if (era !== "m2019" && era !== "m2022") {
// the round compass and the dark zoom buttons came with the 2018 Maps
hide.push(".gm-bundled-control", ".gm-compass", ".gmnoprint.gm-bundled-control-on-bottom");
}
// where you are standing, as Google's viewer names it (it follows you as you walk)
const named = !!(name && name !== "Dropped pin");
const follow = function() {
try {
const d = frame.contentDocument;
const a = d && d.querySelector(".gm-iv-short-address-description");
const b = d && d.querySelector(".gm-iv-long-address-description");
const t1 = a ? a.textContent.trim() : "";
const t2 = b ? b.textContent.trim() : "";
if (t1 && !named) {
sv.querySelector(".t").textContent = t1;
sv.querySelector(".c").textContent = t2 || where;
} else if (t1 && named) {
sv.querySelector(".c").textContent = t1 + (t2 ? ", " + t2 : "");
}
} catch (e) {}
};
// the copyright line carries the period's year, as the map's own small print does
const year = ugfMapsYear();
let yearWatch = null;
const dateIt = function() {
try {
const d = frame.contentDocument;
if (!d || !d.body) {
return;
}
d.querySelectorAll(".gm-style-cc span, .gm-style-cc a, .gm-style-cc div").forEach(function(el) {
[].forEach.call(el.childNodes, function(n) {
if (n.nodeType === 3 && /\u00a9\s*(19|20)\d\d/.test(n.nodeValue)) {
const v = n.nodeValue.replace(/(\u00a9\s*)(19|20)\d\d/g, "$1" + year);
if (v !== n.nodeValue) {
n.nodeValue = v;
}
}
});
});
if (!yearWatch) {
yearWatch = new MutationObserver(dateIt);
yearWatch.observe(d.body, { childList: true, subtree: true, characterData: true });
}
} catch (e) {}
};
const walk = setInterval(function() {
if (!sv.isConnected) {
clearInterval(walk);
if (yearWatch) {
yearWatch.disconnect();
}
return;
}
follow();
dateIt();
}, 1000);
frame.addEventListener("load", dateIt);
// zoom, as the period's own buttons, working Google's (hidden) ones
const press = function(label) {
try {
const d = frame.contentDocument;
const bt = d && (d.querySelector('button[aria-label="' + label + '"]') || d.querySelector('button[title="' + label + '"]'));
if (bt) {
bt.click();
}
} catch (e) {}
};
if (modern && era !== "m2019" && era !== "m2022") {
const K = ugfMapsArt().kit;
const z = document.createElement("div");
z.className = "ugf-maps-ctl zoom15 svzoom";
z.innerHTML = trusted_policy.createHTML(' ');
z.querySelector(".zi").addEventListener("click", function() {
press("Zoom in");
});
z.querySelector(".zo").addEventListener("click", function() {
press("Zoom out");
});
sv.appendChild(z);
}
const dress = function() {
try {
const d = frame.contentDocument;
if (!d || !d.head || d.getElementById("ugf-sv-css")) {
return;
}
const st = d.createElement("style");
st.id = "ugf-sv-css";
st.textContent = hide.join(", ") + " { display: none !important; }";
d.head.appendChild(st);
} catch (e) {}
};
frame.addEventListener("load", dress);
let tries = 0;
const again = setInterval(function() {
dress();
if (++tries > 20 || !sv.isConnected) {
clearInterval(again);
}
}, 250);
const close = function(ev) {
if (ev) {
ev.preventDefault();
}
sv.remove();
document.removeEventListener("keydown", onKey, true);
// opened from a Street View address: the address becomes the map's again,
// so a reload comes back to the map
if (ugfMapsStreetFromUrl()) {
try {
history.replaceState(null, "", "/maps/@" + lat.toFixed(7) + "," + lng.toFixed(7) + ",17z");
} catch (e) {}
}
};
const onKey = function(ev) {
if (ev.key === "Escape") {
close(ev);
}
};
document.addEventListener("keydown", onKey, true);
sv.querySelector(".back").addEventListener("click", close);
(modern ? shell : (shell.querySelector("#ugf-maps-mapwrap") || shell)).appendChild(sv);
ugfMapsTranslate(sv);
return sv;
}
// Pegman: click him for Street View where the map is centred, or drag him onto the
// map and let go where you want to stand
function ugfMapsPegman(el, map, open) {
const A = ugfMapsArt();
let drag = null;
el.addEventListener("pointerdown", function(ev) {
if (ev.button !== 0) {
return;
}
ev.preventDefault();
ev.stopPropagation();
drag = { sx: ev.clientX, sy: ev.clientY, moved: false, ghost: null };
try {
el.setPointerCapture(ev.pointerId);
} catch (e) {}
});
el.addEventListener("pointermove", function(ev) {
if (!drag) {
return;
}
if (!drag.moved && Math.abs(ev.clientX - drag.sx) + Math.abs(ev.clientY - drag.sy) > 4) {
drag.moved = true;
const g = document.createElement("img");
g.src = A.pegfly;
g.alt = "";
g.id = "ugf-maps-pegfly";
document.documentElement.appendChild(g);
drag.ghost = g;
}
if (drag.ghost) {
// held by the head, feet where the pointer is
drag.ghost.style.left = (ev.clientX - 13) + "px";
drag.ghost.style.top = (ev.clientY - 33) + "px";
}
});
const end = function(ev) {
if (!drag) {
return;
}
const d = drag;
drag = null;
if (d.ghost) {
d.ghost.remove();
}
if (ev.type === "pointercancel") {
return;
}
if (!d.moved) {
const v = map.view();
open(v.lat, v.lng);
return;
}
const r = map.el.getBoundingClientRect();
const x = ev.clientX - r.left;
const y = ev.clientY - r.top;
if (x < 0 || y < 0 || x > r.width || y > r.height) {
return; // let go off the map: nothing happens, as on Maps
}
const ll = map.screenToLatLng(x, y);
open(ll.lat, ll.lng);
};
el.addEventListener("pointerup", end);
el.addEventListener("pointercancel", end);
el.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
});
el.style.touchAction = "none";
}
function ugfMapsScale(map) {
const mpp = map.metersPerPixel();
const us = /^en-(US|LR|MM)$/i.test(navigator.language || "") || /^en$/i.test(navigator.language || "");
const nice = function(max, units) {
for (let i = units.length - 1; i >= 0; i--) {
if (units[i][0] <= max) {
return units[i];
}
}
return units[0];
};
if (us) {
const ft = mpp * 3.28084 * 90;
const u = ft < 5280 ? nice(ft, [[10, "10 ft"], [20, "20 ft"], [50, "50 ft"], [100, "100 ft"], [200, "200 ft"], [500, "500 ft"], [1000, "1000 ft"], [2000, "2000 ft"]])
: nice(ft / 5280, [[0.5, "0.5 mi"], [1, "1 mi"], [2, "2 mi"], [5, "5 mi"], [10, "10 mi"], [20, "20 mi"], [50, "50 mi"], [100, "100 mi"], [200, "200 mi"], [500, "500 mi"], [1000, "1000 mi"], [2000, "2000 mi"]]);
const px = ft < 5280 ? u[0] / 3.28084 / mpp : u[0] * 1609.344 / mpp;
return { px: Math.round(px), label: u[1] };
}
const mm = mpp * 90;
const u = mm < 1000 ? nice(mm, [[5, "5 m"], [10, "10 m"], [20, "20 m"], [50, "50 m"], [100, "100 m"], [200, "200 m"], [500, "500 m"]])
: nice(mm / 1000, [[1, "1 km"], [2, "2 km"], [5, "5 km"], [10, "10 km"], [20, "20 km"], [50, "50 km"], [100, "100 km"], [200, "200 km"], [500, "500 km"], [1000, "1000 km"], [2000, "2000 km"]]);
const px = mm < 1000 ? u[0] / mpp : u[0] * 1000 / mpp;
return { px: Math.round(px), label: u[1] };
}
function ugfMapsIdentity() {
let name = "";
try {
name = typeof GM_getValue === "function" ? String(GM_getValue("UGF_USERNAME", "") || "") : "";
} catch (e) {}
const a = document.querySelector('a[aria-label*="@"]');
// the Maps page names the account too, the way Gmail's does
name = name || ugfGmailIdentity().name || "";
const signedIn = !!a || !!name;
return { name: name.split(" ")[0] || "", signedIn: signedIn };
}
// The Google bar, one per period, as Gplex draws it on google.com
function ugfMapsGbar(era) {
const who = ugfMapsIdentity();
const esc = ugfMapsEsc;
// late 2012 to 2013: the +You bar (bold links, +Name first, nothing on the right)
const lay = String(layout || "");
const plusBar = lay === "2013";
const dark = era === "m2011" || plusBar;
const apps = dark
? [["Search", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"], ["Maps", ""],
["Play", "https://play.google.com/"], ["YouTube", "https://www.youtube.com/"], ["News", "https://news.google.com/"],
["Gmail", "https://mail.google.com/"], [ugfDocsLabel(), "https://docs.google.com/document/"], ["Drive", "https://drive.google.com/"], ["Calendar", "https://calendar.google.com/"]].filter(ugfDvGbarKeep)
: [["Web", "https://www.google.com/"], ["Images", "https://www.google.com/imghp"],
[era === "m2010" ? "Videos" : "Video", "https://www.google.com/videohp"], ["Maps", ""],
["News", "https://news.google.com/"], ["Shopping", "https://www.google.com/shopping"],
["Gmail", "https://mail.google.com/"], [ugfDocsLabel(), "https://docs.google.com/document/"]].filter(ugfDvGbarKeep);
// Late 2012-2013 (layout 2013, not the legacy 2013L) is the +You bar: +Name leads
// the links, the current product is just the white highlight, and the right side
// is only the gear - the name / count / Share / photo block sits in the header.
const late = plusBar;
let links = late
? '+' + esc(ugfGmailPlusName()) + " "
: "";
apps.forEach(function(a) {
links += a[1] ? '' + esc(a[0]) + " " : '' + esc(a[0]) + " ";
});
links += '' +
(dark ? "More" : "more") + " ▾ ";
const right = late
? ""
: era === "m2011"
? (who.name ? '' + esc(who.name) + " " : 'Sign in ')
: 'iGoogle | ' +
'Search settings | ' +
(who.name ? '' + esc(who.name) + " " : 'Sign in ');
return '' +
'
' + links + '
' + right + "
";
}
// The header account block of the +You years, as Gplex draws it on Gmail and
// Search: +Name, the notification count, Share, then the photo with a caret.
// 2014 slots the app launcher in after the name. Signed out, it is Sign in.
function ugfMapsAccount(withApps) {
const esc = ugfMapsEsc;
const id = ugfGmailIdentity();
if (!id.name && !id.email && !ugfMapsIdentity().signedIn) {
return 'Sign in ';
}
return '';
}
function ugfMapsMain() {
const era = ugfMapsEra();
const A = ugfMapsArt();
const K = A.kit;
const esc = ugfMapsEsc;
const year = ugfMapsYear();
const url = ugfMapsParseUrl();
console.log("[Gplex] Maps: layout " + layout + " (" + era + ")" + (UGF_VERSION ? " - Gplex " + UGF_VERSION : ""));
const style = document.createElement("style");
style.id = "ugf-maps-styles";
style.textContent = ugfMapsCss();
(document.head || document.documentElement).appendChild(style);
document.documentElement.setAttribute("gplex-maps", era);
ugfMapsSetFavicon();
const shell = document.createElement("div");
shell.id = "ugf-maps";
shell.setAttribute("era", era);
const classic = ["m2005", "m2006", "m2007", "m2010", "m2011"].indexOf(era) > -1;
let searchVal = url.kind === "search" ? url.q : (url.kind === "place" ? url.name : "");
let html = "";
if (era === "m2005" || era === "m2006") {
html = '' +
'
' +
'
' +
'
' +
'Maps
' +
'';
} else if (era === "m2007" || era === "m2010" || era === "m2011") {
const logo = era === "m2007"
? ' '
: (era === "m2010" ? ' '
: ugfMapsHeadLogo());
const btn = era === "m2011"
? ' '
: ' ";
html = ugfMapsGbar(era) +
'' + logo + " " +
'
" +
(era === "m2011" && String(layout || "") === "2013" ? ugfMapsAccount(false) : "") + "
" +
'
' +
(era === "m2011" ? "" : '
') +
'
';
} else {
// 2014 onward: the map fills the window and everything floats on it
const newer = era === "m2019" || era === "m2022";
html = '' +
'" +
(newer ? '
' : "") +
'
' +
'' +
(era === "m2014" ? "" : '
') +
(era === "m2014" ? ugfMapsAccount(true)
// 2015 on: the account is the round photo, as on Search and Gmail
: ugfMapsIdentity().signedIn && (ugfGmailIdentity().name || ugfGmailIdentity().email)
? '
' + ugfGmailAvatar() + " "
: '
Sign in ') +
"
" +
'
';
}
shell.innerHTML = trusted_policy.createHTML(html);
document.body.appendChild(shell);
// ---- the map itself
let knownView = false;
let start = { lat: 39.5, lng: -98.35, z: era === "m2005" || era === "m2006" ? 3 : 4 };
try {
const saved = JSON.parse(localStorage.getItem("UGF_MAPS_VIEW") || "null");
if (saved && isFinite(saved.lat)) {
start = saved;
knownView = true;
}
} catch (e) {}
// no position in the address and none saved: start where Google itself
// placed you (it goes by your connection)
ugfMapsAppView.first = /@-?\d/.test(window.location.pathname) ? "url" : "ip";
if (url.lat === undefined && !knownView) {
const av = ugfMapsAppView(true);
if (av) {
start = av;
knownView = true;
}
}
if (url.lat !== undefined) {
start = { lat: url.lat, lng: url.lng, z: url.z };
}
const host = shell.querySelector("#ugf-maps-map");
const map = ugfMapsCreate(host, start);
map.setView(start.lat, start.lng, start.z);
if (!knownView && url.lat === undefined) {
// Google's page may still be on its way in: take its view when it lands,
// unless the map has been moved by then
let tries = 0;
const iv = setInterval(function() {
const cur = map.view();
if (++tries > 25 || Math.abs(cur.lat - start.lat) > 1e-4 || cur.z !== start.z) {
clearInterval(iv);
return;
}
const av = ugfMapsAppView(true);
if (av) {
clearInterval(iv);
map.setView(av.lat, av.lng, av.z);
}
}, 200);
}
ugfMapsControls(shell, map, era);
// a Street View address opens straight into Street View, the map waiting behind it
if (url.street) {
ugfMapsStreetView(shell, era, url.street.lat, url.street.lng, "", url.street);
}
// keep the address in step with the map, as Maps does, without disturbing
// whatever place or search the app below is showing
let urlTimer = 0;
map.onMove(function() {
clearTimeout(urlTimer);
urlTimer = setTimeout(function() {
const v = map.view();
const at = "@" + v.lat.toFixed(7) + "," + v.lng.toFixed(7) + "," + v.z + "z";
try {
localStorage.setItem("UGF_MAPS_VIEW", JSON.stringify({ lat: v.lat, lng: v.lng, z: v.z }));
} catch (e) {}
const p = window.location.pathname;
let next = /@[^/]*/.test(p) ? p.replace(/@[^/]*/, at)
: (/\/data=/.test(p) ? p.replace(/\/data=/, "/" + at + "/data=") : p.replace(/\/?$/, "/" + at));
if (!/^\/maps/.test(next)) {
next = "/maps/" + at;
}
try {
history.replaceState(history.state, "", next + (window.location.search || ""));
} catch (e) {}
}, 400);
});
// ---- results
const panel = shell.querySelector("#ugf-maps-panel");
const card = shell.querySelector("#ugf-maps-card");
let results = [];
let markers = [];
let iw = null;
const closeIw = function() {
if (iw) {
map.removeMarker(iw);
iw = null;
}
if (card) {
card.innerHTML = ugfTT("");
card.classList.remove("on");
}
};
const itemActions = function(it) {
return '";
};
const showItem = function(it, i) {
closeIw();
markers.forEach(function(mk, j) {
mk.el.classList.toggle("sel", j === i);
});
if (classic) {
// the info window: Google's own bubble, cut from its sprite
const el = document.createElement("div");
el.className = "ugf-maps-iw";
el.innerHTML = trusted_policy.createHTML('' +
'
' + esc(it.name) + "
" +
it.lines.map(function(l) {
return '
' + esc(l) + "
";
}).join("") + itemActions(it) + '
');
iw = map.addMarker({ lat: it.lat, lng: it.lng, el: el, ax: 38, ay: 200 });
el.querySelector(".x").addEventListener("click", closeIw);
// the anchor depends on how tall the bubble came out
requestAnimationFrame(function() {
iw.ay = el.offsetHeight + 85 + 32;
map.redraw();
});
} else if (card) {
const t = map.project(it.lat, it.lng, 17);
const n = Math.pow(2, 17);
const thumb = ugfMapsTileUrl("s", ((Math.floor(t.x / 256) % n) + n) % n, Math.floor(t.y / 256), 17);
card.innerHTML = trusted_policy.createHTML('
' +
'' + esc(it.name) + "
" +
(it.lines[0] ? '
' + esc(it.lines[0]) + "
" : "") +
'
' + it.lat.toFixed(6) + ", " + it.lng.toFixed(6) + "
" +
' ' +
' ');
card.classList.add("on");
card.querySelector(".x").addEventListener("click", closeIw);
card.querySelector(".thumb").title = "Street View";
card.querySelector(".thumb").addEventListener("click", function() {
ugfMapsStreetView(shell, era, it.lat, it.lng, it.name);
});
}
};
const markerFor = function(it, i) {
const el = document.createElement("img");
el.className = "ugf-maps-marker";
let ax = 10;
let ay = 34;
if (classic) {
el.src = i < 10 ? A["marker" + "ABCDEFGHIJ".charAt(i)] : A.marker;
} else {
el.src = A.spot;
ax = 11;
ay = 40;
}
el.alt = it.name;
el.title = it.name;
el.addEventListener("click", function(ev) {
ev.stopPropagation();
showItem(it, i);
});
return map.addMarker({ lat: it.lat, lng: it.lng, el: el, ax: ax, ay: ay });
};
const letter = function(i) {
return i < 10 ? "ABCDEFGHIJ".charAt(i) : "";
};
const renderPanel = function(state) {
if (!panel) {
return;
}
let h = "";
if (state === "searching") {
h = 'Searching…
';
} else if (state === "none") {
h = 'We could not find ' + esc(searchVal) + " .
" +
'Check the spelling, or try a different search.
';
} else if (results.length) {
if (classic) {
h = '' + (results.length === 1 ? "" : "Results 1-" + results.length) + "
";
}
results.forEach(function(it, i) {
h += '' +
(classic ? '
' : "") +
'
' + esc(it.name) + " " +
it.lines.map(function(l) {
return '
' + esc(l) + "
";
}).join("") +
(classic ? itemActions(it) : "") + "
";
});
} else if (era === "m2005" || era === "m2006") {
h = '' +
'Example searches
' +
'
Go to a location:
' +
'
' +
'
' +
'
Find a business:
' +
'
' +
'
' +
'
Get directions:
' +
'
' +
'
' +
'
Drag the map with your mouse, or double-click to center.
';
} else if (classic) {
h = '" +
'';
}
panel.innerHTML = trusted_policy.createHTML(h);
panel.classList.toggle("on", !!h);
panel.querySelectorAll(".res").forEach(function(r) {
r.addEventListener("click", function(ev) {
if (ev.target.closest(".acts a")) {
return;
}
ev.preventDefault();
const i = parseInt(r.getAttribute("data-i"), 10);
const it = results[i];
map.panTo(it.lat, it.lng);
showItem(it, i);
});
});
panel.querySelectorAll("form[data-q]").forEach(function(f) {
f.addEventListener("submit", function(ev) {
ev.preventDefault();
const q = f.querySelector("input").value;
if (f.getAttribute("data-dir")) {
const parts = q.split(/\s+to\s+/i);
openDir(parts[0], parts.slice(1).join(" to "), 0);
return;
}
runSearch(q);
});
});
panel.querySelectorAll("a[data-try]").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
runSearch(a.getAttribute("data-try"));
});
});
ugfMapsLinks(panel, map);
ugfMapsTranslate(shell);
};
const showResults = function(res) {
results = res.items || [];
markers.forEach(function(mk) {
map.removeMarker(mk);
});
markers = results.map(markerFor);
renderPanel(res.kind === "none" ? "none" : "list");
if (results.length) {
map.fit(results);
if (results.length === 1) {
showItem(results[0], 0);
}
}
};
const mapSize = function() {
return { w: host.clientWidth || window.innerWidth, h: host.clientHeight || window.innerHeight };
};
// Google's app below is the fallback: read whatever it comes up with
const harvest = function() {
ugfMapsHarvest(function(res) {
if (res.kind === "none" && url.pin) {
return; // the address already told us where it is
}
showResults(res);
});
};
let searchSeq = 0;
let pointer = null;
// A search typed here stays here: the list comes from Gplex's own request and
// the address bar is updated in place, so the page never reloads.
const runSearch = function(q, plain) {
q = String(q || "").trim();
if (!q) {
return;
}
// "seattle to 98109": directions, as Maps always read it
const trip = plain ? null : q.match(/^\s*(?:from\s+)?(.+?)\s+to\s+(.+?)\s*$/i);
if (trip && trip[1].length > 1 && trip[2].length > 1) {
openDir(trip[1], trip[2], 0, q);
return;
}
if (dir) {
dir = null;
dirSeq++;
clearDirMap();
showDirUi(false);
}
const seq = ++searchSeq;
const v = map.view();
searchVal = q;
shell.querySelector("#ugf-maps-q").value = q;
closeIw();
if (pointer) {
map.removeMarker(pointer);
pointer = null;
}
results = [];
markers.forEach(function(mk) {
map.removeMarker(mk);
});
markers = [];
renderPanel("searching");
try {
history.pushState({ ugfMaps: q }, "", ugfMapsSearchUrl(q, v).replace(/^https:\/\/www\.google\.com/, ""));
} catch (e) {}
ugfMapsFetch(q, v, mapSize(), function(res) {
if (seq !== searchSeq) {
return;
}
if (!res) {
window.location.href = ugfMapsSearchUrl(q, v);
return;
}
showResults(res);
});
};
// ---- directions: Gplex's own, from Google's route service, drawn on this map
const DIR_MODES = {
0: { icon: "directions_car", by: "By car", word: "Driving" },
3: { icon: "directions_transit", by: "By public transit", word: "Transit" },
2: { icon: "directions_walk", by: "Walking", word: "Walking" },
1: { icon: "directions_bike", by: "Bicycling", word: "Bicycling" }
};
// what each period offered: driving only at first, walking from 2008, then
// transit and cycling
const dirModes = era === "m2005" || era === "m2006" ? [0] : (era === "m2007" ? [0, 2] : [0, 3, 2, 1]);
let dir = null;
let dirSeq = 0;
let dirMarks = [];
const dirIcon = function(end) {
if (era === "m2005" || era === "m2006" || era === "m2007") {
return { src: end ? A.ddEnd : A.ddStart, ax: 10, ay: 34 };
}
if (classic) {
return { src: end ? A.greenB : A.greenA, ax: 10, ay: 34 };
}
return end ? { src: A.spot, ax: 11, ay: 40 } : { src: A.ddVia, ax: 5, ay: 5 };
};
const dirLine = function(sel, mode) {
if (classic) {
return sel ? [{ color: "#0000ff", width: 5, opacity: 0.5 }] : null;
}
const modern = era === "m2019" || era === "m2022";
const core = modern ? "#4285f4" : "#00b3fd";
const edge = modern ? "#1967d2" : "#0a7fc4";
if (!sel) {
return [{ color: "#8e9093", width: 9 }, { color: "#bcbfc2", width: 6 }];
}
if (mode === 2) {
return [{ color: core, width: 8, dash: "0 12" }]; // on foot: a line of dots
}
return [{ color: edge, width: 9 }, { color: core, width: 6 }];
};
const clearDirMap = function() {
map.setRoutes([]);
dirMarks.forEach(function(mk) {
map.removeMarker(mk);
});
dirMarks = [];
};
const drawDir = function() {
clearDirMap();
if (!dir || !dir.res || !dir.res.ok) {
return;
}
const list = [];
dir.res.routes.forEach(function(r, i) {
if (i === dir.sel) {
return;
}
const ly = dirLine(false, dir.mode);
if (ly) {
list.push({ pts: r.path, layers: ly, onclick: function() {
dir.sel = i;
dir.details = false;
drawDir();
renderDir();
} });
}
});
list.push({ pts: dir.res.routes[dir.sel].path, layers: dirLine(true, dir.mode) });
map.setRoutes(list);
[dir.res.from, dir.res.to].forEach(function(p, end) {
if (!p) {
return;
}
const ic = dirIcon(end === 1);
const el = document.createElement("img");
el.className = "ugf-maps-marker";
el.src = ic.src;
el.alt = p.name || "";
el.title = p.name || "";
dirMarks.push(map.addMarker({ lat: p.lat, lng: p.lng, el: el, ax: ic.ax, ay: ic.ay }));
});
};
const fitDir = function() {
const pts = dir && dir.res && dir.res.ok ? dir.res.routes[dir.sel].path : [];
if (!pts.length) {
return;
}
let a = { lat: 90, lng: 180 };
let b = { lat: -90, lng: -180 };
pts.forEach(function(p) {
a = { lat: Math.min(a.lat, p.lat), lng: Math.min(a.lng, p.lng) };
b = { lat: Math.max(b.lat, p.lat), lng: Math.max(b.lng, p.lng) };
});
map.fit([a, b], classic ? 40 : 80);
if (!classic && map.el.clientWidth > 900) {
// keep the route clear of the directions card on the left
const c = map.screenToLatLng(map.el.clientWidth / 2 - 200, map.el.clientHeight / 2);
map.setView(c.lat, c.lng, map.view().z);
}
};
// "Your location" (or "My location"): ask the browser where we are
const isHere = function(t) {
return /^\s*(your|my|current)\s+location\s*$/i.test(String(t || ""));
};
const resolvePlace = function(t, cb) {
if (!isHere(t)) {
cb(String(t || "").trim());
return;
}
try {
navigator.geolocation.getCurrentPosition(function(p) {
cb(p.coords.latitude.toFixed(6) + "," + p.coords.longitude.toFixed(6));
}, function() {
cb(null);
}, { timeout: 15000, maximumAge: 60000 });
} catch (e) {
cb(null);
}
};
const dirPath = function() {
const enc = function(t) {
return encodeURIComponent(t).replace(/%20/g, "+").replace(/%2C/g, ",");
};
const v = map.view();
return "/maps/dir/" + enc(dir.from) + "/" + enc(dir.to) + "/@" + v.lat.toFixed(7) + "," + v.lng.toFixed(7) + "," + v.z + "z" +
"/data=!4m2!4m1!3e" + dir.mode;
};
// the page's own directions request, when this page was opened as directions
let dirPreload = null;
if (url.kind === "dir") {
const ln = document.querySelector('link[href*="/maps/preview/directions"]');
dirPreload = ln ? ln.getAttribute("href") : null;
}
const dirKey = function() {
const enc = function(t) {
return encodeURIComponent(t).replace(/%20/g, "+").replace(/%2C/g, ",");
};
return "/maps/dir/" + enc(dir.from) + "/" + enc(dir.to) + "/data=!4m2!4m1!3e" + dir.mode;
};
const runDir = function(push) {
if (!dir) {
return;
}
dir.from = String(dir.from || "").trim();
dir.to = String(dir.to || "").trim();
if (!dir.from || !dir.to) {
dir.status = "form";
renderDir(true);
return;
}
const seq = ++dirSeq;
dir.status = "loading";
dir.res = null;
dir.sel = 0;
dir.details = false;
clearDirMap();
renderDir(false);
if (push !== false) {
try {
history.pushState({ ugfMaps: "dir" }, "", dirPath());
} catch (e) {}
}
resolvePlace(dir.from, function(f) {
resolvePlace(dir.to, function(t) {
if (seq !== dirSeq || !dir) {
return;
}
if (!f || !t) {
dir.status = "noloc";
renderDir(false);
return;
}
// the first run on a directions page uses the request Google's own
// page made for it; after that, Gplex asks itself
let pre = dirPreload;
dirPreload = null;
// only when it asked for the same way of travelling (with no mode in
// the address, Google's page asks for "best", which mixes them)
if (pre) {
let pm = null;
try {
pm = decodeURIComponent(pre).match(/!20m5!1e(\d+)!/);
} catch (e) {}
if (!pm || parseInt(pm[1], 10) !== dir.mode) {
pre = null;
}
}
const ask = pre ? function(f2, t2, m2, v2, sz2, cb) {
ugfMapsGetRoute(pre, function(r2, why2) {
if (r2) {
cb(r2, why2);
} else {
ugfMapsRoute(f2, t2, m2, v2, sz2, cb);
}
});
} : ugfMapsRoute;
ask(f, t, dir.mode, map.view(), mapSize(), function(res, why) {
if (seq !== dirSeq || !dir) {
return;
}
const tryKey = dirKey();
if (!res) {
// Gplex's own request did not get through: load the directions
// page itself once, and read the request Google's page makes
let tried = "";
try {
tried = sessionStorage.getItem("UGF_MAPS_DIRTRY") || "";
} catch (e) {}
if (tried !== tryKey && !isHere(dir.from) && !isHere(dir.to)) {
try {
sessionStorage.setItem("UGF_MAPS_DIRTRY", tryKey);
} catch (e) {}
window.location.href = "https://www.google.com" + tryKey;
return;
}
} else {
try {
sessionStorage.removeItem("UGF_MAPS_DIRTRY");
} catch (e) {}
}
dir.why = why || "";
if (res && !res.ok && dir.fallbackQ) {
// "pizza to go" is a search, not a trip
const q = dir.fallbackQ;
closeDir();
runSearch(q, true);
return;
}
dir.res = res;
dir.status = !res ? "error" : (res.ok ? "ok" : "none");
if (res && res.ok) {
drawDir();
fitDir();
}
renderDir(false);
});
});
});
};
const openDir = function(from, to, mode, fallbackQ, push) {
closeIw();
if (pointer) {
map.removeMarker(pointer);
pointer = null;
}
results = [];
markers.forEach(function(mk) {
map.removeMarker(mk);
});
markers = [];
mode = parseInt(mode, 10) || 0;
dir = {
from: from || "", to: to || "", mode: dirModes.indexOf(mode) > -1 ? mode : 0,
res: null, sel: 0, status: "form", details: false, fallbackQ: fallbackQ || ""
};
showDirUi(true);
if (dir.from && dir.to) {
runDir(push);
} else {
renderDir(true);
}
};
const closeDir = function() {
dir = null;
dirSeq++;
clearDirMap();
showDirUi(false);
renderPanel("idle");
const v = map.view();
try {
history.replaceState(null, "", "/maps/@" + v.lat.toFixed(7) + "," + v.lng.toFixed(7) + "," + v.z + "z");
} catch (e) {}
};
const showDirUi = function(on) {
const omni = shell.querySelector("#ugf-maps-omni");
if (!omni) {
return; // the older pages keep it all in the side panel
}
let box = omni.querySelector("#ugf-maps-dirbox");
if (on && !box) {
box = document.createElement("div");
box.id = "ugf-maps-dirbox";
omni.insertBefore(box, omni.firstChild);
}
if (!on && box) {
box.remove();
}
omni.classList.toggle("dir", !!on);
};
const icon = function(n) {
return '' + (A.mi[n] || "") + " ";
};
const dirStatus = function() {
if (!dir) {
return "";
}
if (dir.status === "loading") {
return 'Loading…
';
}
if (dir.status === "noloc") {
return 'Your location could not be determined.
' +
'Allow this page to use your location, or type a starting point.
';
}
if (dir.status === "error") {
return 'Directions could not be loaded right now.
Please try again.' +
(dir.why ? ' (' + esc(dir.why) + ") " : "") + "
";
}
if (dir.status === "none") {
return 'We could not calculate ' + (DIR_MODES[dir.mode].word.toLowerCase()) +
' directions between ' + esc(dir.from) + ' and ' + esc(dir.to) + " .
";
}
return "";
};
// the older pages: the form and the turn list in the side panel
const classicDir = function() {
const r = dir.res && dir.res.ok ? dir.res.routes[dir.sel] : null;
const old = era === "m2005" || era === "m2006";
let modeUi = "";
if (dirModes.length > 1) {
if (era === "m2011") {
modeUi = '";
} else {
modeUi = '' + dirModes.map(function(m) {
return '" + DIR_MODES[m].by + " ";
}).join("") + " ";
}
}
let h = '' +
'
" +
(era === "m2011" ? modeUi : "") +
'
' + (old ? '
Start address ' : '
') +
'
' +
'
' + (old ? '
End address ' : '
') +
'
' +
'
" +
'
' + (era === "m2011" ? "GET DIRECTIONS" : "Get Directions") + " " +
"
";
h += dirStatus();
if (r) {
h += '' + esc(DIR_MODES[dir.mode].word) + " directions to " +
'' + esc((dir.res.to && dir.res.to.name) || dir.to) + " " +
'
' + esc(r.dist) + (r.time ? " – about " + esc(r.time) : "") + (r.span ? " (" + esc(r.span) + ")" : "") + "
";
if (dir.res.routes.length > 1) {
h += '";
}
h += '' +
esc((dir.res.from && dir.res.from.name) || dir.from) + " " +
r.steps.map(function(st, i) {
return '' + (i + 1) + '. ' + esc(st.text) +
(st.note ? '' + esc(st.note) + "
" : "") + ' ' + esc(st.dist || st.time) + " ";
}).join("") +
'' +
esc((dir.res.to && dir.res.to.name) || dir.to) + "
" +
'These directions are for planning purposes only. You may find that construction projects, traffic, weather, or other events may cause conditions to differ from the map results, and you should plan your route accordingly.
';
}
return h;
};
// 2014 on: the fields up top in place of the search box, the routes under them
const modernBox = function() {
return '";
};
const modernList = function() {
let h = dirStatus();
if (dir.res && dir.res.ok) {
dir.res.routes.forEach(function(r, i) {
h += '' + icon(DIR_MODES[dir.mode].icon) +
'
";
if (i === dir.sel && dir.details) {
h += '' + r.steps.map(function(st, k) {
return '
' + esc(st.text) +
(st.note ? '
' + esc(st.note) + "
" : "") + '
' + esc(st.dist || st.time) + "
";
}).join("") + "
";
}
});
}
return h;
};
const renderDir = function(focus) {
if (!dir || !panel) {
return;
}
let box = null;
if (classic) {
panel.innerHTML = trusted_policy.createHTML(classicDir());
panel.classList.add("on");
box = panel;
} else {
box = shell.querySelector("#ugf-maps-dirbox");
box.innerHTML = trusted_policy.createHTML(modernBox());
const lh = modernList();
panel.innerHTML = trusted_policy.createHTML(lh);
panel.classList.toggle("on", !!lh);
}
const fIn = box.querySelector(".dfrom");
const tIn = box.querySelector(".dto");
const go = function() {
dir.from = fIn.value;
dir.to = tIn.value;
dir.fallbackQ = "";
runDir();
};
[fIn, tIn].forEach(function(inp) {
inp.addEventListener("input", function() {
dir.from = fIn.value;
dir.to = tIn.value;
});
inp.addEventListener("keydown", function(ev) {
if (ev.key === "Enter") {
ev.preventDefault();
go();
}
});
});
const gob = box.querySelector(".dgo");
if (gob) {
gob.addEventListener("click", go);
}
box.querySelector(".dclose").addEventListener("click", function(ev) {
ev.preventDefault();
closeDir();
});
box.querySelector(".dswap").addEventListener("click", function(ev) {
ev.preventDefault();
const f = fIn.value;
dir.from = tIn.value;
dir.to = f;
dir.fallbackQ = "";
runDir();
});
box.querySelectorAll(".dm").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
dir.from = fIn.value;
dir.to = tIn.value;
dir.mode = parseInt(a.getAttribute("data-mode"), 10) || 0;
runDir();
});
});
const sel = box.querySelector(".dsel");
if (sel) {
sel.addEventListener("change", function() {
dir.from = fIn.value;
dir.to = tIn.value;
dir.mode = parseInt(sel.value, 10) || 0;
runDir();
});
}
panel.querySelectorAll(".alt, .rt").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
const i = parseInt(a.getAttribute("data-i"), 10);
if (ev.target.closest(".det")) {
dir.details = !dir.details;
} else if (i !== dir.sel) {
dir.sel = i;
dir.details = false;
drawDir();
fitDir();
}
renderDir(false);
});
});
panel.querySelectorAll(".st").forEach(function(tr) {
tr.addEventListener("click", function() {
const st = dir.res.routes[dir.sel].steps[parseInt(tr.getAttribute("data-i"), 10)];
if (st && st.at) {
map.setView(st.at.lat, st.at.lng, Math.max(map.view().z, 16));
}
});
});
ugfMapsTranslate(shell);
if (focus) {
(fIn.value ? tIn : fIn).focus();
}
};
// back and forward: the page for that address, from the top
window.addEventListener("popstate", function(ev) {
if (ev.state && ev.state.ugfMaps !== undefined || /^\/maps/.test(window.location.pathname)) {
window.location.reload();
}
});
if (url.kind === "search" || url.kind === "place") {
renderPanel("searching");
if (url.pin) {
showResults({ kind: "place", items: [{ name: url.name || url.q, lat: url.pin.lat, lng: url.pin.lng, lines: [] }] });
}
const q0 = url.kind === "search" ? url.q : url.name;
const v0 = url.lat !== undefined ? { lat: url.lat, lng: url.lng, z: url.z } : map.view();
// with nowhere to search around yet (a first visit from a link like
// maps?q=pizza) Google's app does it, placing it by where you are
const nowhere = url.lat === undefined && !knownView;
(nowhere ? function(q, v, sz, cb) {
cb(null);
} : ugfMapsFetch)(q0, v0, mapSize(), function(res) {
if (!res) {
harvest();
return;
}
if (url.pin) {
// a place link: keep its own position, take the details of the match
let best = null;
let bestD = 1e9;
res.items.forEach(function(it) {
const d = Math.abs(it.lat - url.pin.lat) + Math.abs(it.lng - url.pin.lng);
if (d < bestD) {
bestD = d;
best = it;
}
});
if (best && bestD < 0.02) {
showResults({ kind: "place", items: [best] });
}
return;
}
showResults(res);
});
} else if (url.kind === "dir") {
renderPanel("idle");
dir = null;
setTimeout(function() {
openDir(url.from, url.to, url.mode, "", false);
}, 0);
} else {
renderPanel("idle");
}
// ---- search box, chips and clicks on the map
const form = shell.querySelector("#ugf-maps-form");
form.addEventListener("submit", function(ev) {
ev.preventDefault();
const q = String(shell.querySelector("#ugf-maps-q").value || "").trim();
if (q) {
runSearch(q);
}
});
shell.querySelectorAll("#ugf-maps-head .tabs a").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
if (a.getAttribute("data-tab") === "dir") {
openDir("", "", 0);
} else {
if (dir) {
closeDir();
}
shell.querySelector("#ugf-maps-q").focus();
}
});
});
const chips = shell.querySelector("#ugf-maps-chips");
if (chips) {
["Restaurants", "Hotels", "Things to do", "Transit", "Parking", "Pharmacies", "ATMs"].forEach(function(c) {
const b = document.createElement("button");
b.type = "button";
b.textContent = c;
b.addEventListener("click", function() {
runSearch(c);
});
chips.appendChild(b);
});
}
map.onClick(function(ll) {
if (dir && (!String(dir.from).trim() || !String(dir.to).trim())) {
const at = ll.lat.toFixed(6) + "," + ll.lng.toFixed(6);
if (!String(dir.from).trim()) {
dir.from = at;
} else {
dir.to = at;
}
runDir();
return;
}
if (classic) {
closeIw();
return;
}
// 2014 onward: a click drops the small grey pointer and says where it is
if (pointer) {
map.removeMarker(pointer);
pointer = null;
}
if (card && card.classList.contains("on")) {
closeIw();
return;
}
const el = document.createElement("img");
el.className = "ugf-maps-marker";
el.src = K.pointer;
pointer = map.addMarker({ lat: ll.lat, lng: ll.lng, el: el, ax: 10, ay: 10 });
showItem({ name: "Dropped pin", lat: ll.lat, lng: ll.lng, lines: [] }, -1);
});
// any other link to a Maps search on the page ("Search nearby" and the like)
// is run here too rather than reloading
shell.addEventListener("click", function(ev) {
const a = ev.target.closest && ev.target.closest("a[href]");
if (!a || ev.defaultPrevented || ev.button !== 0 || ev.ctrlKey || ev.metaKey || ev.shiftKey) {
return;
}
const hr = String(a.getAttribute("href"));
const dm = hr.match(/^https:\/\/www\.google\.com\/maps\/dir\/([^?#]*)/);
if (dm) {
ev.preventDefault();
const segs = dm[1].split("/").map(function(t) {
try {
return decodeURIComponent(t.replace(/\+/g, " "));
} catch (e) {
return t;
}
});
openDir(segs[0] || "", segs[1] || "", dir ? dir.mode : 0);
return;
}
const m = hr.match(/^https:\/\/www\.google\.com\/maps\/search\/([^/@?#]+)/);
if (m) {
ev.preventDefault();
runSearch(decodeURIComponent(m[1].replace(/\+/g, " ")));
}
});
// The account menu from the +You block (2013, 2014) or the photo (2015 on), and
// the app launcher from the nine dots (2014 on) - the same menus Gplex gives
// Gmail. The name on the older bars is a plain link to the Google Account page.
const menuChrome = era === "m2019" || era === "m2022" ? "m2018" : "m2013";
const burger = shell.querySelector("#ugf-maps-omni .menu");
if (burger) {
ugfMapsDrawer(shell, map, era, burger);
}
shell.querySelectorAll("#ugf-maps-account .pfpwrap, #ugf-maps-account .plusname, #ugf-maps-topright .me").forEach(function(el) {
el.style.cursor = "pointer";
el.addEventListener("click", function(ev) {
if (ev.button !== 0 || ev.ctrlKey || ev.metaKey || ev.shiftKey) {
return;
}
ev.preventDefault();
ev.stopPropagation();
ugfGmailAccountMenu(el, menuChrome);
});
});
shell.querySelectorAll("#ugf-maps-account .ic.grid, #ugf-maps-topright .apps").forEach(function(el) {
el.addEventListener("click", function(ev) {
if (ev.button !== 0 || ev.ctrlKey || ev.metaKey || ev.shiftKey) {
return;
}
ev.preventDefault();
ev.stopPropagation();
ugfGmailAppsMenu(el, menuChrome);
});
});
ugfMapsLinks(shell, map);
ugfMapsTranslate(shell);
}
// The side menu behind the three lines (2015 on): the map layers at the top, then
// your places and sharing, then the help and settings links - each period's own
// set and wording. Layers switch here; the rest go where Maps sent them.
function ugfMapsDrawer(shell, map, era, burger) {
const A = ugfMapsArt();
const esc = ugfMapsEsc;
const l = String(layout || "");
// late 2015 keeps 2015's menu, but under the new logo of September 2015
const v2015 = l === "2015" || UGF_LATE2015 || (UGF_EARLY2016 && l === "2016");
const v2022 = era === "m2022";
const icon = function(n) {
return '' + (A.mi[n] || "") + " ";
};
const here = function() {
const v = map.view();
return { lat: v.lat.toFixed(6), lng: v.lng.toFixed(6), z: v.z };
};
const earthUrl = function() {
const h = here();
const alt = Math.round(156543.03392 * Math.cos(h.lat * Math.PI / 180) / Math.pow(2, h.z) * 800);
return "https://earth.google.com/web/@" + h.lat + "," + h.lng + "," + alt + "a,0d";
};
// [label, icon, action] - action is a layer, a function name or a link
const layers = v2022 ? [] : [
["Satellite", "satellite", "type:y"],
["Traffic", "traffic", "ov:traffic"],
[v2015 ? "Public transit" : "Transit", "directions_bus", "ov:transit"],
[v2015 ? "Bicycling" : "Biking", "directions_bike", "ov:bike"],
["Terrain", "terrain", "type:p"],
["Google Earth", "public", "earth"]
];
const yours = (v2022 ? [["Saved", "bookmark", "https://www.google.com/maps/saved"]] : [["Your places", "place", "https://www.google.com/maps/saved"]])
.concat([["Your contributions", "rate_review", "https://www.google.com/maps/contrib/"]])
.concat(era === "m2019" || v2022 ? [["Location sharing", "people", "https://www.google.com/maps?gplex=false"]] : [])
.concat(v2015 ? [] : [["Your timeline", "timeline", "https://timeline.google.com/"]])
.concat([["Share or embed map", "link", "share"], ["Print", "print", "print"]]);
const edit = [["Add a missing place", "", "https://support.google.com/maps/answer/6320846"]]
.concat(v2015 ? [] : [["Add your business", "", "https://business.google.com/"]])
.concat([["Edit the map", "", "https://support.google.com/maps/answer/3094088"]]);
const help = [["Tips and tricks", "", "https://www.google.com/maps/about/"],
[v2015 ? "Help" : "Get help", "", "https://support.google.com/maps"]]
.concat(v2015 ? [["Send feedback", "", "https://support.google.com/maps/answer/3094045"]] : [["Consumer information", "", "https://support.google.com/maps/answer/9057034"]]);
const prefs = [["Language", "", "https://myaccount.google.com/language"],
["Search settings", "", "https://www.google.com/gplex"],
[era === "m2015" && l !== "2018" && l !== "2018M" ? "History" : "Maps activity", "", "https://myactivity.google.com/product/maps"]];
const logo = v2015 && !UGF_LATE2015 && !(UGF_EARLY2016 && l === "2016")
? ' '
: ' ';
const scrim = document.createElement("div");
scrim.id = "ugf-maps-scrim";
const box = document.createElement("div");
box.id = "ugf-maps-drawer";
box.setAttribute("era", era);
shell.appendChild(scrim);
shell.appendChild(box);
const row = function(r) {
const act = r[2];
const isLink = /^https?:/.test(act);
return '' +
(r[1] ? icon(r[1]) : "") + '' + esc(r[0]) + " ";
};
const group = function(rows) {
return rows.length ? '' + rows.map(row).join("") + "
" : "";
};
const paint = function() {
const v = map.view();
box.innerHTML = trusted_policy.createHTML('' + logo + ' Maps
' +
'' + group(layers) + group(yours) + group(edit) + group(help) + group(prefs) + "
");
box.querySelectorAll(".row").forEach(function(a) {
const act = a.getAttribute("data-act");
const on = (act === "type:" + v.type) || (act === "ov:" + map.overlay());
a.classList.toggle("on", on);
});
};
const open = function() {
paint();
shell.classList.add("drawer-open");
};
const close = function() {
shell.classList.remove("drawer-open");
};
burger.addEventListener("click", function(ev) {
ev.preventDefault();
ev.stopPropagation();
if (shell.classList.contains("drawer-open")) {
close();
} else {
open();
}
});
scrim.addEventListener("click", close);
document.addEventListener("keydown", function(ev) {
if (ev.key === "Escape") {
close();
}
});
box.addEventListener("click", function(ev) {
const a = ev.target.closest && ev.target.closest(".row");
if (!a) {
return;
}
const act = a.getAttribute("data-act");
if (/^https?:/.test(act)) {
return; // an ordinary link
}
ev.preventDefault();
const v = map.view();
if (act.indexOf("type:") === 0) {
const t = act.slice(5);
map.setType(v.type === t ? "m" : t);
paint();
return; // the menu stays open, so a second layer can be picked
}
if (act.indexOf("ov:") === 0) {
const o = act.slice(3);
map.setOverlay(map.overlay() === o ? "" : o);
paint();
return;
}
close();
if (act === "earth") {
window.open(earthUrl(), "_blank");
} else if (act === "print") {
setTimeout(function() {
window.print();
}, 50);
} else if (act === "share") {
const h = here();
try {
window.prompt("Link to share", "https://www.google.com/maps/@" + h.lat + "," + h.lng + "," + h.z + "z");
} catch (e) {}
}
});
}
// Print / Send / Link on the older pages
function ugfMapsLinks(root, map) {
root.querySelectorAll("a[data-link]").forEach(function(a) {
if (a._wired) {
return;
}
a._wired = true;
a.addEventListener("click", function(ev) {
ev.preventDefault();
const what = a.getAttribute("data-link");
const v = map.view();
const link = "https://www.google.com/maps/@" + v.lat.toFixed(6) + "," + v.lng.toFixed(6) + "," + v.z + "z";
if (what === "print") {
window.print();
} else if (what === "send" || what === "email") {
window.location.href = "mailto:?subject=" + encodeURIComponent("Google Maps") + "&body=" + encodeURIComponent(link);
} else {
try {
window.prompt("Paste link in email or IM", link);
} catch (e) {}
}
});
});
}
// Gplex's own words in the interface language; search results stay as Google wrote them
function ugfMapsTranslate(root) {
try {
if (typeof ugfI18nTree === "function" && UGF_LANG !== "en") {
ugfI18nTree(root);
}
} catch (e) {}
}
// ---- controls, per period ---------------------------------------------------
function ugfMapsControls(shell, map, era) {
const A = ugfMapsArt();
const K = A.kit;
const wrap = shell.querySelector("#ugf-maps-mapwrap");
const add = function(cls, html) {
const d = document.createElement("div");
d.className = "ugf-maps-ctl " + cls;
d.innerHTML = trusted_policy.createHTML(html);
wrap.appendChild(d);
return d;
};
const street = function(lat, lng) {
ugfMapsStreetView(shell, era, lat, lng, "");
};
const knobSync = [];
map.onMove(function() {
knobSync.forEach(function(fn) {
fn();
});
});
// 2005-2010: the large pan/zoom control, with its slider
const slider = function(ctl, rail, knob, top, per, levels) {
const sync = function() {
const z = map.view().z;
const i = Math.max(0, Math.min(levels - 1, levels - 1 - (z - 2)));
knob.style.top = (top + i * per) + "px";
};
knobSync.push(sync);
rail.addEventListener("click", function(ev) {
const r = rail.getBoundingClientRect();
const i = Math.floor((ev.clientY - r.top) / per);
map.zoomTo(2 + (levels - 1 - i));
});
sync();
};
if (era === "m2005" || era === "m2006") {
const levels = 18;
const c = add("large2005",
' ' +
' ');
c.querySelector(".up").onclick = function() { map.panBy(0, -Math.round(map.el.clientHeight / 2)); };
c.querySelector(".dn").onclick = function() { map.panBy(0, Math.round(map.el.clientHeight / 2)); };
c.querySelector(".lf").onclick = function() { map.panBy(-Math.round(map.el.clientWidth / 2), 0); };
c.querySelector(".rt").onclick = function() { map.panBy(Math.round(map.el.clientWidth / 2), 0); };
c.querySelector(".ct").onclick = function() { const v = map.view(); map.setView(v.lat, v.lng, v.z); };
c.querySelector(".zi").onclick = map.zoomIn;
c.querySelector(".zo").onclick = map.zoomOut;
slider(c, c.querySelector(".rail"), c.querySelector(".knob"), 84, 8, levels);
} else if (era === "m2007") {
const levels = 20;
const c = add("large2008",
' ' +
' ');
c.querySelector(".up").onclick = function() { map.panBy(0, -200); };
c.querySelector(".dn").onclick = function() { map.panBy(0, 200); };
c.querySelector(".lf").onclick = function() { map.panBy(-200, 0); };
c.querySelector(".rt").onclick = function() { map.panBy(200, 0); };
c.querySelector(".zi").onclick = map.zoomIn;
c.querySelector(".zo").onclick = map.zoomOut;
ugfMapsPegman(c.querySelector(".peg"), map, street);
slider(c, c.querySelector(".rail"), c.querySelector(".knob"), 118, 8, levels);
} else if (era === "m2010" || era === "m2011") {
const levels = 20;
const c = add("large2010",
' ' +
' ');
c.querySelector(".up").onclick = function() { map.panBy(0, -200); };
c.querySelector(".dn").onclick = function() { map.panBy(0, 200); };
c.querySelector(".lf").onclick = function() { map.panBy(-200, 0); };
c.querySelector(".rt").onclick = function() { map.panBy(200, 0); };
c.querySelector(".zi").onclick = map.zoomIn;
c.querySelector(".zo").onclick = map.zoomOut;
ugfMapsPegman(c.querySelector(".peg"), map, street);
slider(c, c.querySelector(".rail"), c.querySelector(".knob"), 116, 8, levels);
}
// map types
if (era === "m2005" || era === "m2006" || era === "m2007" || era === "m2010") {
const types = era === "m2005" || era === "m2006" ? [["m", "Map"], ["s", "Satellite"], ["y", "Hybrid"]]
: (era === "m2007" ? [["m", "Map"], ["y", "Satellite"], ["p", "Terrain"]] : [["m", "Map"], ["y", "Satellite"], ["p", "Terrain"]]);
const t = add("types " + (era === "m2010" ? "v3" : "v2"), types.map(function(x) {
return '" + x[1] + " ";
}).join(""));
t.querySelectorAll("a").forEach(function(a) {
a.addEventListener("click", function(ev) {
ev.preventDefault();
map.setType(a.getAttribute("data-t"));
t.querySelectorAll("a").forEach(function(o) {
o.classList.toggle("on", o === a);
});
});
});
} else if (era === "m2011" || era === "m2014") {
// the imagery thumbnail: a real satellite tile of where you are
const t = add(era === "m2011" ? "thumb11" : "thumb14", '' + (era === "m2011" ? "Satellite" : "Earth") + " ");
const paint = function() {
const v = map.view();
const on = v.type !== "m";
const zz = Math.max(2, v.z - 2);
const p = map.project(v.lat, v.lng, zz);
const n = Math.pow(2, zz);
t.querySelector(".img").style.backgroundImage = 'url("' +
ugfMapsTileUrl(on ? "m" : "s", ((Math.floor(p.x / 256) % n) + n) % n, Math.floor(p.y / 256), zz) + '")';
t.querySelector(".lbl").textContent = on ? "Map" : (era === "m2011" ? "Satellite" : "Earth");
};
let pt = 0;
map.onMove(function() {
clearTimeout(pt);
pt = setTimeout(paint, 300);
});
t.addEventListener("click", function() {
map.setType(map.view().type === "m" ? "y" : "m");
paint();
});
paint();
}
if (era === "m2014" || era === "m2015" || era === "m2019" || era === "m2022") {
// bottom right: my location, zoom, and (2015-2018) the imagery strip with Pegman
const loc = add("loc15", ' ');
loc.title = "Your location";
// Your location: the browser's position, marked with Maps' blue dot; if the
// browser will not say, the rough area Google placed you in
let dot = null;
loc.addEventListener("click", function() {
const put = function(lat, lng, z, exact) {
if (dot) {
map.removeMarker(dot);
dot = null;
}
if (exact) {
const el = document.createElement("img");
el.className = "ugf-maps-marker ugf-maps-me";
el.src = A.bluedot;
el.alt = "Your location";
el.title = "Your location";
dot = map.addMarker({ lat: lat, lng: lng, el: el, ax: 11, ay: 11 });
}
map.setView(lat, lng, z);
};
const rough = function() {
const v = ugfMapsAppView(true);
if (v) {
put(v.lat, v.lng, Math.min(v.z, 12), false);
}
ugfMapsToast(shell, "Your location could not be determined.");
};
try {
navigator.geolocation.getCurrentPosition(function(p) {
put(p.coords.latitude, p.coords.longitude, Math.max(map.view().z, 15), true);
}, rough, { timeout: 15000, maximumAge: 60000 });
} catch (e) {
rough();
}
});
const z = add("zoom15", ' ');
z.querySelector(".zi").onclick = map.zoomIn;
z.querySelector(".zo").onclick = map.zoomOut;
if (era === "m2015") {
const im = add("imagery15", ' ');
ugfMapsPegman(im.querySelector(".peg"), map, street);
im.querySelector(".more").onclick = function() {
map.setType(map.view().type === "m" ? "y" : "m");
};
} else {
const pg = add("peg14", ' ');
pg.title = "Street View";
ugfMapsPegman(pg, map, street);
}
if (era === "m2019" || era === "m2022") {
const t = add("layers19", 'Layers ');
const paint = function() {
const v = map.view();
const zz = Math.max(2, v.z - 1);
const p = map.project(v.lat, v.lng, zz);
const n = Math.pow(2, zz);
t.querySelector(".img").style.backgroundImage = 'url("' +
ugfMapsTileUrl(v.type === "m" ? "s" : "m", ((Math.floor(p.x / 256) % n) + n) % n, Math.floor(p.y / 256), zz) + '")';
};
let pt = 0;
map.onMove(function() {
clearTimeout(pt);
pt = setTimeout(paint, 300);
});
t.addEventListener("click", function() {
map.setType(map.view().type === "m" ? "y" : "m");
paint();
});
paint();
}
}
// the Google mark and the small print, as each period set them on the map
const y = ugfMapsYear();
const foot = add("foot " + era, "");
const scaleBar = function() {
const s = ugfMapsScale(map);
return '' + s.label + ' ';
};
const paintFoot = function() {
let h = "";
if (era === "m2005" || era === "m2006") {
h = '©' + y + " Google " + scaleBar() + 'Map data ©' + y + " NAVTEQ™, TeleAtlas ";
} else if (era === "m2007") {
h = ' ' + scaleBar() +
'Map data ©' + y + ' Google - Terms of Use ';
} else if (era === "m2010" || era === "m2011") {
h = ' ' + scaleBar() +
'Map data ©' + y + ' Google - Terms of Use ';
} else {
// 2014 on: the mark sits at the bottom middle; the small print at the right
h = ' ' +
'Map data ©' + y + ' Google Terms ' +
'Privacy ' +
(era === "m2019" || era === "m2022" ? "Send Product Feedback" : "Send feedback") + " " + scaleBar() + " ";
}
foot.innerHTML = trusted_policy.createHTML(h);
};
let ft = 0;
map.onMove(function() {
clearTimeout(ft);
ft = setTimeout(paintFoot, 150);
});
paintFoot();
}
// The account and app menus are Gmail's own, so their look is taken from the Gmail
// stylesheet rather than kept twice.
function ugfMapsMenuCss() {
const g = ugfGmailCss();
const cut = function(from, to) {
const i = g.indexOf(from);
const j = i > -1 ? g.indexOf(to, i + from.length) : -1;
return i > -1 && j > -1 ? g.slice(i, j) : "";
};
return cut("/* ---------- account dropdown ---------- */", "/* ----------") + "\n" +
cut("#ugf-gmail-appsmenu {", "/* late 2012-2013");
}
function ugfMapsCss() {
const A = ugfMapsArt();
const u = function(k) {
return 'url("' + A[k] + '")';
};
return [
// Google's own app stays in place, hidden, so it can keep doing the searching
'html[gplex-maps] body > *:not(#ugf-maps):not(#ugf-maps-gbarwrap):not(#ugf-maps-styles):not(#ugf-gmail-accmenu):not(#ugf-gmail-appsmenu):not(#ugf-gmail-accfence):not(script):not(style) { visibility: hidden !important; pointer-events: none !important; }',
// the account menu (shared with Gmail) opens above the Maps page
'html[gplex-maps] #ugf-gmail-accfence { z-index: 2147483600 !important; }',
'html[gplex-maps] #ugf-gmail-accmenu { z-index: 2147483601 !important; text-align: left; }',
'html[gplex-maps] #ugf-gmail-appsmenu { z-index: 2147483601 !important; text-align: left; }',
'html[gplex-maps] #ugf-gmail-accmenu a, html[gplex-maps] #ugf-gmail-appsmenu a { text-decoration: none; }',
ugfMapsMenuCss(),
// the name on the Google bar goes to the Google Account page, as on Search and Gmail
'#ugf-maps-gbar a.who { color: #00c !important; font-weight: bold; text-decoration: none !important; }',
'#ugf-maps-gbar.dark a.who { color: #fff !important; }',
'#ugf-maps-gbar a.who:hover { text-decoration: underline !important; }',
// 2015 on: the round photo at the top right
'#ugf-maps-topright .me { display: block; width: 32px; height: 32px; border-radius: 50%; cursor: pointer; box-shadow: 0 1px 4px rgba(0,0,0,.3); }',
'#ugf-maps-topright .me .pfp { display: block; width: 32px; height: 32px; border-radius: 50%; object-fit: cover; }',
'#ugf-maps-topright .me .pfp.letter { background: #c62828; color: #fff; font: 16px Roboto, arial, sans-serif; display: flex; align-items: center; justify-content: center; text-transform: uppercase; }',
'#ugf-maps-topright .apps { cursor: pointer; }',
'#ugf-maps-account .ic.grid { cursor: pointer; }',
// routes and the blue dot
'.ugf-maps-route { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; will-change: transform; }',
'.ugf-maps-route path.hit { pointer-events: visibleStroke; cursor: pointer; }',
'#ugf-maps-toast { position: absolute; left: 50%; bottom: 40px; transform: translateX(-50%); background: #323232; color: #fff; font: 13px Roboto, arial, sans-serif; padding: 10px 18px; border-radius: 2px; z-index: 60; opacity: 0; pointer-events: none; transition: opacity .2s; }',
'#ugf-maps-toast.on { opacity: 1; }',
// directions, the older pages
'#ugf-maps-panel .dirf { margin: 0 0 10px 0; }',
'#ugf-maps-panel .dhd { display: flex; justify-content: space-between; align-items: baseline; margin: 0 0 8px 0; font-size: 13px; }',
'#ugf-maps-panel .dhd a { font-size: 12px; }',
'#ugf-maps-panel .drow { display: flex; align-items: center; gap: 6px; margin: 0 0 5px 0; }',
'#ugf-maps-panel .drow img { width: 20px; height: 34px; flex: 0 0 20px; }',
'#ugf-maps-panel .drow .dl { width: 84px; flex: 0 0 84px; font-size: 12px; }',
'#ugf-maps-panel .drow input { flex: 1; min-width: 0; font: 13px arial, sans-serif; border: 1px solid #7f9db9; padding: 2px 3px; }',
'#ugf-maps[era="m2011"] #ugf-maps-panel .drow input { border: 1px solid #d9d9d9; border-top-color: #c0c0c0; padding: 5px 6px; }',
'#ugf-maps-panel .dbar { display: flex; align-items: center; gap: 10px; margin: 4px 0 8px 26px; font-size: 12px; }',
'#ugf-maps-panel .dsel { font: 12px arial, sans-serif; }',
'#ugf-maps-panel .dgo { font: 13px arial, sans-serif; margin-left: 26px; }',
'#ugf-maps-panel .dgo.blue { font: bold 11px arial, sans-serif; color: #fff; background: linear-gradient(#4d90fe, #4787ed); border: 1px solid #3079ed; border-radius: 2px; padding: 6px 12px; cursor: pointer; }',
'#ugf-maps-panel .dmodes { display: flex; gap: 0; margin: 0 0 8px 26px; }',
'#ugf-maps-panel .dmodes .dm { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 27px; border: 1px solid #dcdcdc; background: linear-gradient(#f5f5f5, #f1f1f1); margin-right: -1px; }',
'#ugf-maps-panel .dmodes .dm.on { background: #eee; box-shadow: inset 0 1px 2px rgba(0,0,0,.2); border-color: #ccc; }',
'#ugf-maps-panel .dmodes .dm svg { width: 18px; height: 18px; fill: #666; display: block; }',
'#ugf-maps-panel .dmodes .dm.on svg { fill: #333; }',
'#ugf-maps-panel .dsum { margin: 12px 0 8px 0; }',
'#ugf-maps-panel .dtot { color: #333; margin-top: 3px; }',
'#ugf-maps-panel .dalts { margin: 0 0 10px 0; }',
'#ugf-maps-panel .dah { font-weight: bold; font-size: 12px; margin-bottom: 3px; color: #333; }',
'#ugf-maps-panel .alt { display: flex; justify-content: space-between; gap: 8px; padding: 4px 6px; text-decoration: none; font-size: 12px; }',
'#ugf-maps-panel .alt.sel { background: #e5ecf9; color: #000 !important; }',
'#ugf-maps-panel .alt .m { color: #666; white-space: nowrap; }',
'#ugf-maps-panel .dsteps { border-collapse: collapse; width: 100%; font-size: 12px; }',
'#ugf-maps-panel .dsteps td { padding: 5px 4px; border-top: 1px solid #e5e5e5; vertical-align: top; }',
'#ugf-maps-panel .dsteps tr.end td { background: #f3f3f3; font-weight: bold; vertical-align: middle; }',
'#ugf-maps-panel .dsteps tr.end img { display: block; }',
'#ugf-maps-panel .dsteps tr.st { cursor: pointer; }',
'#ugf-maps-panel .dsteps tr.st:hover td { background: #f5f8fe; }',
'#ugf-maps-panel .dsteps .n { width: 22px; text-align: right; color: #333; }',
'#ugf-maps-panel .dsteps .dd { white-space: nowrap; text-align: right; color: #666; }',
'#ugf-maps-panel .note { color: #777; font-size: 11px; margin-top: 2px; }',
'#ugf-maps-panel .dnote { color: #777; font-size: 11px; margin: 10px 0; line-height: 1.4; }',
// directions, 2014 on
'#ugf-maps-omni.dir #ugf-maps-form, #ugf-maps-omni.dir #ugf-maps-chips { display: none !important; }',
'#ugf-maps-dirbox { background: #fff; box-shadow: 0 2px 4px rgba(0,0,0,.2); border-radius: 2px 2px 0 0; font: 13px Roboto, arial, sans-serif; }',
'#ugf-maps[era="m2015"] #ugf-maps-dirbox { background: #4285f4; }',
'#ugf-maps-dirbox .dhead { padding: 8px 12px 12px 12px; }',
'#ugf-maps-dirbox .dmodes { display: flex; align-items: center; gap: 6px; margin: 0 0 8px 40px; }',
'#ugf-maps-dirbox .dm { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 32px; border-radius: 16px; }',
'#ugf-maps-dirbox .dm svg, #ugf-maps-dirbox .dclose svg, #ugf-maps-dirbox .dswap svg { display: block; fill: #757575; }',
'#ugf-maps-dirbox .dm.on { background: #e8f0fe; } #ugf-maps-dirbox .dm.on svg { fill: #1a73e8; }',
'#ugf-maps[era="m2015"] #ugf-maps-dirbox .dm svg, #ugf-maps[era="m2015"] #ugf-maps-dirbox .dclose svg, #ugf-maps[era="m2015"] #ugf-maps-dirbox .dswap svg { fill: rgba(255,255,255,.7); }',
'#ugf-maps[era="m2015"] #ugf-maps-dirbox .dm.on { background: rgba(0,0,0,.15); } #ugf-maps[era="m2015"] #ugf-maps-dirbox .dm.on svg { fill: #fff; }',
'#ugf-maps-dirbox .dclose { margin-left: auto; display: block; }',
'#ugf-maps-dirbox .dflds { position: relative; padding-right: 36px; }',
'#ugf-maps-dirbox .dfld { display: flex; align-items: center; height: 36px; }',
'#ugf-maps-dirbox .dot { display: block; width: 8px; height: 8px; border-radius: 50%; border: 2px solid #757575; margin: 0 20px 0 14px; flex: 0 0 auto; }',
'#ugf-maps-dirbox .dot.b { border-color: #db4437; background: #db4437; }',
'#ugf-maps[era="m2015"] #ugf-maps-dirbox .dot { border-color: #fff; } #ugf-maps[era="m2015"] #ugf-maps-dirbox .dot.b { background: #fff; }',
'#ugf-maps-dirbox input { flex: 1; min-width: 0; height: 32px; border: 0; border-bottom: 1px solid #e0e0e0; outline: none; background: transparent; font: 14px Roboto, arial, sans-serif; color: #222; padding: 0 4px; }',
'#ugf-maps[era="m2015"] #ugf-maps-dirbox input { color: #fff; border-bottom-color: rgba(255,255,255,.5); }',
'#ugf-maps[era="m2015"] #ugf-maps-dirbox input::placeholder { color: rgba(255,255,255,.7); }',
'#ugf-maps-dirbox .dswap { position: absolute; right: 0; top: 24px; }',
'#ugf-maps-omni.dir #ugf-maps-panel { border-radius: 0 0 2px 2px; margin-top: 0; }',
'#ugf-maps-omni #ugf-maps-panel .rt { display: flex; gap: 18px; padding: 14px 18px; border-bottom: 1px solid #e6e6e6; cursor: pointer; font: 13px Roboto, arial, sans-serif; }',
'#ugf-maps-omni #ugf-maps-panel .rt.sel { border-left: 4px solid #4285f4; padding-left: 14px; }',
'#ugf-maps-omni #ugf-maps-panel .rt .mi svg { display: block; fill: #757575; }',
'#ugf-maps-omni #ugf-maps-panel .rt .rtx { flex: 1; min-width: 0; }',
'#ugf-maps-omni #ugf-maps-panel .rt .l1 { display: flex; justify-content: space-between; }',
'#ugf-maps-omni #ugf-maps-panel .rt .tm { font-size: 15px; color: #0f9d58; font-weight: 500; }',
'#ugf-maps-omni #ugf-maps-panel .rt .ds { color: #757575; }',
'#ugf-maps-omni #ugf-maps-panel .rt .via { color: #222; margin-top: 3px; }',
'#ugf-maps-omni #ugf-maps-panel .rt .det { display: inline-block; margin-top: 8px; color: #4285f4 !important; font-weight: 500; text-transform: uppercase; font-size: 12px; text-decoration: none; }',
'#ugf-maps-omni #ugf-maps-panel .steps { border-bottom: 1px solid #e6e6e6; }',
'#ugf-maps-omni #ugf-maps-panel .steps .st { display: flex; gap: 12px; padding: 10px 18px 10px 60px; cursor: pointer; font: 13px Roboto, arial, sans-serif; }',
'#ugf-maps-omni #ugf-maps-panel .steps .st:hover { background: #f5f5f5; }',
'#ugf-maps-omni #ugf-maps-panel .steps .tx { flex: 1; }',
'#ugf-maps-omni #ugf-maps-panel .steps .dd { color: #757575; white-space: nowrap; }',
'#ugf-maps-omni #ugf-maps-panel .steps .note { font-size: 12px; color: #757575; }',
// the side menu (2015 on)
'#ugf-maps-scrim { position: absolute; inset: 0; z-index: 40; background: rgba(0,0,0,.4); opacity: 0; pointer-events: none; transition: opacity .2s; }',
'#ugf-maps.drawer-open #ugf-maps-scrim { opacity: 1; pointer-events: auto; }',
'#ugf-maps-drawer { position: absolute; left: 0; top: 0; bottom: 0; width: 300px; z-index: 41; background: #fff; box-shadow: 0 0 20px rgba(0,0,0,.3); transform: translateX(-110%); transition: transform .2s ease-out; display: flex; flex-direction: column; font: 14px Roboto, arial, sans-serif; visibility: hidden; }',
'#ugf-maps.drawer-open #ugf-maps-drawer { transform: none; visibility: visible; }',
'#ugf-maps-drawer .head { display: flex; align-items: center; height: 64px; padding: 0 24px; flex: 0 0 auto; }',
'#ugf-maps-drawer .head img { display: block; }',
'#ugf-maps-drawer .head .mp { color: #757575; font: 22px Roboto, arial, sans-serif; margin-left: 5px; position: relative; top: -1px; }',
'#ugf-maps-drawer .list { overflow-y: auto; flex: 1; padding-bottom: 8px; }',
'#ugf-maps-drawer .grp { border-top: 1px solid #e6e6e6; padding: 8px 0; }',
'#ugf-maps-drawer .grp:first-child { border-top: 0; padding-top: 0; }',
'#ugf-maps-drawer a.row { display: flex; align-items: center; height: 40px; padding: 0 24px; color: #333 !important; text-decoration: none !important; cursor: pointer; }',
'#ugf-maps-drawer a.row:not(.wi) { height: 32px; font-size: 13px; color: #666 !important; }',
'#ugf-maps-drawer a.row:hover { background: #f1f1f1; }',
'#ugf-maps-drawer a.row .ic { display: block; width: 24px; height: 24px; margin-right: 24px; font-style: normal; }',
'#ugf-maps-drawer a.row .ic svg { display: block; fill: #757575; }',
'#ugf-maps-drawer a.row.on { color: #4285f4 !important; }',
'#ugf-maps-drawer a.row.on .ic svg { fill: #4285f4; }',
'#ugf-maps-drawer[era="m2019"] a.row.on, #ugf-maps-drawer[era="m2022"] a.row.on { color: #1a73e8 !important; }',
'#ugf-maps-drawer[era="m2019"] a.row.on .ic svg, #ugf-maps-drawer[era="m2022"] a.row.on .ic svg { fill: #1a73e8; }',
'html[gplex-maps], html[gplex-maps] body { overflow: hidden !important; }',
'#ugf-maps { position: fixed; inset: 0; z-index: 2147483000; background: #fff; font: 13px arial, sans-serif; color: #000; display: flex; flex-direction: column; visibility: visible; text-align: left; }',
'#ugf-maps * { box-sizing: content-box; }',
'#ugf-maps a { color: #00c; cursor: pointer; }',
'#ugf-maps-body { flex: 1; display: flex; min-height: 0; position: relative; }',
'#ugf-maps-mapwrap { position: relative; flex: 1; min-width: 0; overflow: hidden; }',
'#ugf-maps-map { position: absolute; inset: 0; overflow: hidden; background: #e5e3df; outline: none; cursor: ' + u("openhand") + ' 8 8, grab; touch-action: none; user-select: none; }',
'#ugf-maps-map.dragging { cursor: ' + u("closedhand") + ' 8 8, grabbing; }',
'.ugf-maps-pane, .ugf-maps-layer { position: absolute; left: 0; top: 0; }',
'.ugf-maps-layer { transform-origin: 0 0; }',
'.ugf-maps-tile { position: absolute; width: 256px; height: 256px; max-width: none; user-select: none; -webkit-user-drag: none; opacity: 0; transition: opacity .2s; }',
'.ugf-maps-tile.in { opacity: 1; }',
'#ugf-maps[era="m2005"] .ugf-maps-tile, #ugf-maps[era="m2006"] .ugf-maps-tile, #ugf-maps[era="m2007"] .ugf-maps-tile { transition: none; }',
'.ugf-maps-overlay { position: absolute; inset: 0; pointer-events: none; }',
'.ugf-maps-marker { position: absolute; pointer-events: auto; cursor: pointer; }',
'.ugf-maps-ctl { position: absolute; z-index: 5; }',
'.ugf-maps-ctl i, .ugf-maps-ctl b { position: absolute; display: block; cursor: pointer; }',
// ---- 2005-2006
'#ugf-maps[era="m2005"] #ugf-maps-head, #ugf-maps[era="m2006"] #ugf-maps-head { display: flex; align-items: flex-start; padding: 5px 8px 3px 8px; }',
'#ugf-maps-head .logo img { display: block; border: 0; }',
'#ugf-maps-head .mid { margin: 5px 0 0 12px; }',
'#ugf-maps-head .tabs { font-size: 13px; margin: 0 0 3px 1px; }',
'#ugf-maps-head .tabs b { margin-right: 14px; }',
'#ugf-maps-head .tabs a { margin-right: 14px; }',
'#ugf-maps[era="m2005"] #ugf-maps-q, #ugf-maps[era="m2006"] #ugf-maps-q { width: 440px; font: 13px arial, sans-serif; padding: 1px 2px; border: 1px solid #7f9db9; }',
'#ugf-maps-head input[type="submit"] { font: 13px arial, sans-serif; margin-left: 5px; }',
'#ugf-maps-head .help { margin: 6px 0 0 auto; font-size: 11px; line-height: 13px; }',
'#ugf-maps-titlebar { background: #ffe9c6; border-top: 1px solid #dbbd95; font: bold 16px arial, sans-serif; padding: 2px 8px 3px 8px; margin: 0 8px; }',
'#ugf-maps[era="m2005"] #ugf-maps-body, #ugf-maps[era="m2006"] #ugf-maps-body { padding: 8px; }',
'#ugf-maps[era="m2005"] #ugf-maps-mapwrap, #ugf-maps[era="m2006"] #ugf-maps-mapwrap { border: 1px solid #979797; }',
'#ugf-maps[era="m2005"] #ugf-maps-panel, #ugf-maps[era="m2006"] #ugf-maps-panel { width: 280px; flex: 0 0 280px; padding: 0 0 0 10px; overflow-y: auto; }',
'#ugf-maps-panel .links { margin: 2px 0 14px 0; }',
'#ugf-maps-panel .links a { margin-right: 12px; }',
'#ugf-maps-panel .eh { color: #e98b39; font: bold 16px arial, sans-serif; margin-bottom: 8px; }',
'#ugf-maps-panel .ex { font-weight: bold; margin: 8px 0 5px 0; }',
'#ugf-maps-panel .examples form { margin: 0 0 3px 0; display: flex; gap: 4px; }',
'#ugf-maps-panel .examples input:not([type]) { width: 170px; font: 13px arial, sans-serif; border: 1px solid #7f9db9; padding: 1px 2px; }',
'#ugf-maps-panel .examples input[type="submit"] { font: 13px arial, sans-serif; }',
'#ugf-maps-panel .drag { margin-top: 14px; }',
'.large2005 { left: 7px; top: 7px; width: 59px; height: 400px; }',
'.large2005 i { background-image: ' + u("ctl2005") + '; width: 17px; height: 17px; }',
'.large2005 .up { left: 20px; top: 0; background-position: -20px 0; }',
'.large2005 .lf { left: 0; top: 20px; background-position: 0 -20px; }',
'.large2005 .ct { left: 20px; top: 20px; background-position: -20px -20px; }',
'.large2005 .rt { left: 40px; top: 20px; background-position: -40px -20px; }',
'.large2005 .dn { left: 20px; top: 40px; background-position: -20px -40px; }',
'.large2005 .zi { left: 20px; top: 65px; background-position: -20px -65px; }',
'.large2005 .rail { left: 21px; top: 85px; width: 17px; background-position: -21px -85px; }',
'.large2005 .zo { left: 20px; background-position: -20px -365px; }',
'.large2005 .knob { left: 19px; width: 22px; height: 14px; background-position: 0 -384px; cursor: default; }',
// ---- 2007-2013 headers and the Google bar
'#ugf-maps-gbar { display: flex; align-items: center; justify-content: space-between; font: 13px arial, sans-serif; flex: 0 0 auto; }',
'#ugf-maps-gbar .left, #ugf-maps-gbar .right { display: flex; align-items: center; }',
'#ugf-maps-gbar .sepr { color: #ccc; margin: 0 8px; }',
'#ugf-maps-gbar.plain { background: #fff; padding: 3px 10px 5px 10px; }',
'#ugf-maps-gbar.plain .left { gap: 11px; }',
'#ugf-maps-gbar.plain a { color: #00c; text-decoration: underline; }',
'#ugf-maps-gbar a.here { color: #000 !important; font-weight: bold; text-decoration: none !important; cursor: default; }',
'#ugf-maps-gbar .who { color: #00c; font-weight: bold; }',
'#ugf-maps-gbar.g2010 { background: linear-gradient(#fff, #fafafa); border-bottom: 1px solid #e5e5e5; padding: 0 10px; height: 29px; }',
'#ugf-maps-gbar.g2010 .left { gap: 13px; height: 29px; }',
'#ugf-maps-gbar.g2010 a { color: #00c; line-height: 26px; height: 29px; border-top: 3px solid transparent; box-sizing: border-box; text-decoration: none; }',
'#ugf-maps-gbar.g2010 a.here { border-top-color: #4d90fe; }',
'#ugf-maps-gbar.dark { background: #2d2d2d; height: 30px; padding: 0 14px; color: #ccc; }',
'#ugf-maps-gbar.dark .left { gap: 13px; height: 30px; }',
'#ugf-maps-gbar.dark a { color: #ccc !important; line-height: 27px; height: 30px; border-top: 3px solid transparent; box-sizing: border-box; text-decoration: none; }',
'#ugf-maps-gbar.dark a:hover { color: #fff !important; }',
'#ugf-maps-gbar.dark a.here { color: #fff !important; border-top-color: #dd4b39; }',
'#ugf-maps-gbar.dark .who { color: #fff; }',
'#ugf-maps-gbar.dark a.plus { color: #fff !important; font-weight: bold; }',
'#ugf-maps-gbar.dark.late { padding: 0 4px; height: 29px; } #ugf-maps-gbar.dark.late .left { gap: 0; height: 29px; }',
'#ugf-maps-gbar.dark.late a { border-top: 0; line-height: 29px; height: 29px; font-weight: bold; color: #bbb !important; padding: 0 9px; }',
'#ugf-maps-gbar.dark.late a.here, #ugf-maps-gbar.dark.late a:hover { color: #fff !important; } #ugf-maps-gbar.dark.late a.plus { color: #bbb !important; }',
// 2014 and 2015: the bar sits above the full-window map
'#ugf-maps-gbarwrap { position: fixed; top: 0; left: 0; right: 0; z-index: 2147483001; visibility: visible; text-align: left; }',
'html[gplex-maps-bar] #ugf-maps { top: 29px; }',
'#ugf-maps-gbar.dark .gear { display: inline-flex; align-items: center; border: 0; line-height: normal; }',
'#ugf-maps-gbar.dark .gear svg { fill: #ccc; display: block; }',
'#ugf-maps-gbar.dark .gear:hover svg { fill: #fff; }',
'#ugf-maps-account { display: flex; align-items: center; gap: 10px; font: 13px arial, sans-serif; }',
'#ugf-maps[era="m2011"] #ugf-maps-account, #ugf-maps[era="m2011"] #ugf-maps-head > .signin { margin-left: auto; }',
'#ugf-maps-account .plusname { color: #666; font-size: 13px; text-decoration: none; }',
'#ugf-maps-account .plusname:hover { text-decoration: underline; }',
'#ugf-maps-account .nbox { min-width: 26px; height: 26px; box-sizing: border-box; border: 1px solid #dcdcdc; border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #777; font-size: 12px; display: inline-flex; align-items: center; justify-content: center; padding: 0 6px; }',
'#ugf-maps-account .sharebtn { height: 26px; box-sizing: border-box; border: 1px solid #dcdcdc; border-radius: 2px; background: linear-gradient(#f5f5f5, #f1f1f1); color: #444; font-size: 12px; display: inline-flex; align-items: center; gap: 5px; padding: 0 10px; cursor: pointer; }',
'#ugf-maps-account .sharebtn b { font-size: 14px; font-weight: normal; color: #777; }',
'#ugf-maps-account .pfpwrap { display: inline-flex; align-items: center; gap: 3px; border: 1px solid #dcdcdc; border-radius: 2px; padding: 1px 4px 1px 1px; background: #fff; cursor: pointer; }',
'#ugf-maps-account .pfpwrap .car { font-style: normal; color: #777; font-size: 9px; }',
'#ugf-maps-account .pfp { width: 24px; height: 24px; border-radius: 1px; display: block; object-fit: cover; }',
'#ugf-maps-account .pfp.letter { background: #c62828; color: #fff; font-size: 14px; display: flex; align-items: center; justify-content: center; text-transform: uppercase; }',
'#ugf-maps-account .ic { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; }',
'#ugf-maps-account .ic svg { fill: #666; display: block; }',
'#ugf-maps-account .ic:hover svg { fill: #333; }',
'#ugf-maps-head > .signin { display: inline-flex; align-items: center; height: 29px; padding: 0 12px; background: linear-gradient(#dd4b39, #d14836); border: 1px solid #c53727; border-radius: 2px; color: #fff !important; font: bold 13px arial, sans-serif; text-decoration: none; }',
'#ugf-maps[era="m2014"] #ugf-maps-account { background: rgba(255,255,255,.92); padding: 4px 8px; border-radius: 2px; box-shadow: 0 1px 4px rgba(0,0,0,.2); }',
'#ugf-maps[era="m2007"] #ugf-maps-head, #ugf-maps[era="m2010"] #ugf-maps-head, #ugf-maps[era="m2011"] #ugf-maps-head { display: flex; align-items: center; padding: 4px 10px 8px 10px; border-bottom: 1px solid #c9d7f1; }',
'#ugf-maps[era="m2011"] #ugf-maps-head { border-bottom: 1px solid #e5e5e5; padding: 14px 16px; background: #f1f1f1; }',
'#ugf-maps[era="m2010"] #ugf-maps-head { border-bottom: 1px solid #e5e5e5; }',
'#ugf-maps[era="m2007"] #ugf-maps-form, #ugf-maps[era="m2010"] #ugf-maps-form { margin-left: 14px; display: flex; align-items: center; gap: 6px; }',
'#ugf-maps[era="m2007"] #ugf-maps-q, #ugf-maps[era="m2010"] #ugf-maps-q { width: 420px; font: 16px arial, sans-serif; padding: 2px 3px; border: 1px solid #7e9db9; }',
'#ugf-maps[era="m2007"] #ugf-maps-form input[type="submit"] { font: 13px arial, sans-serif; }',
'#ugf-maps-form .grad { font: bold 13px arial, sans-serif; color: #444; background: linear-gradient(#fff, #e6e6e6); border: 1px solid #aaa; border-radius: 2px; padding: 4px 10px; }',
'#ugf-maps-form .opts { font-size: 12px; margin-left: 6px; }',
'#ugf-maps[era="m2011"] #ugf-maps-head .logo img { margin: -1px 24px -1px 4px; }',
'#ugf-maps[era="m2011"] #ugf-maps-head .logo img.l2012 { margin: -3px 20px -3px 0; }',
'#ugf-maps[era="m2011"] #ugf-maps-form { display: flex; align-items: center; }',
'#ugf-maps[era="m2011"] #ugf-maps-q { width: 520px; height: 23px; font: 16px arial, sans-serif; padding: 2px 8px; border: 1px solid #d9d9d9; border-top-color: #c0c0c0; border-radius: 1px 0 0 1px; outline: none; }',
'#ugf-maps[era="m2011"] #ugf-maps-q:focus { border-color: #4d90fe; }',
'#ugf-maps-form button.blue { width: 72px; height: 29px; border: 1px solid #3079ed; background: linear-gradient(#4d90fe, #4787ed); border-radius: 0 2px 2px 0; cursor: pointer; padding: 0; box-sizing: border-box; }',
'#ugf-maps-form button.blue i, #ugf-maps-form button.go14 i { display: block; width: 24px; height: 24px; margin: 0 auto; background: ' + u("qsb") + ' -48px 0; transform: scale(.75); }',
'#ugf-maps[era="m2007"] #ugf-maps-panel, #ugf-maps[era="m2010"] #ugf-maps-panel, #ugf-maps[era="m2011"] #ugf-maps-panel { width: 326px; flex: 0 0 326px; overflow-y: auto; border-right: 1px solid #c9d7f1; padding: 8px 10px; box-sizing: border-box !important; }',
'#ugf-maps[era="m2011"] #ugf-maps-panel { border-right: 1px solid #e5e5e5; }',
'#ugf-maps-links { position: absolute; top: 0; right: 10px; z-index: 6; font-size: 12px; padding: 3px 0; }',
'#ugf-maps-links a { margin-left: 12px; }',
'#ugf-maps[era="m2007"] #ugf-maps-links + #ugf-maps-map, #ugf-maps[era="m2010"] #ugf-maps-links + #ugf-maps-map { top: 20px; }',
'#ugf-maps-panel .btns { display: flex; gap: 6px; margin: 0 0 12px 0; }',
'#ugf-maps-panel .b { display: inline-block; font: bold 11px arial, sans-serif; color: #444 !important; text-decoration: none; padding: 5px 10px; border: 1px solid #c6c6c6; border-radius: 2px; background: linear-gradient(#f8f8f8, #f1f1f1); }',
'#ugf-maps-panel .b.red { color: #fff !important; background: linear-gradient(#dd4b39, #d14836); border-color: #c53727; text-transform: none; }',
'#ugf-maps-panel .tips { color: #444; line-height: 1.5; }',
'#ugf-maps-panel .status { margin: 8px 0; color: #444; }',
'#ugf-maps-panel .hint { color: #666; }',
'#ugf-maps-panel .rhead { color: #666; font-size: 12px; margin: 0 0 6px 0; }',
'#ugf-maps-panel .res { display: flex; gap: 6px; padding: 5px 0 7px 0; cursor: pointer; }',
'#ugf-maps-panel .res .mk { width: 20px; height: 34px; flex: 0 0 20px; }',
'#ugf-maps-panel .res .n { font-weight: bold; }',
'#ugf-maps-panel .res .l { color: #333; font-size: 12px; }',
'#ugf-maps-panel .acts { font-size: 12px; margin-top: 2px; color: #666; }',
'.large2008 { left: 14px; top: 10px; width: 59px; height: 360px; }',
'.large2008 i { background-image: ' + u("ctl2008") + '; }',
'.large2008 .peg { left: 19px; top: 0; width: 21px; height: 32px; background-position: -5px -460px; }',
'.large2008 .peg:hover { background-position: -35px -460px; }',
'.large2008 .pad { left: 3px; top: 36px; width: 54px; height: 55px; background-position: -3px -2px; cursor: default; }',
'.large2008 b { width: 18px; height: 18px; }',
'.large2008 .up { left: 21px; top: 38px; } .large2008 .dn { left: 21px; top: 72px; } .large2008 .lf { left: 4px; top: 55px; } .large2008 .rt { left: 38px; top: 55px; }',
'.large2008 .zi { left: 20px; top: 98px; width: 20px; height: 22px; background-position: -20px -65px; }',
'.large2008 .rail { left: 20px; top: 120px; width: 20px; background-position: -20px -90px; }',
'.large2008 .zo { left: 20px; width: 20px; height: 22px; background-position: -20px -361px; }',
'.large2008 .knob { left: 21px; width: 18px; height: 12px; background-position: -2px -384px; cursor: default; }',
'.large2010 { left: 14px; top: 10px; width: 59px; height: 360px; }',
'.large2010 i { background-image: ' + u("ctl2010") + '; }',
'.large2010 .peg { left: 20px; top: 0; width: 19px; height: 32px; background: ' + u("pegv3") + ' no-repeat; }',
'.large2010 .pad { left: 3px; top: 36px; width: 52px; height: 54px; background-position: -3px -2px; cursor: default; }',
'.large2010 b { width: 17px; height: 17px; }',
'.large2010 .up { left: 21px; top: 38px; } .large2010 .dn { left: 21px; top: 72px; } .large2010 .lf { left: 4px; top: 55px; } .large2010 .rt { left: 38px; top: 55px; }',
'.large2010 .zi { left: 20px; top: 98px; width: 18px; height: 20px; background-position: -2px -428px; }',
'.large2010 .rail { left: 20px; top: 120px; width: 18px; background-position: -20px -84px; }',
'.large2010 .zo { left: 19px; width: 19px; height: 19px; background-position: -1px -62px; }',
'.large2010 .knob { left: 20px; width: 18px; height: 11px; background-position: -1px -384px; cursor: default; }',
'.types { top: 7px; right: 7px; display: flex; gap: 3px; }',
'#ugf-maps[era="m2007"] .types, #ugf-maps[era="m2010"] .types { top: 27px; }',
'#ugf-maps[era="m2007"] .large2008, #ugf-maps[era="m2010"] .large2010 { top: 30px; }',
'.types.v2 a { display: block; min-width: 5em; text-align: center; background: #fff; border: 1px solid #000; color: #000 !important; font: 12px arial, sans-serif; padding: 0 3px; line-height: 17px; text-decoration: none; }',
'.types.v2 a.on { font-weight: bold; }',
'.types.v3 { gap: 0; box-shadow: rgba(0,0,0,.4) 0 2px 4px; }',
'.types.v3 a { display: block; background: #fff; border: 1px solid #717b87; color: #000 !important; font: 12px arial, sans-serif; padding: 1px 6px; line-height: 17px; text-decoration: none; margin-left: -1px; }',
'.types.v3 a.on { font-weight: bold; }',
'.thumb11 { top: 10px; right: 10px; width: 64px; height: 64px; border: 2px solid #fff; box-shadow: 0 1px 4px rgba(0,0,0,.4); cursor: pointer; overflow: hidden; }',
'.thumb14 { left: 10px; bottom: 26px; width: 72px; height: 72px; border: 2px solid #fff; border-radius: 2px; box-shadow: 0 1px 4px rgba(0,0,0,.3); cursor: pointer; overflow: hidden; }',
'.thumb11 .img, .thumb14 .img, .layers19 .img { position: absolute; inset: 0; background-size: 256px 256px; background-position: center; }',
'.thumb11 .lbl, .thumb14 .lbl, .layers19 .lbl { position: absolute; left: 0; right: 0; bottom: 0; color: #fff; font: bold 11px arial, sans-serif; text-align: center; padding: 3px 0; background: linear-gradient(transparent, rgba(0,0,0,.6)); }',
// ---- the info window, out of Google's own bubble
'.ugf-maps-iw { position: absolute; pointer-events: auto; cursor: default; min-width: 220px; max-width: 300px; font: 13px arial, sans-serif; }',
'.ugf-maps-iw .box { position: relative; border-style: solid; border-width: 20px; border-image: ' + u("iwbox") + ' 25 fill / 20px stretch; padding: 0; }',
'.ugf-maps-iw .box > * { position: relative; }',
'.ugf-maps-iw .x { position: absolute; right: -8px; top: -8px; cursor: pointer; }',
'.ugf-maps-iw .t { font-weight: bold; margin: 0 14px 4px 0; }',
'.ugf-maps-iw .l { color: #333; font-size: 12px; }',
'.ugf-maps-iw .acts { font-size: 12px; margin-top: 6px; }',
'.ugf-maps-iw .tail { position: absolute; left: 30px; bottom: -86px; width: 98px; height: 96px; pointer-events: none; }',
'.ugf-maps-marker.sel { z-index: 3; }',
// ---- small print on the map
'.foot { left: 0; right: 0; bottom: 0; height: 20px; pointer-events: none; font: 11px arial, sans-serif; color: #000; }',
'.foot a { pointer-events: auto; }',
'.foot .copy { position: absolute; bottom: 2px; white-space: nowrap; }',
'.foot .copy.l { left: 5px; } .foot .copy.r { right: 5px; }',
'.foot .glogo { position: absolute; left: 2px; bottom: 0; pointer-events: none; }',
'.foot.m2007 .glogo { height: 26px; bottom: 2px; }',
'.foot .scale { position: absolute; left: 80px; bottom: 3px; }',
'.foot.m2005 .scale, .foot.m2006 .scale { left: 100px; }',
'.foot .scale i { position: static; display: block; height: 4px; border: 2px solid #000; border-top: 0; margin-top: 1px; cursor: default; }',
'.foot .scale .sl { font-size: 11px; }',
// ---- 2014 onward: everything floats on the map
'#ugf-maps[era="m2014"], #ugf-maps[era="m2015"], #ugf-maps[era="m2019"], #ugf-maps[era="m2022"] { font-family: Roboto, arial, sans-serif; }',
'#ugf-maps-omni { position: absolute; left: 8px; top: 8px; width: 392px; z-index: 10; }',
'#ugf-maps-omni #ugf-maps-form { display: flex; align-items: center; height: 48px; background: #fff; border-radius: 2px; box-shadow: 0 2px 4px rgba(0,0,0,.2), 0 -1px 0 rgba(0,0,0,.02); position: relative; }',
'#ugf-maps-omni .menu { width: 18px; height: 12px; margin: 0 27px 0 19px; cursor: pointer; display: block; }',
'#ugf-maps-omni .menu img { display: block; }',
'#ugf-maps-omni #ugf-maps-q { flex: 1; min-width: 0; border: 0; outline: none; font: 15px Roboto, arial, sans-serif; color: #000; background: transparent; padding: 0; height: 24px; }',
'#ugf-maps-omni .go { width: 18px; height: 18px; border: 0; background: none; padding: 0; margin: 0 17px 0 12px; cursor: pointer; }',
'#ugf-maps-omni .go img, #ugf-maps-omni .dir img { display: block; }',
'#ugf-maps-omni .sep { width: 1px; height: 28px; background: #ddd; }',
'#ugf-maps-omni .dir { margin: 0 15px 0 15px; display: block; }',
'#ugf-maps[era="m2014"] #ugf-maps-q { padding-left: 16px !important; }',
'#ugf-maps-omni button.go14 { height: 48px; width: 64px; border: 0; background: #4d90fe; border-radius: 0 2px 2px 0; cursor: pointer; padding: 0; }',
'#ugf-maps-omni #ugf-maps-panel { display: none; background: #fff; box-shadow: 0 2px 4px rgba(0,0,0,.2); border-radius: 0 0 2px 2px; margin-top: -2px; max-height: calc(100vh - 150px); overflow-y: auto; position: relative; }',
'#ugf-maps-omni #ugf-maps-panel.on { display: block; border-top: 1px solid #e6e6e6; }',
'#ugf-maps-omni #ugf-maps-panel .res { display: block; padding: 11px 16px 11px 64px; border-bottom: 1px solid #e6e6e6; cursor: pointer; position: relative; }',
'#ugf-maps-omni #ugf-maps-panel .res:before { content: ""; position: absolute; left: 22px; top: 12px; width: 12px; height: 17px; background: url("' + A.kit.place + '") no-repeat; }',
'#ugf-maps-omni #ugf-maps-panel .res .n { font: 500 13px Roboto, arial, sans-serif; color: #000 !important; text-decoration: none; }',
'#ugf-maps-omni #ugf-maps-panel .res .l { font: 12px Roboto, arial, sans-serif; color: #8c8c8c; margin-top: 2px; }',
'#ugf-maps-omni #ugf-maps-panel .status, #ugf-maps-omni #ugf-maps-panel .hint { padding: 0 16px 0 64px; font: 13px Roboto, arial, sans-serif; }',
'#ugf-maps-omni #ugf-maps-panel .status { padding-top: 12px; } #ugf-maps-omni #ugf-maps-panel .hint { padding-bottom: 12px; color: #8c8c8c; }',
'#ugf-maps-topright { position: absolute; top: 16px; right: 20px; z-index: 10; display: flex; align-items: center; gap: 22px; }',
'#ugf-maps-topright .apps img { display: block; }',
'#ugf-maps-topright .signin { display: flex; align-items: center; height: 29px; padding: 0 12px; background: #4285f4; border: 1px solid #4285f4; border-radius: 2px; color: #fff !important; font: bold 14px Roboto, arial, sans-serif; text-decoration: none; }',
'#ugf-maps-topright .who { font: 500 13px Roboto, arial, sans-serif; color: #000; background: #fff; padding: 6px 10px; border-radius: 2px; box-shadow: 0 1px 4px rgba(0,0,0,.3); }',
'.loc15 { right: 14px; bottom: 106px; width: 41px; height: 41px; cursor: pointer; }',
'.zoom15 { right: 14px; bottom: 46px; width: 41px; height: 69px; }',
'.loc15 img, .zoom15 img, .imagery15 img, .peg14 img { display: block; }',
'.zoom15 .zi, .zoom15 .zo { position: absolute; left: 6px; width: 29px; height: 28px; cursor: pointer; }',
'.zoom15 .zi { top: 6px; } .zoom15 .zo { top: 35px; }',
'.imagery15 { right: 14px; bottom: 14px; width: 156px; height: 41px; }',
'.imagery15 .peg { position: absolute; left: 6px; top: 6px; width: 31px; height: 29px; cursor: pointer; }',
'.imagery15 .more { position: absolute; left: 37px; top: 6px; width: 113px; height: 29px; cursor: pointer; }',
// ---- Street View (4.5.4 / 5.0.5)
'#ugf-maps-pegfly { position: fixed; z-index: 2147483647; pointer-events: none; width: 26px; height: 36px; }',
'#ugf-maps-sv { position: absolute; inset: 0; z-index: 40; background: #000; display: flex; flex-direction: column; }',
'#ugf-maps-sv .pano { flex: 1; width: 100%; border: 0; display: block; min-height: 0; }',
// classic Maps: a plain strip over the panorama saying where you stand
'#ugf-maps-sv .svbar { display: flex; align-items: center; gap: 10px; padding: 4px 8px; background: #fff; border-bottom: 1px solid #979797; font: 13px arial, sans-serif; color: #000; }',
'#ugf-maps-sv .svbar .c { color: #676767; font-size: 11px; }',
'#ugf-maps-sv .svbar .back { margin-left: auto; color: #00c !important; text-decoration: underline; }',
'#ugf-maps-sv[era="m2010"] .svbar, #ugf-maps-sv[era="m2011"] .svbar { background: #f1f1f1; border-bottom-color: #c5c5c5; }',
// new Maps: the dark card at the top left, with the way back to the map
'#ugf-maps-sv .svcard { position: absolute; left: 12px; top: 12px; z-index: 2; display: flex; align-items: center; gap: 12px; max-width: 360px; padding: 10px 16px 10px 10px; background: rgba(34,34,34,.8); color: #fff; font: 13px Roboto, arial, sans-serif; box-shadow: 0 1px 4px rgba(0,0,0,.3); }',
'#ugf-maps-sv .svcard .back { color: #fff !important; text-decoration: none; font-size: 22px; line-height: 22px; padding: 0 4px; }',
'#ugf-maps-sv .svcard .t { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
'#ugf-maps-sv .svcard .c { font-size: 12px; color: #bbb; margin-top: 2px; }',
'#ugf-maps-sv[era="m2019"] .svcard, #ugf-maps-sv[era="m2022"] .svcard { border-radius: 8px; }',
'#ugf-maps-sv[era="m2019"] .svcard .t, #ugf-maps-sv[era="m2022"] .svcard .t { font-family: "Google Sans", Roboto, arial, sans-serif; }',
'#ugf-maps .thumb { cursor: pointer; }',
'#ugf-maps-sv .svzoom { right: 14px; bottom: 30px; z-index: 2; }',
'.peg14 { right: 20px; bottom: 20px; width: 29px; height: 29px; background: #fff; border-radius: 2px; box-shadow: 0 1px 4px rgba(0,0,0,.3); cursor: pointer; display: flex; align-items: center; justify-content: center; }',
'#ugf-maps[era="m2014"] .loc15, #ugf-maps[era="m2019"] .loc15, #ugf-maps[era="m2022"] .loc15 { bottom: 146px; }',
'#ugf-maps[era="m2014"] .zoom15, #ugf-maps[era="m2019"] .zoom15, #ugf-maps[era="m2022"] .zoom15 { bottom: 86px; }',
'#ugf-maps[era="m2014"] .peg14 { bottom: 52px; right: 20px; }',
'#ugf-maps[era="m2019"] .peg14, #ugf-maps[era="m2022"] .peg14 { bottom: 52px; }',
'#ugf-maps[era="m2019"] #ugf-maps-omni #ugf-maps-form { border-radius: 8px; }',
'#ugf-maps[era="m2022"] #ugf-maps-omni #ugf-maps-form { border-radius: 24px; }',
'#ugf-maps-chips { position: absolute; left: 404px; top: 8px; display: flex; gap: 8px; white-space: nowrap; }',
'#ugf-maps-chips button { height: 32px; padding: 0 12px; border: 0; border-radius: 16px; background: #fff; box-shadow: 0 1px 2px rgba(60,64,67,.3), 0 1px 3px 1px rgba(60,64,67,.15); font: 500 14px Roboto, arial, sans-serif; color: #3c4043; cursor: pointer; margin-top: 8px; }',
'.layers19 { left: 16px; bottom: 26px; width: 74px; height: 74px; border: 2px solid #fff; border-radius: 8px; box-shadow: 0 1px 4px rgba(0,0,0,.3); cursor: pointer; overflow: hidden; }',
'#ugf-maps-card { display: none; position: absolute; left: 50%; bottom: 21px; width: 384px; height: 72px; margin-left: -192px; background: #fff; border-radius: 2px; box-shadow: 0 1px 4px rgba(0,0,0,.3); z-index: 9; }',
'#ugf-maps-card.on { display: block; }',
'#ugf-maps-card .thumb { position: absolute; left: 3px; top: 4px; width: 96px; height: 64px; background-size: cover; background-position: center; cursor: pointer; }',
'#ugf-maps-card .txt { position: absolute; left: 114px; top: 11px; right: 70px; }',
'#ugf-maps-card .t { font: bold 12px Roboto, arial, sans-serif; line-height: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
'#ugf-maps-card .a { font: 12px Roboto, arial, sans-serif; line-height: 14px; margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
'#ugf-maps-card .c { font: 12px Roboto, arial, sans-serif; line-height: 14px; margin-top: 4px; color: #989898; }',
'#ugf-maps-card .d { position: absolute; left: 323px; top: 19px; display: block; }',
'#ugf-maps-card .d img { display: block; width: 34px; height: 34px; }',
'#ugf-maps-card .x { position: absolute; right: 5px; top: 5px; cursor: pointer; padding: 2px; }',
'.foot.m2014, .foot.m2015, .foot.m2019, .foot.m2022 { height: 13px; left: auto; right: 0; }',
'.foot.m2014 .copy.r, .foot.m2015 .copy.r, .foot.m2019 .copy.r, .foot.m2022 .copy.r { position: static; display: flex; align-items: center; gap: 14px; background: rgba(255,255,255,.7); padding: 0 6px 0 4px; height: 13px; font: 10px Roboto, arial, sans-serif; color: #444; }',
'.foot.m2014 .copy.r a, .foot.m2015 .copy.r a, .foot.m2019 .copy.r a, .foot.m2022 .copy.r a { color: #444 !important; text-decoration: none; }',
'.foot.m2014 .scale, .foot.m2015 .scale, .foot.m2019 .scale, .foot.m2022 .scale { position: static; display: flex; align-items: center; gap: 4px; }',
'.foot.m2014 .scale i, .foot.m2015 .scale i, .foot.m2019 .scale i, .foot.m2022 .scale i { height: 3px; border-width: 1px; border-color: #444; margin: 2px 0 0 0; }',
'.foot.m2014 .scale .sl, .foot.m2015 .scale .sl, .foot.m2019 .scale .sl, .foot.m2022 .scale .sl { font-size: 10px; }',
'.foot .glogo.mid { position: fixed; left: 50%; bottom: 14px; margin-left: -31px; }',
'.foot .glogo.mid[width="70"] { margin-left: -35px; bottom: 12px; }',
'#ugf-maps[era="m2019"] .foot .glogo.mid, #ugf-maps[era="m2022"] .foot .glogo.mid { margin-left: -43px; bottom: 8px; }'
].join("\n");
}
// ---- end Gplex for Google Maps ----
// ---- Shopping results (Froogle on the older layouts, Google Shopping from 2012) ----
const UGF_PRICE_RE = /(?:[$£€¥₹]\s?\d[\d.,]*|\d[\d.,]*\s?(?:USD|EUR|GBP|CAD|AUD))/;
const UGF_RATING_RE = /^\d(?:\.\d)?\s*(?:★|stars?)?\s*(?:\(\d[\d,]*\))?$/i;
function ugfShopText(el) {
const out = [];
el.querySelectorAll("span, div, h3, h4, a").forEach(function(n) {
if (n.children.length) {
return;
}
const t = (n.textContent || "").replace(/\s+/g, " ").trim();
if (t && out.indexOf(t) === -1) {
out.push(t);
}
});
return out;
}
function ugfFindShoppingCards() {
const scope = document.querySelector("#rso") || document.querySelector("#search") || document.querySelector("#center_col") || document.body;
if (!scope) {
return [];
}
const out = [];
const seen = {};
scope.querySelectorAll("img").forEach(function(img) {
if (img.closest("#ugf")) {
return;
}
const w = parseInt(img.getAttribute("width") || "0", 10) || img.naturalWidth || Math.round(img.getBoundingClientRect().width);
if (w < 60) {
return;
}
let card = null;
let el = img;
for (let i = 0; i < 8 && el.parentElement; i++) {
el = el.parentElement;
if (UGF_PRICE_RE.test(el.textContent || "")) {
card = el;
break;
}
}
if (!card) {
return;
}
const a = card.querySelector("a[href]");
if (!a) {
return;
}
const href = ugfLensDecodeHref(a.getAttribute("href") || "");
if (!href || href.indexOf("javascript") === 0) {
return;
}
const lines = ugfShopText(card);
let price = "";
let title = "";
let merchant = "";
let rating = "";
lines.forEach(function(t) {
if (!price && UGF_PRICE_RE.test(t) && t.length < 40) {
price = (t.match(UGF_PRICE_RE) || [t])[0];
return;
}
if (!rating && UGF_RATING_RE.test(t)) {
rating = t;
return;
}
if (t.length > title.length && t.length > 12 && !UGF_PRICE_RE.test(t)) {
title = t;
}
});
lines.forEach(function(t) {
if (!merchant && t !== title && t !== price && t !== rating && t.length > 1 && t.length < 32 && !UGF_PRICE_RE.test(t) && !/^\d+$/.test(t)) {
merchant = t;
}
});
if (!title) {
title = (img.getAttribute("alt") || "").trim();
}
const key = href + "|" + title;
if (!title || seen[key]) {
return;
}
seen[key] = true;
out.push({
href: href,
title: title,
price: price,
merchant: merchant,
rating: rating,
thumbnail: ugfNewsThumbSrc(img),
origImg: img
});
});
if (out.length < 6) {
ugfFindShoppingByPrice(scope, out, seen);
}
return out.slice(0, 60);
}
// second pass for cards whose thumbnail has not loaded yet: start from the price instead
function ugfFindShoppingByPrice(scope, out, seen) {
const priceNodes = [];
scope.querySelectorAll("span, div, b, strong").forEach(function(n) {
if (n.children.length || priceNodes.length > 200) {
return;
}
const t = (n.textContent || "").replace(/\s+/g, " ").trim();
if (t && t.length < 24 && UGF_PRICE_RE.test(t)) {
priceNodes.push({ el: n, text: (t.match(UGF_PRICE_RE) || [t])[0] });
}
});
priceNodes.forEach(function(p) {
let card = null;
let el = p.el;
for (let i = 0; i < 8 && el.parentElement; i++) {
el = el.parentElement;
if (el.querySelector("a[href]") && (el.textContent || "").replace(/\s+/g, " ").trim().length > 25) {
card = el;
break;
}
}
if (!card) {
return;
}
const a = card.querySelector("a[href]");
const href = ugfLensDecodeHref(a.getAttribute("href") || "");
if (!href || href.indexOf("javascript") === 0) {
return;
}
const lines = ugfShopText(card);
let title = "";
let merchant = "";
let rating = "";
lines.forEach(function(t) {
if (UGF_PRICE_RE.test(t)) {
return;
}
if (!rating && UGF_RATING_RE.test(t)) {
rating = t;
return;
}
if (t.length > title.length && t.length > 12) {
title = t;
}
});
lines.forEach(function(t) {
if (!merchant && t !== title && t !== rating && t.length > 1 && t.length < 32 && !UGF_PRICE_RE.test(t)) {
merchant = t;
}
});
if (!title) {
return;
}
const key = href + "|" + title;
if (seen[key]) {
return;
}
for (let i = 0; i < out.length; i++) {
if (out[i].title === title) {
return;
}
}
seen[key] = true;
const img = card.querySelector("img");
out.push({
href: href,
title: title,
price: p.text,
merchant: merchant,
rating: rating,
thumbnail: img ? ugfNewsThumbSrc(img) : "",
origImg: img
});
});
}
// ---- google.com/...?gbv=1 : the no-JavaScript page, whose markup predates everything else we parse ----
function ugfBasicHref(a) {
let href = a.getAttribute("href") || "";
if (href.indexOf("/url?") === 0 || href.indexOf("https://www.google.com/url?") === 0) {
try {
const u = new URL(href, "https://www.google.com");
href = u.searchParams.get("q") || u.searchParams.get("url") || "";
} catch (e) {
href = "";
}
}
return /^https?:\/\//.test(href) ? href : "";
}
function ugfFindBasicResults() {
const scope = document.querySelector("#main") || document.querySelector("#center_col") || document.body;
if (!scope) {
return [];
}
const out = [];
const seen = {};
// (6.5.3) the results' titles are headings: once there are any, links without one (the page's
// own "Sign in", "Privacy", "Learn more"...) aren't results
const headed = !!scope.querySelector("a[href] h3");
scope.querySelectorAll("a[href]").forEach(function(a) {
if (a.closest("#ugf") || (headed && !a.querySelector("h3"))) {
return;
}
const href = ugfBasicHref(a);
if (!href || /^https?:\/\/(www\.)?google\.[^/]+\//.test(href) || seen[href]) {
return;
}
const heading = a.querySelector("h3") || a.querySelector("div, span");
const title = ((heading ? heading.textContent : a.textContent) || "").replace(/\s+/g, " ").trim();
if (!title || title.length < 3) {
return;
}
// climb only while this is still the one result in the container, so snippets don't bleed between results
// (Google's lightweight pages mark each result's box with "xpd": that box is the result)
let card = a.closest(".xpd") || a.parentElement || a;
let guard = a.closest(".xpd") ? 5 : 0;
while (card.parentElement && guard++ < 5) {
const outer = card.parentElement;
if (outer.querySelectorAll('a[href^="/url?"], a[href*="/url?q="]').length !== 1) {
break;
}
card = outer;
}
let description = "";
card.querySelectorAll("div, span, td").forEach(function(n) {
// (6.5.3) not the link itself: its title and address aren't the description
if (n.querySelector("a") || n.contains(a) || a.contains(n)) {
return;
}
const t = (n.textContent || "").replace(/\s+/g, " ").trim();
if (t.length > description.length && t !== title && t.length > 20) {
description = n.innerHTML;
}
});
// (6.5.4) video results: the thumbnail beside the result, and "Duration: 25:59" under it
let thumbImg = null;
card.querySelectorAll("img").forEach(function(im) {
const w = parseInt(im.getAttribute("width") || im.style.width || "0", 10);
if (!thumbImg && !a.contains(im) && (!w || w > 30)) {
thumbImg = im;
}
});
const dur = /Duration:\s*([0-9]{1,2}(?::[0-9]{2}){1,2})/.exec(card.textContent || "");
if (dur) {
const cut = description.search(/( \s*)?Duration:/i);
if (cut > 0) {
description = description.slice(0, cut);
}
}
seen[href] = true;
out.push({ href: href, title: title, description: description, thumbImg: thumbImg, duration: dur ? dur[1] : "" });
});
return out;
}
function ugfParseBasic() {
const results = ugfFindBasicResults();
let itemNo = 0;
results.forEach(function(r) {
if (location === "videos" && r.thumbImg) {
// (6.5.4) the Videos tab of the lightweight page: video results with their thumbnails
let thumb = r.thumbImg.getAttribute("src") || "";
const yt = ugfExtractYtId(r.href);
if ((!thumb || thumb.indexOf("data:image/gif") > -1 || thumb.length < 100) && yt) {
thumb = "https://i.ytimg.com/vi/" + yt + "/mqdefault.jpg";
}
linkList.push({videoResult: {
itemNo: itemNo,
type: "video",
href: r.href,
title: ugfNewsBold(r.title),
unmoddedTitle: r.title,
description: r.description || "",
thumbnail: thumb,
duration: r.duration || "",
origImg: r.thumbImg,
origImgId: r.thumbImg.id || ""
}});
createItem(linkList[linkList.length - 1], "videoResult");
itemNo++;
return;
}
linkList.push({searchResult: {
itemNo: itemNo,
type: "result",
href: r.href,
title: ugfNewsBold(r.title),
unmoddedTitle: r.title,
description: r.description || ""
}});
createItem(linkList[linkList.length - 1], "searchResult");
itemNo++;
});
if (itemNo > 0) {
document.querySelector("html").setAttribute("results-arrived", "");
}
return itemNo;
}
function ugfShopFallback(why) {
const h = document.querySelector("html");
if (!h.hasAttribute("shopping-results")) {
return;
}
console.log("[Gplex] Shopping: " + why + "; showing Google's page instead");
const shell = document.querySelector("#ugf");
if (shell) {
shell.remove();
}
h.removeAttribute("shopping-loading");
h.removeAttribute("shopping-results");
h.removeAttribute("shopping-browse");
h.removeAttribute("gplex");
h.setAttribute("disabled", "");
}
function ugfShopWatchdog() {
setTimeout(function() {
if (document.querySelector(".ugf-shop-result")) {
return;
}
const found = ugfFindShoppingCards().length;
const h = document.querySelector("html");
console.log("[Gplex] Shopping watchdog: cards=" + found +
", confirmed-sv=" + h.hasAttribute("confirmed-sv") +
", shell=" + !!document.querySelector("#ugf") +
", inputs=" + document.querySelectorAll("input, textarea").length);
if (found) {
// the page is readable, the normal path just never got there
try {
started = false;
parseHTMLNeo("shopping");
return;
} catch (e) {
console.log("[Gplex] Shopping watchdog parse failed", e);
}
}
ugfShopFallback("nothing rendered after 20s");
}, 20000);
}
function ugfShopEnsureShell() {
if (!document.body) {
return;
}
if (!document.querySelector("textarea") && !document.querySelector("input")) {
const ta = document.createElement("textarea");
ta.style.display = "none";
try {
ta.value = new URLSearchParams(window.location.search).get("q") || "";
} catch (e) {}
document.body.appendChild(ta);
}
if (!document.querySelector("#result-stats")) {
const rs = document.createElement("div");
rs.id = "result-stats";
rs.style.display = "none";
rs.innerHTML = trusted_policy.createHTML(" ");
document.body.appendChild(rs);
}
}
function ugfParseShopping() {
const cards = ugfFindShoppingCards();
if (!cards.length) {
// nothing we can read (the "For you" browse page is mostly widgets) - hand the page back to Google
ugfShopFallback("no product cards found");
return;
}
document.querySelector("html").removeAttribute("shopping-loading");
let itemNo = 0;
cards.forEach(function(card) {
linkList.push({shoppingResult: {
itemNo: itemNo,
type: "shopping",
href: card.href,
title: card.title,
price: card.price,
merchant: card.merchant,
rating: card.rating,
thumbnail: card.thumbnail,
origImg: card.origImg
}});
createItem(linkList[linkList.length - 1], "shoppingResult");
itemNo++;
});
if (itemNo > 0) {
document.querySelector("html").setAttribute("results-arrived", "");
}
ugfShoppingNav();
}
function ugfShoppingNav() {
["#ugf-all-tab", "#ugf-all-item", "#gp-gbar-search"].forEach(function(sel) {
const e = document.querySelector(sel);
if (e) {
e.classList.remove("active");
}
});
// light up whichever era link stands for Shopping (Froogle before 2011)
document.querySelectorAll("#ugf-era-nav a, .ugf-era-nav a, #ugf-top a, .ugf-tab").forEach(function(a) {
const t = (a.textContent || "").trim();
if (ugfIsShoppingLink(t) || t === ugfT("Froogle") || t === ugfT("Shopping")) {
a.classList.add("active");
} else if (t === "Web" || t === "All" || t === ugfT("Web") || t === ugfT("All")) {
a.classList.remove("active");
}
});
}
function ugfRenderShoppingItem(item) {
const container = document.querySelector("#ugf-search-results-container");
if (!container) {
return;
}
const el = document.createElement("div");
el.className = "ugf-search-result ugf-shop-result";
const hasThumb = item.thumbnail && item.thumbnail.indexOf("data:image/gif") !== 0;
el.innerHTML = trusted_policy.createHTML(
'' +
(hasThumb ? '
' : '
') +
'
' +
'
' + ugfEscapeHtml(item.title) + ' ' +
(item.price ? '
' + ugfEscapeHtml(item.price) + '
' : '') +
(item.merchant ? '
' + ugfEscapeHtml(item.merchant) + '
' : '') +
(item.rating ? '
' + ugfEscapeHtml(item.rating) + '
' : '') +
'
' +
'
');
container.insertBefore(el, container.children[item.itemNo] || null);
if (!hasThumb && item.origImg) {
let tries = 0;
const t = setInterval(function() {
tries++;
const src = ugfNewsThumbSrc(item.origImg);
if (src) {
clearInterval(t);
const a = document.createElement("a");
a.className = "ugf-shop-thumb";
a.href = item.href;
const img = document.createElement("img");
img.src = src;
a.appendChild(img);
const inner = el.querySelector(".ugf-shop-result-inner");
const ph = inner.querySelector(".ugf-shop-thumb-empty");
if (ph) {
inner.replaceChild(a, ph);
} else {
inner.insertBefore(a, inner.firstChild);
}
} else if (tries >= 100) {
clearInterval(t);
}
}, 150);
}
}
function ugfNewsPickThumb(container, card) {
let best = null;
let bestScore = -1;
container.querySelectorAll("img").forEach(function(img) {
if (img.closest('[role="heading"]')) {
return;
}
const aw = parseInt(img.getAttribute("width") || "0", 10);
const ah = parseInt(img.getAttribute("height") || "0", 10);
const nw = img.naturalWidth || 0;
const st = (img.getAttribute("style") || "") + " " + (img.parentElement ? img.parentElement.getAttribute("style") || "" : "");
const sw = parseInt((st.match(/width:\s*(\d+)px/) || [0, 0])[1], 10);
const size = Math.max(aw, ah, nw > 1 ? nw : 0, sw);
if (size > 0 && size < 36) {
return; // favicon
}
const src = img.getAttribute("src") || "";
if (/favicon|faviconV2|\/s2\/favicons/.test(src)) {
return;
}
const afterHeading = card.heading.compareDocumentPosition(img) & Node.DOCUMENT_POSITION_FOLLOWING;
let score = size;
if (/^dimg_/.test(img.id || "")) {
score += 1000;
}
if (afterHeading) {
score += 500;
}
if (size === 0 && !afterHeading && !/^dimg_/.test(img.id || "")) {
score = 1; // unknown size before the headline: only if nothing better
}
if (score > bestScore) {
best = img;
bestScore = score;
}
});
return best;
}
function ugfNewsThumbSrc(img) {
const ok = function(v) {
return v && v.indexOf("data:image/gif") !== 0 && v.length >= 40 ? v : "";
};
return ok(img.getAttribute("src") || "") ||
ok(ugfGetDeferredImage(img.id)) ||
ok(img.getAttribute("data-src") || "") ||
ok(img.getAttribute("data-iurl") || "") ||
ok(((img.getAttribute("srcset") || img.getAttribute("data-srcset") || "").split(",")[0] || "").trim().split(" ")[0]) ||
ok(img.currentSrc || "");
}
function ugfParseNews() {
const cards = ugfFindNewsCards(document);
let itemNo = 0;
cards.forEach(function(card) {
const container = ugfNewsCardContainer(card, cards);
const title = card.heading.textContent.replace(/\s+/g, " ").trim();
const blocks = ugfNewsTextBlocks(container).filter(function(b) {
return !card.heading.contains(b.el) && b.text !== title;
});
let source = "";
let time = "";
let snippet = "";
blocks.forEach(function(b) {
const before = card.heading.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_PRECEDING;
if (before) {
if (!source && b.text.length < 80) {
source = b.text;
}
} else if ((UGF_NEWS_TIME_RE.test(b.text) || UGF_NEWS_TIME_RE_INTL.test(b.text)) && b.text.length < 40) {
time = b.text;
} else if (b.text.length > snippet.length) {
snippet = b.text;
}
});
if (!source) {
try {
source = new URL(card.href).hostname.replace(/^www\./, "");
} catch (e) {}
}
const imgEl = ugfNewsPickThumb(container, card);
const thumb = imgEl ? ugfNewsThumbSrc(imgEl) : "";
if (!imgEl && container.querySelector("img")) {
console.log("[Gplex] News: no thumbnail picked in card", card.href);
}
linkList.push({newsResult: {
itemNo: itemNo,
type: "news",
href: card.href,
title: title,
source: source,
time: time,
description: snippet,
thumbnail: thumb,
origImg: imgEl
}});
createItem(linkList[linkList.length - 1], "newsResult");
itemNo++;
});
if (itemNo > 0) {
document.querySelector("html").setAttribute("results-arrived", "");
}
}
function ugfRenderNewsItem(item) {
const container = document.querySelector("#ugf-search-results-container");
if (!container) {
return;
}
const el = document.createElement("div");
el.className = "ugf-search-result ugf-news-result";
const meta = [item.source, item.time].filter(Boolean).map(ugfEscapeHtml).join(' - ');
const hasThumb = item.thumbnail && item.thumbnail.indexOf("data:image/gif") !== 0;
el.innerHTML = trusted_policy.createHTML(
'');
container.insertBefore(el, container.children[item.itemNo] || null);
if (!hasThumb && item.origImg) {
let tries = 0;
try {
item.origImg.loading = "eager";
} catch (e) {}
const t = setInterval(function() {
tries++;
const src = ugfNewsThumbSrc(item.origImg);
if (src) {
clearInterval(t);
const a = document.createElement("a");
a.className = "ugf-news-result-thumb";
a.href = item.href;
const img = document.createElement("img");
img.src = src;
a.appendChild(img);
el.querySelector(".ugf-news-result-inner").appendChild(a);
} else if (tries >= 100) {
clearInterval(t);
console.log("[Gplex] News: no thumbnail found for", item.href, item.origImg.outerHTML.slice(0, 300));
}
}, 150);
}
}
// ---- 2000-2005 results pages, measured from Dec 2000 / Nov 2002 / Apr 2003 captures ----
function ugfClassicEras() {
return ["gplex2000", "gplex2001", "gplex2002", "gplex2003"];
}
function ugfClassicSerpActive() {
const h = document.querySelector("html");
const loc = h.getAttribute("location") || "";
return ugfClassicEras().indexOf(ugfRetroEra()) > -1 && loc !== "gplex" && !/home$/.test(loc);
}
function ugfClassicResultsLine() {
const span = document.querySelector("#ugf-search-results-header span");
if (!span || span.getAttribute("data-classic")) {
return;
}
const txt = span.textContent || "";
const nums = txt.match(/\d[\d., ]*\d|\d/g);
const count = nums && nums.length ? nums[0].trim() : "";
const secs = nums && nums.length > 1 ? nums[nums.length - 1].trim() : "";
let first = 0;
try {
first = parseInt(new URLSearchParams(window.location.search).get("start") || "0", 10) || 0;
} catch (e) {}
first = first + 1;
const q = ugfEscapeHtml(searchValue || "");
const onNews = document.querySelector("html").hasAttribute("news-results");
const onImagesPage = document.querySelector("html").getAttribute("location") === "images";
let right = "Results " + first + " - " + (first + 9) + " " + (count ? " of about " + ugfEscapeHtml(count) + " " : "") + ".";
if (secs) {
right += " Search took " + ugfEscapeHtml(secs) + " seconds.";
}
span.setAttribute("data-classic", "1");
span.innerHTML = trusted_policy.createHTML('Searched ' + (onNews ? "news" : (onImagesPage ? "images" : "the web")) + ' for ' + q + ' . ' + right + ' ');
}
function ugfClassicUrlLines(root) {
(root || document).querySelectorAll("#ugf-search-results-container .ugf-search-result:not([data-classic-url])").forEach(function(res) {
const link = res.querySelector(".ugf-search-result-link");
const inner = res.querySelector(".ugf-search-result-inner") || res;
if (!link) {
return;
}
res.setAttribute("data-classic-url", "1");
const href = link.getAttribute("href") || "";
let shown = href.replace(/^https?:\/\//, "");
if (shown.length > 60) {
shown = shown.slice(0, 57) + "...";
}
const line = document.createElement("div");
line.className = "ugf-classic-urlline";
const u = document.createElement("span");
u.className = "ugf-classic-url";
u.textContent = shown;
line.appendChild(u);
const add = function(label, url) {
line.appendChild(document.createTextNode(" - "));
const a = document.createElement("a");
a.className = "ugf-classic-sub";
a.href = url;
a.textContent = label;
line.appendChild(a);
};
add("Cached", "https://web.archive.org/web/2/" + href);
add("Similar pages", "https://www.google.com/search?q=" + encodeURIComponent("related:" + href.replace(/^https?:\/\//, "")));
inner.appendChild(line);
});
}
// 2000-2005 results footer, from the Apr 2003 capture: Result Page label, bottom search box,
// "Dissatisfied?" line, blue link bar and copyright.
function ugfClassicFooter() {
const h = document.querySelector("html");
if (h.getAttribute("location") === "images" || document.querySelector("#ugf-classic-bottom")) {
return;
}
const era = ugfRetroEra();
const year = { gplex2000: "2000", gplex2001: "2001", gplex2002: "2002", gplex2003: "2003", gplex2005: "2005" }[era] || "2003";
let q = "";
try {
q = new URLSearchParams(window.location.search).get("q") || "";
} catch (e) {}
ugf2009WaitFor("#ugf-footer", function(footer) {
if (document.querySelector("#ugf-classic-bottom")) {
return;
}
const box = document.createElement("div");
box.id = "ugf-classic-bottom";
const row = document.createElement("div");
row.className = "ugf-cb-search";
const input = document.createElement("input");
input.type = "text";
input.value = q;
const go = function(query) {
if (query.trim()) {
window.location = "https://www.google.com/search?q=" + encodeURIComponent(query.trim());
}
};
input.addEventListener("keydown", function(ev) {
if (ev.key === "Enter") {
go(input.value);
}
});
const btn = document.createElement("button");
btn.textContent = "Google Search";
btn.addEventListener("click", function() {
go(input.value);
});
const within = document.createElement("a");
within.href = "#";
within.textContent = "Search within results";
within.addEventListener("click", function(ev) {
ev.preventDefault();
const extra = input.value.trim() === q.trim() ? "" : input.value.trim();
go(extra ? q + " " + extra : q);
});
row.appendChild(input);
row.appendChild(btn);
row.appendChild(within);
const dis = document.createElement("div");
dis.className = "ugf-cb-dissatisfied";
dis.appendChild(document.createTextNode("Dissatisfied with your search results? "));
const help = document.createElement("a");
help.href = "https://support.google.com/websearch";
help.textContent = "Help us improve.";
dis.appendChild(help);
const bar = document.createElement("div");
bar.className = "ugf-cb-bar";
[["Google Home", "https://www.google.com/"], ["Advertise with Us", "https://ads.google.com/"], ["Business Solutions", "https://www.google.com/services/"], ["Services & Tools", "https://www.google.com/intl/en/options/"], ["Jobs, Press, & Help", "https://about.google/"]].forEach(function(l, i) {
if (i > 0) {
bar.appendChild(document.createTextNode(" - "));
}
const a = document.createElement("a");
a.href = l[1];
a.textContent = l[0];
bar.appendChild(a);
});
const copy = document.createElement("div");
copy.className = "ugf-cb-copy";
copy.textContent = "©" + year + " Google";
box.appendChild(row);
box.appendChild(dis);
box.appendChild(bar);
box.appendChild(copy);
footer.appendChild(box);
});
}
function ugfClassicSerp() {
const loc0 = document.querySelector("html").getAttribute("location") || "";
if (ugfRetroEra() === "gplex2005" && loc0 !== "gplex" && loc0 !== "images" && !/home$/.test(loc0)) {
document.querySelector("html").setAttribute("era-urlline", "");
ugf2009WaitFor("#ugf-search-results-container", function(container) {
ugfClassicUrlLines(container);
new MutationObserver(function() {
ugfClassicUrlLines(container);
}).observe(container, { childList: true });
});
}
if (!ugfClassicSerpActive()) {
return;
}
const era = ugfRetroEra();
const h = document.querySelector("html");
h.setAttribute("era-serp-classic", era === "gplex2000" || era === "gplex2001" ? "notabs" : "tabs");
const q = searchValue || (function() {
try {
return new URLSearchParams(window.location.search).get("q") || "";
} catch (e) {
return "";
}
})();
ugf2009WaitFor("#ugf-topbar #ugf-search", function(searchEl) {
const outer = searchEl.parentElement;
if (!outer.querySelector("#ugf-classic-links")) {
const row = document.createElement("div");
row.id = "ugf-classic-links";
const links = [["Advanced Search", "https://www.google.com/advanced_search?q=" + encodeURIComponent(q)], ["Preferences", "https://www.google.com/preferences"]];
if (h.getAttribute("era-serp-classic") === "tabs") {
links.push(["Language Tools", "https://www.google.com/language_tools"]);
}
links.push(["Search Tips", "https://www.google.com/intl/en/help/basics.html"]);
links.forEach(function(l) {
const a = document.createElement("a");
a.href = l[1];
a.textContent = l[0];
row.appendChild(a);
});
outer.insertBefore(row, searchEl);
}
});
ugf2009WaitFor("#ugf-topbar #ugf-search .searchbtn-small", function(btn) {
btn.textContent = "Google Search";
if (h.getAttribute("era-serp-classic") === "notabs" && !btn.parentElement.querySelector(".ugf-classic-lucky")) {
const lucky = document.createElement("button");
lucky.className = "searchbtn-small ugf-classic-lucky";
lucky.textContent = "I'm Feeling Lucky";
lucky.addEventListener("click", function() {
const v = document.querySelector("#ugf-search-value").value;
window.location = "https://www.google.com/search?q=" + encodeURIComponent(v) + "&btnI=I%27m+Feeling+Lucky";
});
btn.parentElement.appendChild(lucky);
}
});
if (h.getAttribute("era-serp-classic") === "tabs") {
ugf2009WaitFor("#ugf-topbar .ugf-era-nav", function(nav) {
const header = document.querySelector("#ugf-search-results-header");
if (!header) {
return;
}
nav.classList.add("ugf-classic-tabs");
const more = nav.querySelector("a.more");
if (more) {
more.remove();
}
if (era === "gplex2002" && !Array.from(nav.querySelectorAll("a")).some(function(a) { return a.textContent.trim() === "News"; })) {
const news = document.createElement("a");
news.href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&tbm=nws";
news.textContent = "News";
news.className = "ugf-classic-wide";
if (document.querySelector("html").hasAttribute("news-results")) {
nav.querySelectorAll("a.active").forEach(function(a) { a.classList.remove("active"); });
news.classList.add("active");
}
nav.appendChild(news);
}
const mainInner = document.querySelector("#ugf-main-inner");
if (mainInner) {
mainInner.insertBefore(header, mainInner.firstChild);
}
header.parentElement.insertBefore(nav, header);
});
} else {
ugf2009WaitFor("#ugf-search-results-header", function(header) {
const mainInner = document.querySelector("#ugf-main-inner");
if (mainInner && header.parentElement !== mainInner) {
mainInner.insertBefore(header, mainInner.firstChild);
}
});
}
ugfClassicFooter();
ugf2009WaitFor("#ugf-search-results-container", function(container) {
ugfClassicUrlLines(container);
new MutationObserver(function() {
ugfClassicUrlLines(container);
}).observe(container, { childList: true });
});
}
function ugfEscapeHtml(t) {
return String(t == null ? "" : t)
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """);
}
function ugfParseResultsFrom(doc) {
const out = [];
const heads = doc.querySelectorAll("h3");
heads.forEach(function(h) {
const a = h.closest("a[href]");
if (!a) {
return;
}
let href = a.getAttribute("href") || "";
if (href.indexOf("/url?") === 0) {
try {
href = new URLSearchParams(href.split("?")[1]).get("q") || href;
} catch (e) {}
}
if (href.indexOf("http") !== 0) {
return;
}
if (href.indexOf("google.com/search") > -1) {
return;
}
const title = (h.textContent || "").trim();
if (!title) {
return;
}
let desc = "";
let block = a.closest("div[data-hveid]") || a.parentElement;
for (let hop = 0; hop < 4 && block; hop++) {
const spans = block.querySelectorAll("div > span, div[data-sncf] span");
for (let i = 0; i < spans.length; i++) {
const t = (spans[i].textContent || "").trim();
if (t.length > 40 && t.indexOf(title) === -1) {
desc = t;
break;
}
}
if (desc) {
break;
}
block = block.parentElement;
}
out.push({ title: title, href: href, desc: desc });
});
return out;
}
// 1997-1998: the "N results" dropdown limits how many result pages the Goooogle pager offers
// (10 results = page 1 only, 30 = pages 1-3, 100 = pages 1-10).
function ugfEraPageLimit() {
const era = ugfRetroEra();
if (era !== "gplex1997" && era !== "gplex1998") {
return;
}
let num = 10;
let start = 0;
try {
const sp = new URLSearchParams(window.location.search);
num = parseInt(sp.get("num") || "", 10) || parseInt(localStorage.getItem("UGF_ERA_NUM") || "10", 10) || 10;
start = parseInt(sp.get("start") || "0", 10) || 0;
} catch (e) {}
const maxPages = Math.max(1, Math.min(10, Math.round(num / 10)));
const curPage = Math.floor(start / 10) + 1;
const h = document.querySelector("html");
h.setAttribute("era-max-pages", String(maxPages));
if (curPage >= maxPages) {
h.setAttribute("era-last-page", "");
}
}
// ---- Reverse image search (Google Lens) themed as "Search by image" (2011-2016) / "Google Lens" (2017+) ----
// Google's Lens page stays visible until enough visual matches are found; if parsing fails it is left untouched.
// ---- "Search by image" (2011-2016) and "Google Lens" (2017+) entry: camera icon + panel, no Google page needed ----
const UGF_CAMERA_SVG = ' ';
function ugfSbiSearchUrl(u) {
u = (u || "").trim();
if (!/^https?:\/\//i.test(u)) {
return false;
}
window.location = "https://lens.google.com/uploadbyurl?url=" + encodeURIComponent(u);
return true;
}
function ugfSbiUploadForm() {
const form = document.createElement("form");
form.method = "POST";
form.enctype = "multipart/form-data";
form.style.display = "none";
const file = document.createElement("input");
file.type = "file";
file.name = "encoded_image";
file.accept = "image/*";
form.appendChild(file);
const send = function() {
if (!file.files || !file.files.length) {
return;
}
form.action = "https://lens.google.com/v3/upload?hl=" + encodeURIComponent(UGF_LANG_HL) + "&re=df&ep=gsbubb&st=" + Date.now();
form.submit();
};
file.addEventListener("change", send);
return { form: form, file: file, send: send };
}
function ugfSbiHandleDrop(ev, up) {
ev.preventDefault();
const dt = ev.dataTransfer;
if (!dt) {
return;
}
if (dt.files && dt.files.length) {
try {
up.file.files = dt.files;
up.send();
return;
} catch (e) {}
}
const uri = (dt.getData("text/uri-list") || dt.getData("text/plain") || "").split("\n")[0];
ugfSbiSearchUrl(uri);
}
function ugfSbiBuildPanel(style) {
const panel = document.createElement("div");
panel.id = "ugf-sbi-panel";
panel.className = "ugf-sbi-" + style;
const up = ugfSbiUploadForm();
panel.appendChild(up.form);
const close = document.createElement("a");
close.className = "ugf-sbi-close";
close.href = "#";
close.textContent = "×";
close.addEventListener("click", function(ev) {
ev.preventDefault();
panel.remove();
});
if (style === "sbi") {
const title = document.createElement("div");
title.className = "ugf-sbi-title";
title.textContent = "Search by image";
const desc = document.createElement("div");
desc.className = "ugf-sbi-desc";
desc.textContent = "Search Google with an image instead of text. Try dragging an image here.";
const tabs = document.createElement("div");
tabs.className = "ugf-sbi-tabs";
const tUrl = document.createElement("a");
tUrl.href = "#";
tUrl.textContent = "Paste image URL";
tUrl.className = "active";
const tUp = document.createElement("a");
tUp.href = "#";
tUp.textContent = "Upload an image";
tabs.appendChild(tUrl);
tabs.appendChild(tUp);
const bodyUrl = document.createElement("div");
bodyUrl.className = "ugf-sbi-body";
const inp = document.createElement("input");
inp.type = "text";
const btn = document.createElement("button");
btn.textContent = "Search by image";
btn.addEventListener("click", function() { ugfSbiSearchUrl(inp.value); });
inp.addEventListener("keydown", function(ev) {
if (ev.key === "Enter") {
ugfSbiSearchUrl(inp.value);
}
});
bodyUrl.appendChild(inp);
bodyUrl.appendChild(btn);
const bodyUp = document.createElement("div");
bodyUp.className = "ugf-sbi-body";
bodyUp.style.display = "none";
const pick = document.createElement("button");
pick.className = "ugf-sbi-choose";
pick.textContent = "Choose File";
const none = document.createElement("span");
none.className = "ugf-sbi-none";
none.textContent = "No file chosen";
pick.addEventListener("click", function() { up.file.click(); });
up.file.addEventListener("change", function() {
if (up.file.files && up.file.files[0]) {
none.textContent = up.file.files[0].name;
}
});
bodyUp.appendChild(pick);
bodyUp.appendChild(none);
tUrl.addEventListener("click", function(ev) {
ev.preventDefault();
tUrl.className = "active";
tUp.className = "";
bodyUrl.style.display = "";
bodyUp.style.display = "none";
});
tUp.addEventListener("click", function(ev) {
ev.preventDefault();
tUp.className = "active";
tUrl.className = "";
bodyUp.style.display = "";
bodyUrl.style.display = "none";
});
panel.appendChild(close);
panel.appendChild(title);
panel.appendChild(desc);
panel.appendChild(tabs);
panel.appendChild(bodyUrl);
panel.appendChild(bodyUp);
setTimeout(function() { inp.focus(); }, 0);
} else {
const title = document.createElement("div");
title.className = "ugf-sbi-title";
title.textContent = "Search any image with Google Lens";
const drop = document.createElement("div");
drop.className = "ugf-sbi-drop";
drop.innerHTML = trusted_policy.createHTML('' + UGF_CAMERA_SVG + '
');
drop.querySelector(".ugf-sbi-upload").addEventListener("click", function(ev) {
ev.preventDefault();
up.file.click();
});
const or = document.createElement("div");
or.className = "ugf-sbi-or";
or.innerHTML = trusted_policy.createHTML("OR ");
const row = document.createElement("div");
row.className = "ugf-sbi-body";
const inp = document.createElement("input");
inp.type = "text";
inp.placeholder = "Paste image link";
const btn = document.createElement("button");
btn.textContent = "Search";
btn.addEventListener("click", function() { ugfSbiSearchUrl(inp.value); });
inp.addEventListener("keydown", function(ev) {
if (ev.key === "Enter") {
ugfSbiSearchUrl(inp.value);
}
});
row.appendChild(inp);
row.appendChild(btn);
panel.appendChild(close);
panel.appendChild(title);
panel.appendChild(drop);
panel.appendChild(or);
panel.appendChild(row);
}
panel.addEventListener("dragover", function(ev) {
ev.preventDefault();
panel.classList.add("ugf-sbi-dragging");
});
panel.addEventListener("dragleave", function() {
panel.classList.remove("ugf-sbi-dragging");
});
panel.addEventListener("drop", function(ev) {
panel.classList.remove("ugf-sbi-dragging");
ugfSbiHandleDrop(ev, up);
});
return panel;
}
function ugfSbiCamera() {
const style = ugfLensStyle();
if (!style) {
return;
}
const h = document.querySelector("html");
const loc = h.getAttribute("location") || "";
const onImages = loc === "images" || ugfHomeVertical === "images";
const lensEverywhere = h.hasAttribute("gplex2022") && /home$/.test(loc);
if (!onImages && !lensEverywhere && loc !== "lens") {
return;
}
const sel = /home$/.test(loc) ? "#ugf-hp-search #ugf-searchbar" : "#ugf-top #ugf-searchbar";
ugf2009WaitFor(sel, function(bar) {
if (bar.querySelector(".ugf-sbi-camera")) {
return;
}
h.setAttribute("sbi-camera", style);
const cam = document.createElement("a");
cam.href = "#";
cam.className = "ugf-sbi-camera";
cam.title = style === "lens" ? "Search by image (Google Lens)" : "Search by image";
cam.innerHTML = trusted_policy.createHTML(UGF_CAMERA_SVG);
cam.addEventListener("click", function(ev) {
ev.preventDefault();
const open = document.querySelector("#ugf-sbi-panel");
if (open) {
open.remove();
return;
}
const panel = ugfSbiBuildPanel(style);
bar.appendChild(panel);
});
bar.appendChild(cam);
});
}
function ugfLensStyle() {
const h = document.querySelector("html");
const era = ugfRetroEra();
if (era === "gplex2022") {
return "lens";
}
if (era) {
return null;
}
const layout = h.getAttribute("layout") || "";
if (["2017", "2018", "2018M", "2019"].indexOf(layout) > -1) {
return "lens";
}
if (["2011", "2012", "2013", "2013L", "2014", "2015", "2015L", "2016", "2016C", "2016L"].indexOf(layout) > -1) {
return "sbi";
}
return null;
}
function ugfLensDecodeHref(href) {
if (href.indexOf("/url?") === 0 || href.indexOf("https://www.google.com/url?") === 0) {
try {
const u = new URL(href, "https://www.google.com");
return u.searchParams.get("q") || u.searchParams.get("url") || href;
} catch (e) {}
}
return href;
}
function ugfLensImgSrc(img) {
let src = img.getAttribute("src") || "";
if (!src || src.indexOf("data:image/gif") === 0 || (src.indexOf("data:") === 0 && src.length < 100)) {
src = img.getAttribute("data-src") || ugfGetDeferredImage(img.id) || "";
}
return src;
}
function ugfFindLensCards() {
const out = [];
const seen = {};
document.querySelectorAll("a[href]").forEach(function(a) {
if (a.closest("#ugf")) {
return;
}
const href = ugfLensDecodeHref(a.getAttribute("href") || "");
if (!/^https?:\/\//.test(href) || seen[href]) {
return;
}
let host = "";
try {
host = new URL(href).hostname;
} catch (e) {
return;
}
if (/(^|\.)google\.[a-z.]+$/.test(host) || /gstatic\.com$|googleusercontent\.com$|googleadservices\.com$/.test(host)) {
return;
}
const img = a.querySelector("img");
if (!img) {
return;
}
const r = img.getBoundingClientRect();
const w = r.width || parseInt(img.getAttribute("width") || "0", 10);
if (w < 50) {
return;
}
const thumb = ugfLensImgSrc(img);
if (!thumb) {
return;
}
let title = (a.getAttribute("aria-label") || "").trim();
if (!title) {
const texts = [];
a.querySelectorAll("*").forEach(function(e) {
if (!e.children.length) {
const t = (e.textContent || "").replace(/\s+/g, " ").trim();
if (t.length > 3 && t.indexOf(host.replace(/^www\./, "")) === -1) {
texts.push(t);
}
}
});
texts.sort(function(x, y) { return y.length - x.length; });
title = texts[0] || img.getAttribute("alt") || host;
}
seen[href] = true;
out.push({ href: href, title: title, source: host.replace(/^www\./, ""), thumb: thumb });
});
return out;
}
function ugfFindLensQueryImage() {
let best = null;
let bestArea = 0;
document.querySelectorAll("img").forEach(function(img) {
if (img.closest("#ugf")) {
return;
}
const a = img.closest("a[href]");
if (a && /^https?:\/\//.test(ugfLensDecodeHref(a.getAttribute("href") || "")) && !/google\./.test(a.getAttribute("href") || "")) {
return;
}
const r = img.getBoundingClientRect();
const area = r.width * r.height;
if (r.width >= 80 && r.height >= 60 && area > bestArea && ugfLensImgSrc(img)) {
best = img;
bestArea = area;
}
});
return best;
}
function ugfLensTheme() {
const h = document.querySelector("html");
if (h.getAttribute("location") !== "lens") {
return;
}
const style = ugfLensStyle();
if (!style) {
return;
}
// show the themed shell straight away; Google's Lens page keeps rendering off-screen so it can be parsed
h.setAttribute("lens-page", style);
h.setAttribute("lens-loading", "");
h.removeAttribute("disabled");
ugfLensStartShell(style);
let polls = 0;
let lastCount = -1;
const timer = setInterval(function() {
polls++;
const cards = ugfFindLensCards();
const status = document.querySelector("#ugf-lens-loading");
if (status) {
status.textContent = "Loading... " + cards.length + " result" + (cards.length === 1 ? "" : "s") + " found";
}
const ready = (cards.length >= 4 && cards.length === lastCount) || (polls > 20 && cards.length >= 2);
lastCount = cards.length;
if (ready) {
clearInterval(timer);
ugfBuildLensPage(style, cards, ugfFindLensQueryImage());
} else if (polls > 40) {
clearInterval(timer);
console.log("[Gplex] Lens: only " + cards.length + " visual matches found; showing Google's page instead");
const shell = document.querySelector("#ugf");
if (shell) {
shell.remove();
}
h.removeAttribute("lens-loading");
h.removeAttribute("lens-page");
h.setAttribute("disabled", "");
}
}, 300);
}
function ugfLensImagesTab() {
["#ugf-all-tab", "#ugf-all-item", "#gp-gbar-search"].forEach(function(sel) {
const e = document.querySelector(sel);
if (e) {
e.classList.remove("active");
}
});
["#ugf-images-tab", "#ugf-images-item", "#gp-gbar-images"].forEach(function(sel) {
const e = document.querySelector(sel);
if (e) {
e.classList.add("active");
}
});
}
function ugfLensStartShell(style) {
const ensure = function() {
if (!document.body) {
return false;
}
if (!document.querySelector("textarea") && !document.querySelector("input")) {
const ta = document.createElement("textarea");
ta.style.display = "none";
document.body.appendChild(ta);
}
if (!document.querySelector("#result-stats")) {
const rs = document.createElement("div");
rs.id = "result-stats";
rs.style.display = "none";
rs.innerHTML = trusted_policy.createHTML(" ");
document.body.appendChild(rs);
}
return true;
};
ensure();
document.title = style === "lens" ? "Google Lens" : "Google Search by image";
createPageShell("lens");
ugf2009WaitFor("#ugf-search-results-container", function(container) {
if (container.querySelector("#ugf-lens")) {
return;
}
const load = document.createElement("div");
load.id = "ugf-lens-loading";
load.textContent = "Loading... 0 results found";
container.innerHTML = ugfTT("");
container.appendChild(load);
ugfLensImagesTab();
});
}
function ugfBuildLensPage(style, cards, qImg) {
const h = document.querySelector("html");
const qSrc = qImg ? ugfLensImgSrc(qImg) : "";
const qW = qImg ? (qImg.naturalWidth || 0) : 0;
const qH = qImg ? (qImg.naturalHeight || 0) : 0;
h.removeAttribute("lens-loading");
ugf2009WaitFor("#ugf-top #ugf-searchbar", function(bar) {
if (bar.querySelector(".ugf-lens-chip")) {
return;
}
const chip = document.createElement("span");
chip.className = "ugf-lens-chip";
if (qSrc) {
const ci = document.createElement("img");
ci.src = qSrc;
chip.appendChild(ci);
}
const lab = document.createElement("span");
lab.textContent = style === "lens" ? "Google Lens" : "image";
chip.appendChild(lab);
const x = document.createElement("a");
x.href = "https://www.google.com/imghp";
x.textContent = "×";
x.title = "Remove image";
chip.appendChild(x);
bar.insertBefore(chip, bar.firstChild);
const input = bar.querySelector("#ugf-search-value");
if (input) {
input.value = "";
input.placeholder = "";
}
});
ugf2009WaitFor("#ugf-search-results-container", function(container) {
const loadingNote = container.querySelector("#ugf-lens-loading");
if (loadingNote) {
loadingNote.remove();
}
const box = document.createElement("div");
box.id = "ugf-lens";
const top = document.createElement("div");
top.className = "ugf-lens-top";
if (qSrc) {
const qi = document.createElement("img");
qi.className = "ugf-lens-query";
qi.src = qSrc;
top.appendChild(qi);
}
const info = document.createElement("div");
info.className = "ugf-lens-info";
if (style === "lens") {
info.innerHTML = trusted_policy.createHTML('Google Lens
' + cards.length + ' visual matches
');
} else {
info.innerHTML = trusted_policy.createHTML('Search by image
' + (qW && qH ? 'Image size:
' + qW + " × " + qH + "
" : "") + '' + cards.length + " matches found
");
}
top.appendChild(info);
box.appendChild(top);
const grid = document.createElement("div");
grid.className = "ugf-lens-grid";
const head1 = document.createElement("div");
head1.className = "ugf-lens-heading";
head1.textContent = style === "lens" ? "Visual matches" : "Visually similar images";
box.appendChild(head1);
cards.slice(0, style === "lens" ? 60 : 16).forEach(function(c) {
const a = document.createElement("a");
a.className = "ugf-lens-card";
a.href = c.href;
a.title = c.title;
const im = document.createElement("img");
im.src = c.thumb;
a.appendChild(im);
if (style === "lens") {
const t = document.createElement("div");
t.className = "ugf-lens-card-title";
t.textContent = c.title;
const so = document.createElement("div");
so.className = "ugf-lens-card-source";
so.textContent = c.source;
a.appendChild(so);
a.appendChild(t);
}
grid.appendChild(a);
});
box.appendChild(grid);
if (style === "sbi") {
const head2 = document.createElement("div");
head2.className = "ugf-lens-heading";
head2.textContent = "Pages that include matching images";
box.appendChild(head2);
cards.slice(0, 10).forEach(function(c) {
const r = document.createElement("div");
r.className = "ugf-search-result ugf-lens-page-result";
r.innerHTML = trusted_policy.createHTML(
' ' +
'');
box.appendChild(r);
});
}
container.innerHTML = ugfTT("");
container.appendChild(box);
h.setAttribute("results-arrived", "");
ugfLensImagesTab();
});
}
function ugfContinuousScroll() {
if (!document.querySelector("html").hasAttribute("gplex2022")) {
return;
}
const loc = document.querySelector("html").getAttribute("location") || "";
if (loc === "home" || loc === "structured-home" || loc === "gplex" || loc === "news" || loc === "images") {
return;
}
ugf2009WaitFor("#ugf-search-results-container", function(container) {
let q = "";
let start = 0;
try {
const sp = new URLSearchParams(window.location.search);
q = sp.get("q") || "";
start = parseInt(sp.get("start") || "0", 10) || 0;
} catch (e) {
return;
}
if (!q) {
return;
}
let nextStart = start + 10;
let loading = false;
let pagesLoaded = 0;
const maxPages = 8;
const status = document.createElement("div");
status.className = "ugf-scroll-status";
container.parentElement.appendChild(status);
function loadMore() {
if (loading || pagesLoaded >= maxPages) {
return;
}
loading = true;
status.textContent = "Loading more results\u2026";
fetch("https://www.google.com/search?q=" + encodeURIComponent(q) + "&start=" + nextStart, { credentials: "same-origin" })
.then(function(r) { return r.text(); })
.then(function(html) {
const doc = new DOMParser().parseFromString(ugfTT(html), "text/html");
const results = ugfParseResultsFrom(doc);
if (!results.length) {
console.warn("[Gplex] continuous scroll: no results parsed from start=" + nextStart + " (Google markup may have changed)");
status.textContent = "";
pagesLoaded = maxPages;
return;
}
results.forEach(function(res) {
const el = document.createElement("div");
el.classList.add("ugf-search-result");
el.innerHTML = ugfTT(`
`);
container.appendChild(el);
});
nextStart += 10;
pagesLoaded++;
status.textContent = "";
loading = false;
})
.catch(function(err) {
console.warn("[Gplex] continuous scroll fetch failed:", err);
status.textContent = "";
loading = false;
pagesLoaded = maxPages;
});
}
window.addEventListener("scroll", function() {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 900) {
loadMore();
}
});
});
}
function ugfRetroFooter() {
const era = ugfRetroEra();
if (!era) {
return;
}
const conf = UGF_RETRO_CHROME[era];
if (!conf || !conf.footer) {
return;
}
ugf2009WaitFor("#ugf-structured-hp-footer-left", function(left) {
if (left.querySelector(".ugf-era-footer-link")) {
return;
}
Array.from(left.children).forEach(function(el) {
el.style.display = "none";
});
conf.footer.forEach(function(item, i) {
if (i > 0) {
const dash = document.createElement("span");
dash.className = "ugf-era-footer-dash";
dash.textContent = "-";
left.appendChild(dash);
}
const a = document.createElement("a");
a.className = "ugf-era-footer-link";
a.href = item[1];
a.textContent = item[0];
left.appendChild(a);
if (conf.footerBreakAfter && (i + 1) === conf.footerBreakAfter) {
left.appendChild(document.createElement("br"));
}
});
});
if (conf.copyright) {
ugf2009WaitFor("#ugf-structured-hp-footer-right", function(right) {
if (right.querySelector(".ugf-era-copyright")) {
return;
}
Array.from(right.children).forEach(function(el) {
el.style.display = "none";
});
const span = document.createElement("span");
span.className = "ugf-era-copyright";
span.textContent = conf.copyright;
right.appendChild(span);
});
}
}
function ugfRetroExtras() {
const era = ugfRetroEra();
if (!era) {
return;
}
const conf = UGF_RETRO_CHROME[era];
if (!conf) {
return;
}
const loc = document.querySelector("html").getAttribute("location") || "";
if (loc.indexOf("home") === -1) {
return;
}
ugf2009WaitFor("#ugf-hp-search", function(hpSearch) {
if (document.querySelector(".ugf-era-extras")) {
return;
}
const holder = document.createElement("div");
holder.className = "ugf-era-extras";
if (conf.indexNote) {
const note = document.createElement("div");
note.className = "ugf-era-index-note";
note.textContent = conf.indexNote;
hpSearch.appendChild(note);
}
if (conf.bigLink) {
const big = document.createElement("div");
big.className = "ugf-era-big-link";
const a = document.createElement("a");
a.href = conf.bigLink[1];
a.textContent = conf.bigLink[0];
big.appendChild(a);
holder.appendChild(big);
}
if (conf.extraLinks) {
const row = document.createElement("div");
row.className = "ugf-era-extra-links";
conf.extraLinks.forEach(function(item) {
const a = document.createElement("a");
a.href = item[1];
a.textContent = item[0];
row.appendChild(a);
});
holder.appendChild(row);
}
if (conf.subscribe) {
const box = document.createElement("div");
box.className = "ugf-era-subscribe";
const h = document.createElement("div");
h.className = "ugf-era-subscribe-heading";
h.textContent = conf.subscribe.heading;
box.appendChild(h);
const row = document.createElement("div");
row.className = "ugf-era-subscribe-row";
const input = document.createElement("input");
input.type = "text";
input.value = conf.subscribe.placeholder;
row.appendChild(input);
const btn = document.createElement("button");
btn.textContent = conf.subscribe.button;
row.appendChild(btn);
const arc = document.createElement("a");
arc.href = conf.subscribe.archiveHref;
arc.textContent = conf.subscribe.archive;
row.appendChild(arc);
box.appendChild(row);
holder.appendChild(box);
}
if (holder.children.length) {
hpSearch.parentElement.insertBefore(holder, hpSearch.nextSibling);
}
});
}
function ugfRetroLogoLinks() {
const era = ugfRetroEra();
if (!era) {
return;
}
const conf = UGF_RETRO_CHROME[era];
if (!conf || !conf.logoLinks) {
return;
}
const loc = document.querySelector("html").getAttribute("location") || "";
if (loc.indexOf("home") === -1) {
return;
}
ugf2009WaitFor("#ugf-hp-logo", function(logo) {
if (document.querySelector(".ugf-era-logo-links")) {
return;
}
const wrap = document.createElement("div");
wrap.className = "ugf-era-logo-links";
conf.logoLinks.forEach(function(item) {
const a = document.createElement("a");
a.href = item[1];
a.textContent = item[0];
wrap.appendChild(a);
});
logo.parentElement.insertBefore(wrap, logo.nextSibling);
});
}
function ugfRetroPromo() {
const era = ugfRetroEra();
if (!era) {
return;
}
const conf = UGF_RETRO_CHROME[era];
if (!conf || !conf.promo) {
return;
}
const loc = document.querySelector("html").getAttribute("location") || "";
if (loc.indexOf("home") === -1) {
return;
}
ugf2009WaitFor("#ugf-hp-search", function(hpSearch) {
if (document.querySelector(".ugf-era-promo")) {
return;
}
if (conf.indexLine) {
const idx = document.createElement("div");
idx.className = "ugf-era-index";
idx.textContent = conf.indexLine;
hpSearch.parentElement.insertBefore(idx, hpSearch.nextSibling);
}
const div = document.createElement("div");
div.className = "ugf-era-promo";
div.appendChild(document.createTextNode(conf.promo[0]));
const a = document.createElement("a");
a.href = conf.promo[2];
a.textContent = conf.promo[1];
div.appendChild(a);
div.appendChild(document.createTextNode(conf.promo[3] || ""));
hpSearch.parentElement.insertBefore(div, hpSearch.nextSibling);
if (conf.promoTagline) {
const tag = document.createElement("div");
tag.className = "ugf-era-promo-tagline";
tag.textContent = conf.promoTagline;
div.parentElement.insertBefore(tag, div.nextSibling);
}
});
}
function ugfRetroChrome() {
const era = ugfRetroEra();
if (!era) {
return;
}
const conf = UGF_RETRO_CHROME[era];
if (conf.navAbove) {
ugf2009WaitFor("#ugf-search", function(searchEl) {
if (document.querySelector(".ugf-era-nav") || document.querySelector(".ugf-era-count") || document.querySelector(".ugf-era-above-links")) {
return;
}
let q = "";
try {
q = new URLSearchParams(window.location.search).get("q") || "";
} catch (e) {
q = "";
}
const onImages = document.querySelector("html").getAttribute("location") === "images" || ugfHomeVertical === "images";
if (conf.aboveLinks) {
const row = document.createElement("div");
row.className = "ugf-era-above-links";
conf.aboveLinks.forEach(function(item, i) {
if (i > 0) {
const dash = document.createElement("span");
dash.textContent = " - ";
row.appendChild(dash);
}
const a = document.createElement("a");
a.href = item[1];
a.textContent = item[0];
row.appendChild(a);
});
searchEl.parentElement.insertBefore(row, searchEl);
}
if (conf.aboveBox) {
const line = document.createElement("div");
line.className = "ugf-era-count";
line.textContent = conf.aboveBox;
searchEl.parentElement.insertBefore(line, searchEl);
}
if (!conf.left || !conf.left.length) {
return;
}
const nav = document.createElement("div");
nav.className = "ugf-era-nav" + (conf.tabs ? " ugf-era-tabs" : "");
conf.left.forEach(function(item) {
let href = item[1];
if (q) {
if (item[0] === "Images") {
href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&udm=2";
} else if (item[0] === "News") {
href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&tbm=nws";
} else if (item[0] === "Web") {
href = "https://www.google.com/search?q=" + encodeURIComponent(q);
} else if (ugfIsShoppingLink(item[0])) {
href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&udm=28";
}
}
const a = document.createElement("a");
a.href = href;
a.textContent = item[0];
const onNewsTab = document.querySelector("html").hasAttribute("news-results");
const onVideoTab = ugfHomeVertical === "videos";
if ((onImages && item[0] === "Images") || (onNewsTab && item[0] === "News") || (onVideoTab && (item[0] === "Video" || item[0] === "Videos")) || (ugfOnShopping() && ugfIsShoppingLink(item[0])) || (!onImages && !onNewsTab && !onVideoTab && !ugfOnShopping() && item[0] === "Web")) {
a.className = "active";
}
nav.appendChild(a);
});
if (!conf.tabs) {
const moreLink = document.createElement("a");
moreLink.href = "https://www.google.com/intl/en/options/";
moreLink.className = "more";
moreLink.textContent = "more \u00bb";
nav.appendChild(moreLink);
}
searchEl.parentElement.insertBefore(nav, searchEl);
});
}
ugf2009WaitFor("#gp-gbar-inner", function(bar) {
if (conf.navAbove) {
const more2 = bar.querySelector("#gp-gbar-more");
Array.from(bar.children).forEach(function(el) {
if (el.classList && el.classList.contains("gp-gbar-link")) {
el.style.display = "none";
}
});
if (more2) {
more2.style.display = "none";
}
const right2 = bar.querySelector("#gp-gbar-right");
if (right2 && !right2.querySelector(".ugf-retro-gbar")) {
const anchor2 = right2.firstElementChild;
conf.right.forEach(function(item) {
const link = ugfRetroGbarLink(item[0], item[1], false);
const sep = document.createElement("span");
sep.className = "ugf-retro-gbar-sep";
sep.textContent = "|";
if (anchor2) {
right2.insertBefore(link, anchor2);
right2.insertBefore(sep, anchor2);
} else {
right2.appendChild(link);
right2.appendChild(sep);
}
});
}
return;
}
if (bar.querySelector(".ugf-retro-gbar")) {
return;
}
const more = bar.querySelector("#gp-gbar-more");
const right = bar.querySelector("#gp-gbar-right");
Array.from(bar.children).forEach(function(el) {
if (el.classList && el.classList.contains("gp-gbar-link") && el !== more) {
el.style.display = "none";
}
});
const onImages = document.querySelector("html").getAttribute("location") === "images" || ugfHomeVertical === "images";
const onVideoHome = ugfHomeVertical === "videos";
let q = "";
try {
q = new URLSearchParams(window.location.search).get("q") || "";
} catch (e) {
q = "";
}
conf.left.forEach(function(item) {
const onNews = document.querySelector("html").hasAttribute("news-results");
const onShopping = ugfOnShopping();
const isActive = (onImages && item[0] === "Images") || (onNews && item[0] === "News") || (onVideoHome && (item[0] === "Video" || item[0] === "Videos")) || (onShopping && ugfIsShoppingLink(item[0])) || (!onImages && !onNews && !onVideoHome && !onShopping && item[0] === "Web");
let href = item[1];
if (q) {
if (item[0] === "Images") {
href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&udm=2";
} else if (item[0] === "Video" || item[0] === "Videos") {
href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&tbm=vid";
} else if (item[0] === "News") {
href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&tbm=nws";
} else if (item[0] === "Web") {
href = "https://www.google.com/search?q=" + encodeURIComponent(q);
} else if (ugfIsShoppingLink(item[0])) {
href = "https://www.google.com/search?q=" + encodeURIComponent(q) + "&udm=28";
}
}
const link = ugfRetroGbarLink(item[0], href, isActive);
if (more) {
bar.insertBefore(link, more);
} else {
bar.appendChild(link);
}
});
if (more) {
const moreSpan = more.querySelector(".gp-gbar-link-inner span");
if (moreSpan) {
moreSpan.textContent = "more";
}
}
if (right) {
const anchorEl = right.firstElementChild;
conf.right.forEach(function(item) {
const link = ugfRetroGbarLink(item[0], item[1], false);
const sep = document.createElement("span");
sep.className = "ugf-retro-gbar-sep";
sep.textContent = "|";
if (anchorEl) {
right.insertBefore(link, anchorEl);
right.insertBefore(sep, anchorEl);
} else {
right.appendChild(link);
right.appendChild(sep);
}
});
}
});
}
function ugf2009WaitFor(selector, callback) {
let tries = 0;
const interval = setInterval(function() {
const element = document.querySelector(selector);
if (element) {
clearInterval(interval);
callback(element);
} else if (++tries > 150) {
clearInterval(interval);
}
}, 100);
}
// Classic Google put the buttons in the same centred cell as the search box (input buttons)
function ugfEraHomeButtons() {
const era = ugfRetroEra();
if (!era || era === "gplex2010" || era === "gplex2022") {
return;
}
const loc = document.querySelector("html").getAttribute("location") || "";
if (!/home$/.test(loc)) {
return;
}
if (era === "gplex2009") {
ugf2009WaitFor("#ugf-structured-hp-footer-left .ugf-structured-hp-footer-link", function() {
const labels = ["Advertising Programs", "Business Solutions", "About Google"];
document.querySelectorAll("#ugf-structured-hp-footer-left .ugf-structured-hp-footer-link").forEach(function(a, i) {
if (labels[i]) {
a.textContent = labels[i];
}
});
});
}
ugf2009WaitFor("#ugf-hp-search #ugf-search-outer", function(outer) {
const row = document.querySelector("#ugf-hp-buttons-row");
if (row && row.parentElement !== outer) {
outer.appendChild(row);
}
});
}
// imghp / videohp: logo label, button labels, active tabs
function ugfVerticalHome() {
if (!ugfHomeVertical) {
return;
}
const isImages = ugfHomeVertical === "images";
const isShopping = ugfHomeVertical === "shopping";
const shopEra = ugfRetroEra();
const froogle = ["gplex2003", "gplex2005", "gplex2006"].indexOf(shopEra) > -1;
const productSearch = shopEra === "gplex2007";
const shopName = froogle ? "Froogle" : (productSearch ? "Product Search" : "Shopping");
document.title = isShopping ? (froogle ? "Froogle" : (productSearch ? "Google Product Search" : "Google Shopping")) : (isImages ? "Google Images" : "Google Videos");
ugf2009WaitFor("#ugf-hp-logo-companion", function(comp) {
if (!comp.querySelector("#ugf-hp-vertical-label")) {
const lab = document.createElement("div");
lab.id = "ugf-hp-vertical-label";
const old = document.querySelector("html").hasAttribute("legacy-gbar");
if (isShopping) {
lab.textContent = (froogle || productSearch) ? shopName : (old ? "Shopping" : "shopping");
} else {
lab.textContent = isImages ? (old ? "Images" : "images") : (old ? "Video" : "videos");
}
comp.appendChild(lab);
}
});
const label = isShopping ? (productSearch ? "Search Products" : "Search " + shopName) : (isImages ? "Search Images" : "Search Video");
ugf2009WaitFor("#ugf-hp-buttons", function(row) {
const relabel = function() {
const retro = row.querySelectorAll("button.searchbtn");
if (retro.length) {
retro[0].textContent = label;
for (let i = 1; i < retro.length; i++) {
retro[i].style.display = "none";
}
}
const s2 = document.querySelector("#ugf-search-btn-2 span");
if (s2) {
s2.textContent = label;
}
return retro.length;
};
relabel();
let n = 0;
const t = setInterval(function() {
n++;
if (relabel() || n > 30) {
clearInterval(t);
}
}, 100);
});
if (isShopping) {
ugf2009WaitFor("#ugf-top, #ugf-hp-search", function() {
ugfShoppingNav();
setTimeout(ugfShoppingNav, 500);
});
}
ugf2009WaitFor("#gp-gbar-inner", function() {
const search = document.querySelector("#gp-gbar-search");
const images = document.querySelector("#gp-gbar-images");
if (isImages && search && images) {
search.classList.remove("active");
images.classList.add("active");
}
});
}
function ugf2009Buttons() {
const btnEra = ugfRetroEra();
if (!btnEra || btnEra === "gplex2010") {
return;
}
if (!/home$/.test(document.querySelector("html").getAttribute("location") || "")) {
ugf2009WaitFor("#ugf-search", function(searchBar) {
if (searchBar.querySelector(".searchbtn-small")) {
return;
}
const sBtn = document.createElement("button");
sBtn.classList.add("searchbtn-small");
sBtn.addEventListener("click", function() {
document.querySelector("#ugf-search-btn").click();
});
sBtn.innerText = "Search";
searchBar.appendChild(sBtn);
});
} else {
ugf2009WaitFor("#ugf-hp-buttons", function(btnRow) {
if (btnRow.querySelector(".searchbtn")) {
return;
}
const gsBtn = document.createElement("button");
gsBtn.classList.add("searchbtn");
gsBtn.addEventListener("click", function() {
document.querySelector("#ugf-search-btn-2").click();
});
gsBtn.innerText = "Google Search";
const iflBtn = document.createElement("button");
iflBtn.classList.add("searchbtn");
iflBtn.addEventListener("click", function() {
document.querySelector("#ugf-lucky-btn").click();
});
const eraConf = UGF_RETRO_CHROME[ugfRetroEra()];
iflBtn.innerText = (eraConf && eraConf.luckyLabel) ? eraConf.luckyLabel : "I\'m Feeling Lucky";
const eraConf2 = UGF_RETRO_CHROME[ugfRetroEra()];
if (eraConf2 && eraConf2.resultsDropdown) {
const sel = document.createElement("select");
sel.className = "ugf-era-results-select";
eraConf2.resultsDropdown.forEach(function(opt) {
const o = document.createElement("option");
o.textContent = opt;
o.value = String(parseInt(opt, 10) || 10);
sel.appendChild(o);
});
let savedNum = "10";
try {
savedNum = localStorage.getItem("UGF_ERA_NUM") || "10";
} catch (e) {}
sel.value = savedNum;
if (!sel.value) {
sel.value = "10";
}
sel.addEventListener("change", function() {
try {
localStorage.setItem("UGF_ERA_NUM", sel.value);
} catch (e) {}
});
btnRow.appendChild(sel);
}
btnRow.appendChild(gsBtn);
btnRow.appendChild(iflBtn);
});
}
}
ugf2009Buttons();
ugfEraHomeButtons();
ugfVerticalHome();
ugfEraPageLimit();
ugfClassicSerp();
ugfLensTheme();
ugfSbiCamera();
ugfI18nStart();
ugfRetroChrome();
ugfRetroFooter();
ugfContinuousScroll();
ugfSetFavicon();
ugfRetroPromo();
ugfRetroLogoLinks();
ugfRetroExtras();
})();
});