summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Tay <sam.chong.tay@gmail.com>2020-06-24 13:09:03 -0700
committerSam Tay <sam.chong.tay@gmail.com>2020-06-24 13:14:17 -0700
commit5625602e711ceab71bdace19c239c1972fc6ac4d (patch)
tree1996161a58bf53d10e02ff612d5f5d73874ad678
parent59f6acca025f7a487ec5f6c32899226e0e5c9d5f (diff)
Add google search engine
-rw-r--r--TODO.md15
-rw-r--r--roadmap.md6
-rw-r--r--src/cli.rs2
-rw-r--r--src/config.rs3
-rw-r--r--src/stackexchange/scraper.rs228
-rw-r--r--src/stackexchange/search.rs3
-rw-r--r--test/duckduckgo/bad-user-agent.html (renamed from test/bad-user-agent.html)0
-rw-r--r--test/duckduckgo/exit-vim.html (renamed from test/exit-vim.html)0
-rw-r--r--test/google/exit-vim.html201
9 files changed, 369 insertions, 89 deletions
diff --git a/TODO.md b/TODO.md
index 0e6be2a..992f2d6 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,18 +1,9 @@
# TODO
-### v0.3.1
-1. Much of the code can be reused for google:
- * parsing href after `"url="` (similar to uddg)
- * formatting `(site:stackoverflow.com OR site:unix.stackexchange.com) what is linux`
- So make a `Scraper` trait and implement it for DDG & Google. Then
- `stackexchange` can just code against `Scraper` and choose based on
- `--search-engine | -e' argument`
-
### Endless future improvements for the TUI
-1. Init with smaller layout depending on initial screen size.
-2. Maybe cli `--auto-resize` option.
3. Small text at bottom with '?' to bring up key mapping dialog
-4. Clean up! remove dupe between ListView and MdView by making a common trait
+1. Init with smaller layout depending on initial screen size.
+2. Maybe cli `--auto-resize` option that changes layouts at breakpoints.
5. Maybe **[ESC]** cycles layout in the opposite direction? And stops at
BothColumns?
6. Allow cycling through themes, either found in `~/.config/so/colors/*.toml`
@@ -23,7 +14,7 @@
#### scraping
```python
-# if necessary, choose one of these to mimic browser request
+# if necessary, cycle through these to mimic browser request
USER_AGENTS = ('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0',
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100 101 Firefox/22.0',
'Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0',
diff --git a/roadmap.md b/roadmap.md
index ec52411..f79b693 100644
--- a/roadmap.md
+++ b/roadmap.md
@@ -24,16 +24,16 @@
[x] Add duckduckgo scraper
### v0.3.1
-[ ] Add google scraper
+[x] Add google scraper
### at some point
+[ ] look up how to add `debug!` macros; will help troubleshooting blocked requests
[ ] use trust to distrubute app binaries
[ ] ask SE forums if I should bundle my api-key? (if so use an env var macro)
[ ] allow new queries from TUI, e.g. hit `/` for a prompt
[ ] or `/` searches current q/a
-[ ] clean up error.rs and term.rs ; only keep whats actually ergonomic
+[ ] clean up dingleberries in error.rs and term.rs ; only keep whats actually ergonomic
[ ] ask legal@stackoverflow.com for permission to logo stackoverflow/stackexchange in readme
[ ] add duckduckgo logo to readme
[ ] per platform package mgmt
[ ] more testing
-[ ] maybe add google engine too. but fuck google.
diff --git a/src/cli.rs b/src/cli.rs
index 715d62e..1892066 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -90,7 +90,7 @@ pub fn get_opts() -> Result<Opts> {
.takes_value(true)
.default_value(engine)
.value_name("engine")
- .possible_values(&["duckduckgo", "stackexchange"])
+ .possible_values(&["duckduckgo", "google", "stackexchange"])
.help("Use specified search engine")
.next_line_help(true),
)
diff --git a/src/config.rs b/src/config.rs
index 3102a87..0154cda 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -12,7 +12,7 @@ use crate::utils;
#[serde(rename_all = "lowercase")] // TODO test this
pub enum SearchEngine {
DuckDuckGo,
- //Google,
+ Google,
StackExchange,
}
@@ -30,6 +30,7 @@ impl fmt::Display for SearchEngine {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match &self {
SearchEngine::DuckDuckGo => "duckduckgo",
+ SearchEngine::Google => "google",
SearchEngine::StackExchange => "stackexchange",
};
write!(f, "{}", s)
diff --git a/src/stackexchange/scraper.rs b/src/stackexchange/scraper.rs
index e6376fa..2f62eb6 100644
--- a/src/stackexchange/scraper.rs
+++ b/src/stackexchange/scraper.rs
@@ -9,6 +9,7 @@ use crate::error::{Error, Result};
/// DuckDuckGo URL
const DUCKDUCKGO_URL: &str = "https://duckduckgo.com";
+const GOOGLE_URL: &str = "https://google.com/search";
// Is question_id unique across all sites? If not, then this edge case is
// unaccounted for when sorting.
@@ -40,60 +41,23 @@ pub struct DuckDuckGo;
impl Scraper for DuckDuckGo {
/// Parse (site, question_id) pairs out of duckduckgo search results html
- // TODO Benchmark this. It would likely be faster to use regex on the decoded url.
- // TODO pull out parts that are composable across different engines
fn parse(
&self,
html: &str,
sites: &HashMap<String, String>,
limit: u16,
) -> Result<ScrapedData> {
- let fragment = Html::parse_document(html);
let anchors = Selector::parse("a.result__a").unwrap();
- let mut question_ids: HashMap<String, Vec<String>> = HashMap::new();
- let mut ordering: HashMap<String, usize> = HashMap::new();
- let mut count = 0;
- for anchor in fragment.select(&anchors) {
- let url = anchor
- .value()
- .attr("href")
- .ok_or_else(|| Error::ScrapingError("Anchor with no href".to_string()))
- .map(|href| percent_decode_str(href).decode_utf8_lossy().into_owned())?;
- sites
- .iter()
- .find_map(|(site_code, site_url)| {
- let id = question_url_to_id(site_url, &url)?;
- ordering.insert(id.to_owned(), count);
- match question_ids.entry(site_code.to_owned()) {
- Entry::Occupied(mut o) => o.get_mut().push(id),
- Entry::Vacant(o) => {
- o.insert(vec![id]);
- }
- }
- count += 1;
- Some(())
- })
- .ok_or_else(|| {
- Error::ScrapingError(
- "Duckduckgo returned results outside of SE network".to_string(),
- )
- })?;
- if count >= limit as usize {
- break;
+ parse_with_selector(anchors, html, sites, limit).and_then(|sd| {
+ // DDG seems to never have empty results, so assume this is blocked
+ if sd.question_ids.is_empty() {
+ Err(Error::ScrapingError(String::from(
+ "DuckDuckGo blocked this request",
+ )))
+ } else {
+ Ok(sd)
}
- }
- // It doesn't seem possible for DDG to return no results, so assume this is
- // a bad user agent
- if count == 0 {
- Err(Error::ScrapingError(String::from(
- "DuckDuckGo blocked this request",
- )))
- } else {
- Ok(ScrapedData {
- question_ids,
- ordering,
- })
- }
+ })
}
/// Creates duckduckgo search url given sites and query
@@ -102,27 +66,7 @@ impl Scraper for DuckDuckGo {
where
I: IntoIterator<Item = &'a String>,
{
- let mut q = String::new();
- // Restrict to sites
- q.push('(');
- q.push_str(
- sites
- .into_iter()
- .map(|site| String::from("site:") + site)
- .collect::<Vec<_>>()
- .join(" OR ")
- .as_str(),
- );
- q.push_str(") ");
- // Search terms
- q.push_str(
- query
- .trim_end_matches('?')
- .split_whitespace()
- .collect::<Vec<_>>()
- .join(" ")
- .as_str(),
- );
+ let q = make_query_arg(query, sites);
Url::parse_with_params(
DUCKDUCKGO_URL,
&[("q", q.as_str()), ("kz", "-1"), ("kh", "-1")],
@@ -131,6 +75,107 @@ impl Scraper for DuckDuckGo {
}
}
+pub struct Google;
+
+impl Scraper for Google {
+ /// Parse SE data out of google search results html
+ fn parse(
+ &self,
+ html: &str,
+ sites: &HashMap<String, String>,
+ limit: u16,
+ ) -> Result<ScrapedData> {
+ let anchors = Selector::parse("div.r > a").unwrap();
+ // TODO detect no results
+ // TODO detect blocked request
+ parse_with_selector(anchors, html, sites, limit)
+ }
+
+ /// Creates duckduckgo search url given sites and query
+ /// See https://duckduckgo.com/params for more info
+ fn get_url<'a, I>(&self, query: &str, sites: I) -> Url
+ where
+ I: IntoIterator<Item = &'a String>,
+ {
+ let q = make_query_arg(query, sites);
+ Url::parse_with_params(GOOGLE_URL, &[("q", q.as_str())]).unwrap()
+ }
+}
+
+fn make_query_arg<'a, I>(query: &str, sites: I) -> String
+where
+ I: IntoIterator<Item = &'a String>,
+{
+ let mut q = String::new();
+ // Restrict to sites
+ q.push('(');
+ q.push_str(
+ sites
+ .into_iter()
+ .map(|site| String::from("site:") + site)
+ .collect::<Vec<_>>()
+ .join(" OR ")
+ .as_str(),
+ );
+ q.push_str(") ");
+ // Search terms
+ q.push_str(
+ query
+ .trim_end_matches('?')
+ .split_whitespace()
+ .collect::<Vec<_>>()
+ .join(" ")
+ .as_str(),
+ );
+ q
+}
+
+// TODO Benchmark this. It would likely be faster to use regex on the decoded url.
+fn parse_with_selector(
+ anchors: Selector,
+ html: &str,
+ sites: &HashMap<String, String>,
+ limit: u16,
+) -> Result<ScrapedData> {
+ let fragment = Html::parse_document(html);
+ let mut question_ids: HashMap<String, Vec<String>> = HashMap::new();
+ let mut ordering: HashMap<String, usize> = HashMap::new();
+ let mut count = 0;
+ for anchor in fragment.select(&anchors) {
+ let url = anchor
+ .value()
+ .attr("href")
+ .ok_or_else(|| Error::ScrapingError("Anchor with no href".to_string()))
+ .map(|href| percent_decode_str(href).decode_utf8_lossy().into_owned())?;
+ sites
+ .iter()
+ .find_map(|(site_code, site_url)| {
+ let id = question_url_to_id(site_url, &url)?;
+ ordering.insert(id.to_owned(), count);
+ match question_ids.entry(site_code.to_owned()) {
+ Entry::Occupied(mut o) => o.get_mut().push(id),
+ Entry::Vacant(o) => {
+ o.insert(vec![id]);
+ }
+ }
+ count += 1;
+ Some(())
+ })
+ .ok_or_else(|| {
+ Error::ScrapingError(
+ "Search engine returned results outside of SE network".to_string(),
+ )
+ })?;
+ if count >= limit as usize {
+ break;
+ }
+ }
+ Ok(ScrapedData {
+ question_ids,
+ ordering,
+ })
+}
+
/// For example
/// ```
/// let id = "stackoverflow.com";
@@ -169,7 +214,7 @@ mod tests {
#[test]
fn test_duckduckgo_parser() {
- let html = include_str!("../../test/exit-vim.html");
+ let html = include_str!("../../test/duckduckgo/exit-vim.html");
let sites = vec![
("stackoverflow", "stackoverflow.com"),
("askubuntu", "askubuntu.com"),
@@ -196,21 +241,55 @@ mod tests {
.collect(),
};
assert_eq!(
- SearchEngine::DuckDuckGo.parse(html, &sites, 3).unwrap(),
+ DuckDuckGo.parse(html, &sites, 3).unwrap(),
+ expected_scraped_data
+ );
+ }
+
+ #[test]
+ fn test_google_parser() {
+ let html = include_str!("../../test/google/exit-vim.html");
+ let sites = vec![
+ ("stackoverflow", "stackoverflow.com"),
+ ("askubuntu", "askubuntu.com"),
+ ]
+ .into_iter()
+ .map(|(k, v)| (k.to_string(), v.to_string()))
+ .collect::<HashMap<String, String>>();
+ let expected_scraped_data = ScrapedData {
+ question_ids: vec![
+ ("stackoverflow", vec!["11828270", "25919461"]),
+ ("askubuntu", vec!["24406"]),
+ ]
+ .into_iter()
+ .map(|(k, v)| {
+ (
+ k.to_string(),
+ v.into_iter().map(|s| s.to_string()).collect(),
+ )
+ })
+ .collect(),
+ ordering: vec![("11828270", 0), ("25919461", 1), ("24406", 2)]
+ .into_iter()
+ .map(|(k, v)| (k.to_string(), v))
+ .collect(),
+ };
+ assert_eq!(
+ Google.parse(html, &sites, 3).unwrap(),
expected_scraped_data
);
}
#[test]
fn test_duckduckgo_blocker() -> Result<(), String> {
- let html = include_str!("../../test/bad-user-agent.html");
+ let html = include_str!("../../test/duckduckgo/bad-user-agent.html");
let mut sites = HashMap::new();
sites.insert(
String::from("stackoverflow"),
String::from("stackoverflow.com"),
);
- match SearchEngine::DuckDuckGo.parse(html, &sites, 2) {
+ match DuckDuckGo.parse(html, &sites, 2) {
Err(Error::ScrapingError(s)) if s == "DuckDuckGo blocked this request".to_string() => {
Ok(())
}
@@ -219,6 +298,13 @@ mod tests {
}
#[test]
+ // TODO Get a blocked request html
+ // note: this may only be possible at search.rs level (with non-200 code)
+ fn test_google_blocker() -> Result<(), String> {
+ Ok(())
+ }
+
+ #[test]
fn test_question_url_to_id() {
let site_url = "stackoverflow.com";
let input = "/l/?kh=-1&uddg=https://stackoverflow.com/questions/11828270/how-do-i-exit-the-vim-editor";
diff --git a/src/stackexchange/search.rs b/src/stackexchange/search.rs
index 530b665..acfbcc7 100644
--- a/src/stackexchange/search.rs
+++ b/src/stackexchange/search.rs
@@ -11,7 +11,7 @@ use crate::tui::markdown::Markdown;
use super::api::{Answer, Api, Question};
use super::local_storage::LocalStorage;
-use super::scraper::{DuckDuckGo, ScrapedData, Scraper};
+use super::scraper::{DuckDuckGo, Google, ScrapedData, Scraper};
/// Limit on concurrent requests (gets passed to `buffer_unordered`)
const CONCURRENT_REQUESTS_LIMIT: usize = 8;
@@ -84,6 +84,7 @@ impl Search {
pub async fn search(&self) -> Result<Vec<Question<String>>> {
match self.config.search_engine {
SearchEngine::DuckDuckGo => self.search_by_scraper(DuckDuckGo).await,
+ SearchEngine::Google => self.search_by_scraper(Google).await,
SearchEngine::StackExchange => self.parallel_search_advanced().await,
}
}
diff --git a/test/bad-user-agent.html b/test/duckduckgo/bad-user-agent.html
index 89c4aaa..89c4aaa 100644
--- a/test/bad-user-agent.html
+++ b/test/duckduckgo/bad-user-agent.html
diff --git a/test/exit-vim.html b/test/duckduckgo/exit-vim.html
index a4f7a4a..a4f7a4a 100644
--- a/test/exit-vim.html
+++ b/test/duckduckgo/exit-vim.html
diff --git a/test/google/exit-vim.html b/test/google/exit-vim.html
new file mode 100644
index 0000000..bd74d4c
--- /dev/null
+++ b/test/google/exit-vim.html
@@ -0,0 +1,201 @@
+<!doctype html><html itemscope="" itemtype="http://schema.org/SearchResultsPage" lang="en"><head><meta content="/images/branding/googleg/1x/googleg_standard_color_128dp.png" itemprop="image"><title>(site:askubuntu.com OR site:stackoverflow.com) how do i exit nvim - Google Search</title><script nonce="VnsFleiriCwplgyln3sgFw==">(function(){window.google={kEI:'qLHzXumUMvmOr7wPx-mB2Ag',kEXPI:'31',kBL:'tdrq'};google.sn='web';google.kHL='en';})();(function(){google.lc=[];google.li=0;google.getEI=function(a){for(var c;a&&(!a.getAttribute||!(c=a.getAttribute("eid")));)a=a.parentNode;return c||google.kEI};google.getLEI=function(a){for(var c=null;a&&(!a.getAttribute||!(c=a.getAttribute("leid")));)a=a.parentNode;return c};google.ml=function(){return null};google.time=function(){return Date.now()};google.log=function(a,c,b,d,g){if(b=google.logUrl(a,c,b,d,g)){a=new Image;var e=google.lc,f=google.li;e[f]=a;a.onerror=a.onload=a.onabort=function(){delete e[f]};google.vel&&google.vel.lu&&google.vel.lu(b);a.src=b;google.li=f+1}};google.logUrl=function(a,c,b,d,g){var e="",f=google.ls||"";b||-1!=c.search("&ei=")||(e="&ei="+google.getEI(d),-1==c.search("&lei=")&&(d=google.getLEI(d))&&(e+="&lei="+d));d="";!b&&google.cshid&&-1==c.search("&cshid=")&&"slh"!=a&&(d="&cshid="+google.cshid);b=b||"/"+(g||"gen_204")+"?atyp=i&ct="+a+"&cad="+c+e+f+"&zx="+google.time()+d;/^http:/i.test(b)&&"https:"==window.location.protocol&&(google.ml(Error("a"),!1,{src:b,glmm:1}),b="");return b};}).call(this);(function(){google.y={};google.x=function(a,b){if(a)var c=a.id;else{do c=Math.random();while(google.y[c])}google.y[c]=[a,b];return!1};google.lm=[];google.plm=function(a){google.lm.push.apply(google.lm,a)};google.lq=[];google.load=function(a,b,c){google.lq.push([[a],b,c])};google.loadAll=function(a,b){google.lq.push([a,b])};}).call(this);google.f={};(function(){
+document.documentElement.addEventListener("submit",function(b){var a;if(a=b.target){var c=a.getAttribute("data-submitfalse");a="1"==c||"q"==c&&!a.elements.q.value?!0:!1}else a=!1;a&&(b.preventDefault(),b.stopPropagation())},!0);document.documentElement.addEventListener("click",function(b){var a;a:{for(a=b.target;a&&a!=document.documentElement;a=a.parentElement)if("A"==a.tagName){a="1"==a.getAttribute("data-nohref");break a}a=!1}a&&b.preventDefault()},!0);}).call(this);(function(){google.hs={h:true,sie:false};})();var h="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a},k=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("a");},l=k(this),m=function(a,b){if(b)a:{var c=l;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in
+c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&h(c,a,{configurable:!0,writable:!0,value:b})}};m("String.prototype.startsWith",function(a){return a?a:function(b,c){if(null==this)throw new TypeError("The 'this' value for String.prototype.startsWith must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype.startsWith must not be a regular expression");var d=this+"";b+="";var e=d.length,g=b.length;c=Math.max(0,Math.min(c|0,d.length));for(var f=0;f<g&&c<e;)if(d[c++]!=b[f++])return!1;return f>=g}});google.arwt=function(a){a.href=document.getElementById(a.id.substring(a.id.startsWith("vcs")?3:1)).href;return!0};(function(){
+var f=this||self,h=Date.now;
+
+var x={};var aa=function(a,c){if(null===c)return!1;if("contains"in a&&1==c.nodeType)return a.contains(c);if("compareDocumentPosition"in a)return a==c||!!(a.compareDocumentPosition(c)&16);for(;c&&a!=c;)c=c.parentNode;return c==a};var ba=function(a,c){return function(d){d||(d=window.event);return c.call(a,d)}},z=function(a){a=a.target||a.srcElement;!a.getAttribute&&a.parentNode&&(a=a.parentNode);return a},A="undefined"!=typeof navigator&&/Macintosh/.test(navigator.userAgent),ca="undefined"!=typeof navigator&&!/Opera/.test(navigator.userAgent)&&/WebKit/.test(navigator.userAgent),da={A:1,INPUT:1,TEXTAREA:1,SELECT:1,BUTTON:1},ea=function(){this._mouseEventsPrevented=!0},F={A:13,BUTTON:0,CHECKBOX:32,COMBOBOX:13,FILE:0,GRIDCELL:13,LINK:13,LISTBOX:13,MENU:0,MENUBAR:0,MENUITEM:0,MENUITEMCHECKBOX:0,MENUITEMRADIO:0,OPTION:0,RADIO:32,RADIOGROUP:32,RESET:0,SUBMIT:0,SWITCH:32,TAB:0,TREE:13,TREEITEM:13},G={CHECKBOX:!0,FILE:!0,OPTION:!0,RADIO:!0},H={COLOR:!0,DATE:!0,DATETIME:!0,"DATETIME-LOCAL":!0,EMAIL:!0,MONTH:!0,NUMBER:!0,PASSWORD:!0,RANGE:!0,SEARCH:!0,TEL:!0,TEXT:!0,TEXTAREA:!0,TIME:!0,URL:!0,WEEK:!0},fa={A:!0,AREA:!0,BUTTON:!0,DIALOG:!0,IMG:!0,INPUT:!0,LINK:!0,MENU:!0,OPTGROUP:!0,OPTION:!0,PROGRESS:!0,SELECT:!0,TEXTAREA:!0};
+var I=function(){this.h=this.a=null},K=function(a,c){var d=J;d.a=a;d.h=c;return d};I.prototype.g=function(){var a=this.a;this.a&&this.a!=this.h?this.a=this.a.__owner||this.a.parentNode:this.a=null;return a};var L=function(){this.i=[];this.a=0;this.h=null;this.j=!1};L.prototype.g=function(){if(this.j)return J.g();if(this.a!=this.i.length){var a=this.i[this.a];this.a++;a!=this.h&&a&&a.__owner&&(this.j=!0,K(a.__owner,this.h));return a}return null};var J=new I,M=new L;
+var O=function(){this.o=[];this.a=[];this.g=[];this.j={};this.h=null;this.i=[];N(this,"_custom")},ha="undefined"!=typeof navigator&&/iPhone|iPad|iPod/.test(navigator.userAgent),P=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^\s+/,"").replace(/\s+$/,"")},ia=/\s*;\s*/,ma=function(a,c){return function p(b,g){g=void 0===g?!0:g;var m=c;if("_custom"==m){m=b.detail;if(!m||!m._type)return;m=m._type}if("click"==m&&(A&&b.metaKey||!A&&b.ctrlKey||2==b.which||null==b.which&&
+4==b.button||b.shiftKey))m="clickmod";else{var l=b.which||b.keyCode;ca&&3==l&&(l=13);if(13!=l&&32!=l)l=!1;else{var e=z(b),n;(n="keydown"!=b.type||!!(!("getAttribute"in e)||(e.getAttribute("type")||e.tagName).toUpperCase()in H||"BUTTON"==e.tagName.toUpperCase()||e.type&&"FILE"==e.type.toUpperCase()||e.isContentEditable)||b.ctrlKey||b.shiftKey||b.altKey||b.metaKey||(e.getAttribute("type")||e.tagName).toUpperCase()in G&&32==l)||((n=e.tagName in da)||(n=e.getAttributeNode("tabindex"),n=null!=n&&n.specified),n=!(n&&!e.disabled));if(n)l=!1;else{n=(e.getAttribute("role")||e.type||e.tagName).toUpperCase();var q=!(n in F)&&13==l;e="INPUT"!=e.tagName.toUpperCase()||!!e.type;l=(0==F[n]%l||q)&&e}}l&&(m="clickkey")}e=b.srcElement||b.target;l=Q(m,b,e,"",null);b.path?(M.i=b.path,M.a=0,M.h=this,M.j=!1,n=M):n=K(e,this);for(;q=n.g();){var k=q;var r=void 0;var u=k;q=m;var t=u.__jsaction;if(!t){var y;t=null;"getAttribute"in u&&(t=u.getAttribute("jsaction"));if(y=t){t=x[y];if(!t){t={};for(var B=y.split(ia),ja=B?B.length:0,C=0;C<ja;C++){var w=B[C];if(w){var D=w.indexOf(":"),R=-1!=D,ka=R?P(w.substr(0,D)):"click";w=R?P(w.substr(D+1)):w;t[ka]=w}}x[y]=t}u.__jsaction=t}else t=la,u.__jsaction=t}u=t;"maybe_click"==q&&u.click?(r=q,q="click"):"clickkey"==q?q="click":"click"!=q||u.click||(q="clickonly");r={m:r?r:q,action:u[q]||"",event:null,s:!1};l=Q(r.m,r.event||b,e,r.action||"",k,l.timeStamp);if(r.s||r.action)break}l&&"touchend"==l.eventType&&(l.event._preventMouseEvents=ea);if(r&&r.action){if(e="clickkey"==m)e=z(b),e=(e.type||
+e.tagName).toUpperCase(),(e=32==(b.which||b.keyCode)&&"CHECKBOX"!=e)||(e=z(b),n=e.tagName.toUpperCase(),r=(e.getAttribute("role")||"").toUpperCase(),e="BUTTON"===n||"BUTTON"===r?!0:!(e.tagName.toUpperCase()in fa)||"A"===n||"SELECT"===n||(e.getAttribute("type")||e.tagName).toUpperCase()in G||(e.getAttribute("type")||e.tagName).toUpperCase()in H?!1:!0);e&&(b.preventDefault?b.preventDefault():b.returnValue=!1);if("mouseenter"==m||"mouseleave"==m)if(e=b.relatedTarget,!("mouseover"==b.type&&"mouseenter"==
+m||"mouseout"==b.type&&"mouseleave"==m)||e&&(e===k||aa(k,e)))l.action="",l.actionElement=null;else{m={};for(var v in b)"function"!==typeof b[v]&&"srcElement"!==v&&"target"!==v&&(m[v]=b[v]);m.type="mouseover"==b.type?"mouseenter":"mouseleave";m.target=m.srcElement=k;m.bubbles=!1;l.event=m;l.targetElement=k}}else l.action="",l.actionElement=null;k=l;a.h&&!k.event.a11ysgd&&(v=Q(k.eventType,k.event,k.targetElement,k.action,k.actionElement,k.timeStamp),"clickonly"==v.eventType&&(v.eventType="click"),a.h(v,!0));if(k.actionElement){if(a.h){if(!k.actionElement||"A"!=k.actionElement.tagName||"click"!=k.eventType&&"clickmod"!=k.eventType||(b.preventDefault?b.preventDefault():b.returnValue=!1),(b=a.h(k))&&g){p.call(this,b,!1);return}}else{if((g=f.document)&&!g.createEvent&&g.createEventObject)try{var E=g.createEventObject(b)}catch(pa){E=b}else E=b;k.event=E;a.i.push(k)}if("touchend"==k.event.type&&k.event._mouseEventsPrevented){b=k.event;for(var qa in b);h()}}}},Q=function(a,c,d,b,g,p){return{eventType:a,event:c,targetElement:d,action:b,actionElement:g,timeStamp:p||h()}},la={},na=function(a,c){return function(d){var b=a,g=c,p=!1;"mouseenter"==b?b="mouseover":"mouseleave"==b&&(b="mouseout");if(d.addEventListener){if("focus"==b||"blur"==b||"error"==b||"load"==b)p=!0;d.addEventListener(b,g,p)}else d.attachEvent&&("focus"==b?b="focusin":"blur"==b&&(b="focusout"),g=ba(d,g),d.attachEvent("on"+b,g));return{m:b,l:g,capture:p}}},N=function(a,c){if(!a.j.hasOwnProperty(c)){var d=ma(a,c),b=na(c,d);a.j[c]=d;a.o.push(b);for(d=0;d<a.a.length;++d){var g=a.a[d];g.g.push(b.call(null,g.a))}"click"==c&&N(a,"keydown")}};O.prototype.l=function(a){return this.j[a]};var V=function(a,c){var d=new oa(c);a:{for(var b=0;b<a.a.length;b++)if(S(a.a[b],c)){c=!0;break a}c=!1}if(c)return a.g.push(d),d;T(a,d);a.a.push(d);U(a);return d},U=function(a){for(var c=a.g.concat(a.a),d=[],b=[],g=0;g<a.a.length;++g){var p=a.a[g];W(p,c)?(d.push(p),X(p)):b.push(p)}for(g=0;g<a.g.length;++g)p=a.g[g],W(p,c)?d.push(p):(b.push(p),T(a,p));a.a=b;a.g=d},T=function(a,c){var d=c.a;ha&&(d.style.cursor="pointer");for(d=0;d<a.o.length;++d)c.g.push(a.o[d].call(null,c.a))},Y=function(a,c){a.h=c;a.i&&(0<a.i.length&&c(a.i),a.i=null)},oa=function(a){this.a=a;this.g=[]},S=function(a,c){for(a=a.a;a!=c&&c.parentNode;)c=c.parentNode;return a==c},W=function(a,c){for(var d=0;d<c.length;++d)if(c[d].a!=a.a&&S(c[d],a.a))return!0;return!1},X=function(a){for(var c=0;c<a.g.length;++c){var d=a.a,b=a.g[c];d.removeEventListener?d.removeEventListener(b.m,b.l,b.capture):d.detachEvent&&d.detachEvent("on"+b.m,b.l)}a.g=[]};var Z=new O;V(Z,window.document.documentElement);N(Z,"click");N(Z,"focus");N(Z,"focusin");N(Z,"blur");N(Z,"focusout");N(Z,"error");N(Z,"load");N(Z,"change");N(Z,"dblclick");N(Z,"input");N(Z,"keyup");N(Z,"keydown");N(Z,"keypress");N(Z,"mousedown");N(Z,"mouseenter");N(Z,"mouseleave");N(Z,"mouseout");N(Z,"mouseover");N(Z,"mouseup");N(Z,"paste");N(Z,"touchstart");N(Z,"touchend");N(Z,"touchcancel");N(Z,"speech");(function(a){google.jsad=function(c){Y(a,c)};google.jsaac=function(c){return V(a,c)};google.jsarc=function(c){X(c);for(var d=!1,b=0;b<a.a.length;++b)if(a.a[b]===c){a.a.splice(b,1);d=!0;break}if(!d)for(d=0;d<a.g.length;++d)if(a.g[d]===c){a.g.splice(d,1);break}U(a)}})(Z);window.gws_wizbind=function(a){return{trigger:function(c){var d=a.l(c.type);d||(N(a,c.type),d=a.l(c.type));var b=c.target||c.srcElement;d&&d.call(b.ownerDocument.documentElement,c)},bind:function(c){Y(a,c)}}}(Z);}).call(this);(function(){
+var b=[];google.jsc={xx:b,x:function(a){b.push(a)},mm:[],m:function(a){google.jsc.mm.length||(google.jsc.mm=a)}};}).call(this);(function(){google.c={gl:false,inp:false,lhc:false,slp:false,uio:false,ust:false};(function(){
+var e=window.performance;var g=function(a,b,c,d){a.addEventListener?a.removeEventListener(b,c,d||!1):a.attachEvent&&a.detachEvent("on"+b,c)},h=function(a,b,c,d){a.addEventListener?a.addEventListener(b,c,d||!1):a.attachEvent&&a.attachEvent("on"+b,c)};google.timers={};google.startTick=function(a){google.timers[a]={t:{start:google.time()},e:{},m:{}}};google.tick=function(a,b,c){google.timers[a]||google.startTick(a);c=void 0!==c?c:google.time();b instanceof Array||(b=[b]);for(var d=0,f;f=b[d++];)google.timers[a].t[f]=c};google.c.e=function(a,b,c){google.timers[a].e[b]=c};google.c.b=function(a){var b=google.timers.load.m;b[a]&&google.ml(Error("a"),!1,{m:a});b[a]=!0};google.c.u=function(a){var b=google.timers.load.m;if(b[a]){b[a]=!1;for(a in b)if(b[a])return;google.csiReport()}else google.ml(Error("b"),!1,{m:a})};google.rll=function(a,b,c){var d=function(f){c(f);g(a,"load",d);g(a,"error",d)};h(a,"load",d);b&&h(a,"error",d)};google.aft=function(a){a.setAttribute("data-iml",google.time())};google.startTick("load");var k=google.timers.load;a:{var l=k.t;if(e){var m=e.timing;if(m){var n=m.navigationStart,p=m.responseStart;if(p>n&&p<=l.start){l.start=p;k.wsrt=p-n;break a}}e.now&&(k.wsrt=Math.floor(e.now()))}}google.c.b("pr");google.c.b("xe");if(google.c.gl){var q=function(a){a&&google.aft(a.target)};h(document.documentElement,"load",q,!0);google.c.glu=function(){g(document.documentElement,"load",q,!0)}};}).call(this);})();</script><style>[dir='ltr'],[dir='rtl']{unicode-bidi:-moz-isolate;unicode-bidi:isolate}bdo[dir='ltr'],bdo[dir='rtl']{unicode-bidi:bidi-override;unicode-bidi:-moz-isolate-override;unicode-bidi:isolate-override}#logocont{z-index:1;padding-left:16px;padding-right:10px;margin-top:-2px;padding-top:7px}#logocont.ddl{padding-top:3px}.big #logocont{padding-left:16px;padding-right:12px}#searchform #logocont{padding-top:11px;padding-right:28px;padding-left:30px}.sbibod{background-color:#fff;height:44px;vertical-align:top;border:1px solid #dfe1e5;border-radius:8px;box-shadow:none;transition:box-shadow 200ms cubic-bezier(0.4, 0.0, 0.2, 1);}.lst{border:0;margin-top:5px;margin-bottom:0}.lst:focus{outline:none}#lst-ib{color:#000}.gsfi,.lst{font:16px arial,sans-serif;line-height:34px;height:34px !important}.lst-c{overflow:hidden}#gs_st0{line-height:44px;padding:0 8px;margin-top:-1px;position:static}.srp #gs_st0{padding:0 2px 0 8px}.gsfs{font:17px arial,sans-serif}.lsb{background:transparent;border:0;font-size:0;height:30px;outline:0;text-align:left;width:100%}.sbico{display:inline-block;height:0px;width:0px;cursor:pointer;vertical-align:middle;color:#4285f4}.sbico-c{background:transparent;border:0;float:right;height:44px;line-height:44px;margin-top:-1px;outline:0;padding-right:16px;position:relative;top:-1px}.hp .sbico-c{display:none}#sblsbb{border-bottom-left-radius:0;border-top-left-radius:0;height:44px;margin:0;padding:0;}#sbds{border:0;margin-left:-1px}.hp .nojsb,.srp .jsb{display:none}#sfopt{display:inline-block;line-height:normal}.lsd{font-size:11px;position:absolute;top:3px;left:16px}.tsf{background:none}#sform{height:65px}#searchform{width:100%}.minidiv #gb{top:2px}.minidiv .sfbg{background:#fff;box-shadow:0 1px 6px 0 rgba(32,33,36,.28);height:72px;}.minidiv .sbibod{height:32px;margin:10px 0;border-radius:16px}.minidiv .visible-suggestions{border-bottom-left-radius:0;border-bottom-right-radius:0}.minidiv .sbico-c{height:32px;line-height:32px}.minidiv .sbib_b{padding-top:0}.minidiv .gsfi{font-size:14px;line-height:32px}.minidiv .gsfs{font-size:14px}.minidiv #logo img{height:28px;width:86px}#searchform.minidiv #logocont{padding:17px 34px 0}.minidiv li.sbsb_c .sbse{padding:0px 0}.minidiv .sbdd_a .sbdd_b,.minidiv .sbsb_a{border-bottom-left-radius:16px;border-bottom-right-radius:16px}.minidiv #gs_st0{line-height:32px !important}.minidiv .sbdd_a{top:32px !important}.minidiv .gsri_a{background-size:20px 20px;height:20px;width:16px}.minidiv .sbico-c .sbico{height:20px;width:20px}.hp #searchform{position:absolute;top:311px}@media only screen and (max-height:768px){.hp #searchform{top:269px}}.srp #searchform{position:absolute;top:20px;}.sfbg{height:69px;left:0;position:absolute;width:100%}.sfbgg{height:65px}#cnt{padding-top:20px;}</style><style id="gstyle">body{background:#fff;color:#000;margin:0}.link{color:#1a0dab !important}.ts{border-collapse:collapse}.ts td{padding:0}.g{line-height:1.2;text-align:left;width:600px}#rhs{padding-bottom:15px}a:link,.q:active,.q:visited{color:#1a0dab}a:visited{color:#609}.b{font-weight:bold}.s{max-width:48em}.sl{font-size:82%}.f,.f a:link{color:#70757a;line-height:1.58}.c h2{color:#666}.mslg cite{display:none}h1,ol,ul,li{margin:0;padding:0}.g,body,html,input,.std,h1{font-family:arial,sans-serif}.g,body,input,.std,h1{font-size:14px}.c h2,h1{font-weight:normal}h3,.med{font-size:medium;font-weight:normal;margin:0;padding:0}#res h3,#extrares h3{font-size:20px;line-height:1.3;}#cnt{clear:both}#res{margin:0 16px}ol li{list-style:none}.gl,#foot a,.nobr{white-space:nowrap}.sl,.r{font-weight:normal;margin:0}.r{font-size:medium}h4.r{font-size:small}.gic{position:relative;overflow:hidden;z-index:0}#rhs{display:block;margin-left:712px;padding-bottom:10px;min-width:268px}.mdm #rhs{margin-left:732px}.big #rhs{margin-left:792px}#rhs .scrt.rhsvw,#rhs table.rhsvw{border:0}#rhs .rhsvw{border:1px solid #ebebeb;padding-left:17px;padding-right:16px;position:relative;width:457px;-moz-box-sizing:border-box}#center_col .rhsl4,#center_col .rhsl5{display:none}#rhs.rhstc4 .rhsvw{width:369px}.rhstc4 .rhsg4{background:none !important;display:none !important}.rhstc5 .rhsl5,.rhstc5 .rhsl4,.rhstc4 .rhsl4{background:none !important;display:none !important}.nrgt{margin-left:22px;margin-left:0;margin-bottom:4px}.mslg .vsc{-moz-transition:opacity .2s ease;transition:opacity .2s ease;width:304px;border:1px solid #dadce0;border-radius:8px;border-radius:8px;min-height:66px;}.mslg .vsc:hover{background-color:#fafafa}.mslg>td{padding-right:8px;padding-top:8px;}.vsc{display:block;position:relative;width:100%}#res h3.r{display:block;overflow:hidden;text-overflow:ellipsis;-moz-text-overflow:ellipsis;white-space:nowrap;line-height:22px}em{font-weight:bold;font-style:normal}ol,ul,li{border:0;margin:0;padding:0}.g{margin-top:0;margin-bottom:28px}.tsw{width:595px}#cnt{min-width:833px;margin-left:0}.mw{max-width:1197px}.big .mw{max-width:1280px}.tsf-p{padding-left:180px;margin-right:46px;max-width:739px}.big .tsf-p{margin-right:322px;padding-left:180px}.col{float:left}#leftnavc,#center_col,#rhs{position:relative}#center_col{margin-left:138px;margin-right:264px;}.big #center_col{margin-left:138px;}#res{border:0;margin:0;}a:link,.q:active,.q:visited{cursor:pointer}.gl a,#tsf a,a.gl,a.fl,.bc a,#appbar a{text-decoration:none}.gl a:hover,#tsf a:hover,a.gl:hover,a.fl:hover,.bc a:hover{text-decoration:underline}#tads a,#tadsb a,#res a,#rhs a,#taw a,#brs a,.nsa,.fl,#botstuff a,#rhs .gl a{text-decoration:none}#foot{visibility:hidden}#fll a,#bfl a{color:#1a0dab;margin:0 12px;text-decoration:none}body{color:#222}.s{color:#4d5156}.s .st em,.st.s.std em{color:#5f6368}.s a:visited em{color:#609}.s a:active em{color:#dd4b39}#tsf{width:833px;}.big #tsf{width:1109px}.st{line-height:1.58;word-wrap:break-word}.sbc{padding:0 2px;min-width:30px}#rcnt{margin-top:0px;}#appbar,.rhscol{min-width:1261px}#appbar{background:#fff;-webkit-box-sizing:border-box;width:100%}#main{width:100%}#cnt #center_col,#cnt #foot{width:652px}#center_col{clear:both}#cnt #center_col,.mw #center_col{margin-left:180px}#rso{margin-top:6px}.mw #rhs{margin-left:892px;padding-right:8px}.th{border:1px solid #ebebeb}.ellip{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}</style><style>@-webkit-keyframes qs-timer {0%{}}.fp-f{bottom:0;height:auto;left:0;position:fixed !important;right:0;top:0;width:auto;z-index:127}.fp-h:not(.fp-nh):not(.goog-modalpopup-bg):not(.goog-modalpopup){display:none !important}.fp-zh.fp-h:not(.fp-nh):not(.goog-modalpopup-bg):not(.goog-modalpopup){display:block !important;height:0;overflow:hidden;transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0)}.fp-i .fp-c{display:block;min-height:100vh}li.fp-c{list-style:none}.fp-w{box-sizing:border-box;left:0;margin-left:auto;margin-right:auto;max-width:1217px;right:0}</style><script nonce="VnsFleiriCwplgyln3sgFw==">(function(){
+var b=[function(){google.tick&&google.tick("load","dcl")}];google.dclc=function(a){b.length?b.push(a):a()};function c(){for(var a;a=b.shift();)a()}window.addEventListener?(document.addEventListener("DOMContentLoaded",c,!1),window.addEventListener("load",c,!1)):window.attachEvent&&window.attachEvent("onload",c);}).call(this);(function(){
+window.rwt=function(){return!0};}).call(this);(function(){window.jsarwt=function(){return!1};}).call(this);</script><style>div#searchform{min-width:1261px;z-index:127}#gb{height:0;padding-left:16px;padding-right:16px}</style> <script nonce="VnsFleiriCwplgyln3sgFw==">;this.gbar_={CONFIG:[[[0,"www.gstatic.com","og.qtm.en_US.Y2mHzZ7HU2E.O","com","en","1",1,[4,2,".40.40.40.40.40.40.","","1300102,3700243,3700697","317576115","0"],null,"qLHzXpW9M5PemAX5x6rACg",null,0,"og.qtm.-6ob9ysgt00dy.L.F4.O","AA2YrTuHxZSD4tXZcAmap_MDWGJq1F-pSg","AA2YrTuy2osiv-z56S2oNPKLgdL_hQ5WLQ","",2,1,200,"USA",null,null,"1","1",1],null,[1,0.1000000014901161,2,1],[1,0.001000000047497451,1],[0,0,0,null,"","","",""],[0,0,"",1,0,0,0,0,0,0,0,0,0,null,0,0,null,null,0,0,0,"","","","","","",null,0,0,0,0,0,null,null,null,"rgba(32,33,36,1)","rgba(255,255,255,1)",0,0,1,1,1],null,null,["1","gci_91f30755d6a6b787dcc2a4062e6e9824.js","googleapis.client:plusone:gapi.iframes","","en"],null,null,null,null,["m;/_/scs/abc-static/_/js/k=gapi.gapi.en.yyhByYeMTAc.O/am=AAY/d=1/ct=zgms/rs=AHpOoo-O470EQdZ-4tpWpppyTQmeOEUv-g/m=__features__","https://apis.google.com","","","","",null,1,"es_plusone_gc_20200601.0_p0","en",null,0,0],[0.009999999776482582,"com","1",[null,"","0",null,1,5184000,null,null,"",0,1,"",0,0,0,0,0,0,1,0,0,0,0,0,0,0],null,[["","","0",0,0,-1]],null,0,null,null,["5061451","google\\.(com|ru|ca|by|kz|com\\.mx|com\\.tr)$",1]],[1,1,null,40400,1,"USA","en","317576115.0",8,0.009999999776482582,0,0,null,null,0,0,"",null,null,null,"qLHzXpW9M5PemAX5x6rACg",0],[[null,null,null,"https://www.gstatic.com/og/_/js/k=og.qtm.en_US.Y2mHzZ7HU2E.O/rt=j/m=qabr,q_d,qcwid,qmutsd,qapid/exm=qaaw,qadd,qaid,qein,qhaw,qhbr,qhch,qhga,qhid,qhin,qhpr/d=1/ed=1/rs=AA2YrTuHxZSD4tXZcAmap_MDWGJq1F-pSg"],[null,null,null,"https://www.gstatic.com/og/_/ss/k=og.qtm.-6ob9ysgt00dy.L.F4.O/m=qcwid/excm=qaaw,qadd,qaid,qein,qhaw,qhbr,qhch,qhga,qhid,qhin,qhpr/d=1/ed=1/ct=zgms/rs=AA2YrTuy2osiv-z56S2oNPKLgdL_hQ5WLQ"]],null,null,[""],[[[null,null,[null,null,null,"https://ogs.google.com/widget/app/so?gm2"],0,448,328,57,4,1,0,0,63,64,8000,"https://www.google.com/intl/en/about/products?tab=wh",67,1,69,null,1,70,"Can't seem to load the app launcher right now. Try again or go to the %1$sGoogle Products%2$s page.",3,1,0,74,0,null,null,null,null,null,null,1]],0,[null,null,null,"https://www.gstatic.com/og/_/js/k=og.qtm.en_US.Y2mHzZ7HU2E.O/rt=j/m=qdsh/d=1/ed=1/rs=AA2YrTuHxZSD4tXZcAmap_MDWGJq1F-pSg"],"1","1",1,0,null,"en",0]]],};this.gbar_=this.gbar_||{};(function(_){var window=this;
+try{
+/*
+
+ Copyright The Closure Library Authors.
+ SPDX-License-Identifier: Apache-2.0
+*/
+var aa,ba,ca,da,ea,ha,ja,ka,oa,pa,Ba,Ca,Ea;aa=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}};ba="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};
+ca=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("a");};da=ca(this);ea=function(a,b){if(b)a:{var c=da;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&ba(c,a,{configurable:!0,writable:!0,value:b})}};
+ea("Symbol",function(a){if(a)return a;var b=function(e,f){this.j=e;ba(this,"description",{configurable:!0,writable:!0,value:f})};b.prototype.toString=function(){return this.j};var c=0,d=function(e){if(this instanceof d)throw new TypeError("b");return new b("jscomp_symbol_"+(e||"")+"_"+c++,e)};return d});
+ea("Symbol.iterator",function(a){if(a)return a;a=Symbol("c");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),c=0;c<b.length;c++){var d=da[b[c]];"function"===typeof d&&"function"!=typeof d.prototype[a]&&ba(d.prototype,a,{configurable:!0,writable:!0,value:function(){return ha(aa(this))}})}return a});ha=function(a){a={next:a};a[Symbol.iterator]=function(){return this};return a};
+_.ia=function(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):{next:aa(a)}};ja="function"==typeof Object.create?Object.create:function(a){var b=function(){};b.prototype=a;return new b};if("function"==typeof Object.setPrototypeOf)ka=Object.setPrototypeOf;else{var la;a:{var ma={Yg:!0},na={};try{na.__proto__=ma;la=na.Yg;break a}catch(a){}la=!1}ka=la?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError("d`"+a);return a}:null}oa=ka;
+_.n=function(a,b){a.prototype=ja(b.prototype);a.prototype.constructor=a;if(oa)oa(a,b);else for(var c in b)if("prototype"!=c)if(Object.defineProperties){var d=Object.getOwnPropertyDescriptor(b,c);d&&Object.defineProperty(a,c,d)}else a[c]=b[c];a.P=b.prototype};pa=function(a,b,c){if(null==a)throw new TypeError("e`"+c);if(b instanceof RegExp)throw new TypeError("f`"+c);return a+""};
+ea("String.prototype.startsWith",function(a){return a?a:function(b,c){var d=pa(this,b,"startsWith"),e=d.length,f=b.length;c=Math.max(0,Math.min(c|0,d.length));for(var g=0;g<f&&c<e;)if(d[c++]!=b[g++])return!1;return g>=f}});ea("Number.MAX_SAFE_INTEGER",function(){return 9007199254740991});
+var qa=function(a,b){a instanceof String&&(a+="");var c=0,d={next:function(){if(c<a.length){var e=c++;return{value:b(e,a[e]),done:!1}}d.next=function(){return{done:!0,value:void 0}};return d.next()}};d[Symbol.iterator]=function(){return d};return d};ea("Array.prototype.keys",function(a){return a?a:function(){return qa(this,function(b){return b})}});ea("Array.prototype.values",function(a){return a?a:function(){return qa(this,function(b,c){return c})}});
+var ra=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)};
+ea("WeakMap",function(a){function b(){}function c(l){var m=typeof l;return"object"===m&&null!==l||"function"===m}function d(l){if(!ra(l,f)){var m=new b;ba(l,f,{value:m})}}function e(l){var m=Object[l];m&&(Object[l]=function(r){if(r instanceof b)return r;Object.isExtensible(r)&&d(r);return m(r)})}if(function(){if(!a||!Object.seal)return!1;try{var l=Object.seal({}),m=Object.seal({}),r=new a([[l,2],[m,3]]);if(2!=r.get(l)||3!=r.get(m))return!1;r.delete(l);r.set(m,4);return!r.has(l)&&4==r.get(m)}catch(t){return!1}}())return a;
+var f="$jscomp_hidden_"+Math.random();e("freeze");e("preventExtensions");e("seal");var g=0,k=function(l){this.j=(g+=Math.random()+1).toString();if(l){l=_.ia(l);for(var m;!(m=l.next()).done;)m=m.value,this.set(m[0],m[1])}};k.prototype.set=function(l,m){if(!c(l))throw Error("g");d(l);if(!ra(l,f))throw Error("h`"+l);l[f][this.j]=m;return this};k.prototype.get=function(l){return c(l)&&ra(l,f)?l[f][this.j]:void 0};k.prototype.has=function(l){return c(l)&&ra(l,f)&&ra(l[f],this.j)};k.prototype.delete=function(