diff options
author | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-24 13:09:03 -0700 |
---|---|---|
committer | Sam Tay <sam.chong.tay@gmail.com> | 2020-06-24 13:14:17 -0700 |
commit | 5625602e711ceab71bdace19c239c1972fc6ac4d (patch) | |
tree | 1996161a58bf53d10e02ff612d5f5d73874ad678 | |
parent | 59f6acca025f7a487ec5f6c32899226e0e5c9d5f (diff) |
Add google search engine
-rw-r--r-- | TODO.md | 15 | ||||
-rw-r--r-- | roadmap.md | 6 | ||||
-rw-r--r-- | src/cli.rs | 2 | ||||
-rw-r--r-- | src/config.rs | 3 | ||||
-rw-r--r-- | src/stackexchange/scraper.rs | 228 | ||||
-rw-r--r-- | src/stackexchange/search.rs | 3 | ||||
-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.html | 201 |
9 files changed, 369 insertions, 89 deletions
@@ -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', @@ -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. @@ -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( |