{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# GATE & PYTHON\n",
    "---\n",
    "In this tutorial, we will see various ways of interacting with Java GATE from Python.\n",
    "- Python modules are still experimental! If you find any bugs please report it!\n",
    "- For PythonDoc, and more, you can visit https://gatenlp.github.io/python-gatenlp.\n",
    "- Mainly, Jupyter notebook will be used for this presentation.\n",
    "###### <div class=\"pull-right\">Mehmet E. Bakir</div> "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# GATE and PYTHON\n",
    "---\n",
    "Currently, GATE and Python can, somehow, interact in three ways!\n",
    "\n",
    "1. **Python GateNLP :** A Python package for NLP tasks. It is similar to Java GATE.\n",
    "2. **GATE Slave :** A module that enables running almost anything in Java GATE from Python.\n",
    "3. **GATE Python Plugin :** It is GATE a Processing Resource that allows the editing and running python code within the Java GATE."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Part-1 Python GateNLP\n",
    "---\n",
    "An NLP framework written in pure Python. Its documents and annotations representations are very similar to the Java GATE framework.\n",
    "\n",
    "* A [**document**](https://gatenlp.github.io/python-gatenlp/documents) can have any number of named [**annotation sets**](https://gatenlp.github.io/python-gatenlp/annotationsets) and **features**.\n",
    "* An **annotation set** can have any number of [**annotations**](https://gatenlp.github.io/python-gatenlp/annotations).\n",
    "* **Annotations** are metadata associated with a span of a document. Each annotation can have any number of **features**.\n",
    "\n",
    "Python GateNLP and Java GATE exchange documents in ***bdocjs/bdocym/bdocmp*** formats, via Java GATE [Format Bdoc Plugin](https://gatenlp.github.io/gateplugin-Format_Bdoc/)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Get Your Hands Dirty!\n",
    "\n",
    "![Dirty Hands](./img/get-hands-dirty.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Python GateNLP -  Installation first!\n",
    "##### Main documentation page: https://gatenlp.github.io/python-gatenlp/installation.html\n",
    "### Environment Setup\n",
    "---\n",
    "- First make sure you have Python, We recommend installing Python via Conda with one of:\n",
    "    - Anaconda (https://www.anaconda.com/products/individual), or,\n",
    "    - Miniconda (https://docs.conda.io/en/latest/miniconda.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "- Then, create a **virtual environment**. The main purpose of virtual environments is to create an isolated environment for your projects. This means that each project can have its own dependencies.\n",
    "    - **Create** an environment, named \"*gatenlp*\", with the latest python version: `conda create -n gatenlp python=3.9`\n",
    "    - And **activate** this environment, use: `conda activate gatenlp`\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Installation Cont.\n",
    "## Install from GitHub\n",
    "---\n",
    "To install the *latest **released** version*  of gatenlp package with its all dependencies: `python -m pip install gatenlp[all]`\n",
    "\n",
    "**The RECOMMENDED way (at least for now!).** Install the latest gatenlp code with all dependencies from GitHub :\n",
    "1. Goto the GitHub page https://github.com/GateNLP/python-gatenlp.\n",
    "2. Clone the repository to a local directory and *change  directory* into python-gatenlp.\n",
    "3. Run  `python -m pip install -e .[all]`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Installation Cont.\n",
    "## Run with Jupyter\n",
    "---\n",
    "Requirements for **running gatenlp in a Jupyter notebook** (they should already have been installed--if installed from GitHub):\n",
    "\n",
    "* ipython\n",
    "* jupyter\n",
    "* ipykernel\n",
    "\n",
    "To create a kernel for your conda environment run:\n",
    "\n",
    "`python -m ipykernel install --user --name gatenlp --display-name \"Python gatenlp\"`\n",
    "\n",
    "To use an existing notebook (for example this notebook), run the following and change the kernel to gatenlp environment:\n",
    "\n",
    "`jupyter notebook notebookname.ipynb`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Let's Code!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "***import*** interested classes from ***gatenlp***"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "from gatenlp import Document"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Now load a plain text document!\n",
    " - For loading a document use `load` method of `Document` class, by which you can load local or remote files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# You can just add some text to the document \n",
    "# text = \"\"\"Some text forms the document content\"\"\"\n",
    "# doc = Document(text)\n",
    "# OR load from a local file\n",
    "doc = Document.load('./data/document-testing.txt')\n",
    "# OR\n",
    "# load a remove file with the same method\n",
    "# i.e., doc = Document.load(\"https://gatenlp.github.io/python-gatenlp/testdocument1.txt\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Print the document content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Document(This is a test document.\n",
      "\n",
      "It contains just a few sentences. \n",
      "Here is a sentence that mentions a few named entities like \n",
      "the persons Barack Obama or Ursula von der Leyen, locations\n",
      "like New York City, Vienna or Beijing or companies like \n",
      "Google, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\n",
      "\n",
      "Lets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\n",
      "\n",
      "Here we include a URL https://gatenlp.github.io/python-gatenlp/ \n",
      "and a fake email address john.doe@hiscoolserver.com as well \n",
      "as #some #cool #hastags and a bunch of emojis like 😽 (a kissing cat),\n",
      "👩‍🏫 (a woman teacher), 🧬 (DNA), \n",
      "🧗 (a person climbing), \n",
      "\n",
      "Here we test a few different scripts, e.g. Hangul 한글 or \n",
      "simplified Hanzi 汉字 or Farsi فارسی and Arabic ,اَلْعَرَبِيَّةُ, which goes from right to left.\n",
      "\n",
      ",features=Features({}),anns=[])\n"
     ]
    }
   ],
   "source": [
    "print(doc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Printing the document shows the document text and indicates that there are **no document features** and **no annotations**! We expect this since, we just loaded a plain text file. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "In the **Jupyter notebook/lab**, a *gatenlp* document can also be **displayed graphically** by either;\n",
    "1. by passing it to the IPython `display` function, or,\n",
    "2. calling it at the end of a cell."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Here we pass the doc to the `display` method!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<script type=\"text/javascript\">/*! jQuery v3.5.1 | (c) JS Foundation and other contributors | jquery.org/license */\n",
       "!function(e,t){\"use strict\";\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error(\"jQuery requires a window with a document\");return t(e)}:t(e)}(\"undefined\"!=typeof window?window:this,function(C,e){\"use strict\";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return\"function\"==typeof e&&\"number\"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement(\"script\");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+\"\":\"object\"==typeof e||\"function\"==typeof e?n[o.call(e)]||\"object\":typeof e}var f=\"3.5.1\",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&\"length\"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&(\"array\"===n||0===t||\"number\"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for(\"boolean\"==typeof a&&(l=a,a=arguments[s]||{},s++),\"object\"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],\"__proto__\"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:\"jQuery\"+(f+Math.random()).replace(/\\D/g,\"\"),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||\"[object Object]\"!==o.call(e))&&(!(t=r(e))||\"function\"==typeof(n=v.call(t,\"constructor\")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,\"string\"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),\"function\"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each(\"Boolean Number String Function Array Date RegExp Object Error Symbol\".split(\" \"),function(e,t){n[\"[object \"+t+\"]\"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S=\"sizzle\"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R=\"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",M=\"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",I=\"(?:\\\\\\\\[\\\\da-fA-F]{1,6}\"+M+\"?|\\\\\\\\[^\\\\r\\\\n\\\\f]|[\\\\w-]|[^\\0-\\\\x7f])+\",W=\"\\\\[\"+M+\"*(\"+I+\")(?:\"+M+\"*([*^$|!~]?=)\"+M+\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\"+I+\"))|)\"+M+\"*\\\\]\",F=\":(\"+I+\")(?:\\\\((('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\"+W+\")*)|.*)\\\\)|)\",B=new RegExp(M+\"+\",\"g\"),$=new RegExp(\"^\"+M+\"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\"+M+\"+$\",\"g\"),_=new RegExp(\"^\"+M+\"*,\"+M+\"*\"),z=new RegExp(\"^\"+M+\"*([>+~]|\"+M+\")\"+M+\"*\"),U=new RegExp(M+\"|>\"),X=new RegExp(F),V=new RegExp(\"^\"+I+\"$\"),G={ID:new RegExp(\"^#(\"+I+\")\"),CLASS:new RegExp(\"^\\\\.(\"+I+\")\"),TAG:new RegExp(\"^(\"+I+\"|[*])\"),ATTR:new RegExp(\"^\"+W),PSEUDO:new RegExp(\"^\"+F),CHILD:new RegExp(\"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\"+M+\"*(even|odd|(([+-]|)(\\\\d*)n|)\"+M+\"*(?:([+-]|)\"+M+\"*(\\\\d+)|))\"+M+\"*\\\\)|)\",\"i\"),bool:new RegExp(\"^(?:\"+R+\")$\",\"i\"),needsContext:new RegExp(\"^\"+M+\"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\"+M+\"*((?:-\\\\d)?\\\\d*)\"+M+\"*\\\\)|)(?=[^-]|$)\",\"i\")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\\d$/i,K=/^[^{]+\\{\\s*\\[native \\w/,Z=/^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,ee=/[+~]/,te=new RegExp(\"\\\\\\\\[\\\\da-fA-F]{1,6}\"+M+\"?|\\\\\\\\([^\\\\r\\\\n\\\\f])\",\"g\"),ne=function(e,t){var n=\"0x\"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\0-\\x1f\\x7f-\\uFFFF\\w-]/g,ie=function(e,t){return t?\"\\0\"===e?\"\\ufffd\":e.slice(0,-1)+\"\\\\\"+e.charCodeAt(e.length-1).toString(16)+\" \":\"\\\\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&\"fieldset\"===e.nodeName.toLowerCase()},{dir:\"parentNode\",next:\"legend\"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],\"string\"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+\" \"]&&(!v||!v.test(t))&&(1!==p||\"object\"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute(\"id\"))?s=s.replace(re,ie):e.setAttribute(\"id\",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?\"#\"+s:\":scope\")+\" \"+xe(l[o]);c=l.join(\",\")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute(\"id\")}}}return g(t.replace($,\"$1\"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+\" \")>b.cacheLength&&delete e[r.shift()],e[t+\" \"]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement(\"fieldset\");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split(\"|\"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return\"input\"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return(\"input\"===t||\"button\"===t)&&e.type===n}}function ge(t){return function(e){return\"form\"in e?e.parentNode&&!1===e.disabled?\"label\"in e?\"label\"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:\"label\"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&\"undefined\"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||\"HTML\")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener(\"unload\",oe,!1):n.attachEvent&&n.attachEvent(\"onunload\",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement(\"div\")),\"undefined\"!=typeof e.querySelectorAll&&!e.querySelectorAll(\":scope fieldset div\").length}),d.attributes=ce(function(e){return e.className=\"i\",!e.getAttribute(\"className\")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment(\"\")),!e.getElementsByTagName(\"*\").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute(\"id\")===t}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t=\"undefined\"!=typeof e.getAttributeNode&&e.getAttributeNode(\"id\");return t&&t.value===n}},b.find.ID=function(e,t){if(\"undefined\"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode(\"id\"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return\"undefined\"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if(\"*\"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if(\"undefined\"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML=\"<a id='\"+S+\"'></a><select id='\"+S+\"-\\r\\\\' msallowcapture=''><option selected=''></option></select>\",e.querySelectorAll(\"[msallowcapture^='']\").length&&v.push(\"[*^$]=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\"[selected]\").length||v.push(\"\\\\[\"+M+\"*(?:value|\"+R+\")\"),e.querySelectorAll(\"[id~=\"+S+\"-]\").length||v.push(\"~=\"),(t=C.createElement(\"input\")).setAttribute(\"name\",\"\"),e.appendChild(t),e.querySelectorAll(\"[name='']\").length||v.push(\"\\\\[\"+M+\"*name\"+M+\"*=\"+M+\"*(?:''|\\\"\\\")\"),e.querySelectorAll(\":checked\").length||v.push(\":checked\"),e.querySelectorAll(\"a#\"+S+\"+*\").length||v.push(\".#.+[+~]\"),e.querySelectorAll(\"\\\\\\f\"),v.push(\"[\\\\r\\\\n\\\\f]\")}),ce(function(e){e.innerHTML=\"<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>\";var t=C.createElement(\"input\");t.setAttribute(\"type\",\"hidden\"),e.appendChild(t).setAttribute(\"name\",\"D\"),e.querySelectorAll(\"[name=d]\").length&&v.push(\"name\"+M+\"*[*^$|!~]?=\"),2!==e.querySelectorAll(\":enabled\").length&&v.push(\":enabled\",\":disabled\"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(\":disabled\").length&&v.push(\":enabled\",\":disabled\"),e.querySelectorAll(\"*,:x\"),v.push(\",.*:\")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,\"*\"),c.call(e,\"[s!='']:x\"),s.push(\"!=\",F)}),v=v.length&&new RegExp(v.join(\"|\")),s=s.length&&new RegExp(s.join(\"|\")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+\" \"]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+\"\").replace(re,ie)},se.error=function(e){throw new Error(\"Syntax error, unrecognized expression: \"+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n=\"\",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if(\"string\"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{\">\":{dir:\"parentNode\",first:!0},\" \":{dir:\"parentNode\"},\"+\":{dir:\"previousSibling\",first:!0},\"~\":{dir:\"previousSibling\"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||\"\").replace(te,ne),\"~=\"===e[2]&&(e[3]=\" \"+e[3]+\" \"),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),\"nth\"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*(\"even\"===e[3]||\"odd\"===e[3])),e[5]=+(e[7]+e[8]||\"odd\"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||\"\":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(\")\",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return\"*\"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+\" \"];return t||(t=new RegExp(\"(^|\"+M+\")\"+e+\"(\"+M+\"|$)\"))&&m(e,function(e){return t.test(\"string\"==typeof e.className&&e.className||\"undefined\"!=typeof e.getAttribute&&e.getAttribute(\"class\")||\"\")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?\"!=\"===r:!r||(t+=\"\",\"=\"===r?t===i:\"!=\"===r?t!==i:\"^=\"===r?i&&0===t.indexOf(i):\"*=\"===r?i&&-1<t.indexOf(i):\"$=\"===r?i&&t.slice(-i.length)===i:\"~=\"===r?-1<(\" \"+t.replace(B,\" \")+\" \").indexOf(i):\"|=\"===r&&(t===i||t.slice(0,i.length+1)===i+\"-\"))}},CHILD:function(h,e,t,g,v){var y=\"nth\"!==h.slice(0,3),m=\"last\"!==h.slice(-4),x=\"of-type\"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?\"nextSibling\":\"previousSibling\",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l=\"only\"===h&&!u&&\"nextSibling\"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error(\"unsupported pseudo: \"+e);return a[S]?a(o):1<a.length?(t=[e,e,\"\",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,\"$1\"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||\"\")||se.error(\"unsupported lang: \"+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute(\"xml:lang\")||e.getAttribute(\"lang\"))return(t=t.toLowerCase())===n||0===t.indexOf(n+\"-\")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&!!e.checked||\"option\"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return\"input\"===t&&\"button\"===e.type||\"button\"===t},text:function(e){var t;return\"input\"===e.nodeName.toLowerCase()&&\"text\"===e.type&&(null==(t=e.getAttribute(\"type\"))||\"text\"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r=\"\";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&\"parentNode\"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||\"*\",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[\" \"],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:\" \"===e[s-2].type?\"*\":\"\"})).replace($,\"$1\"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+\" \"];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($,\" \")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+\" \"];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l=\"0\",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG(\"*\",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l=\"function\"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&\"ID\"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split(\"\").sort(D).join(\"\")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement(\"fieldset\"))}),ce(function(e){return e.innerHTML=\"<a href='#'></a>\",\"#\"===e.firstChild.getAttribute(\"href\")})||fe(\"type|href|height|width\",function(e,t,n){if(!n)return e.getAttribute(t,\"type\"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML=\"<input/>\",e.firstChild.setAttribute(\"value\",\"\"),\"\"===e.firstChild.getAttribute(\"value\")})||fe(\"value\",function(e,t,n){if(!n&&\"input\"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute(\"disabled\")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[\":\"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\\/\\0>:\\x20\\t\\r\\n\\f]*)[\\x20\\t\\r\\n\\f]*\\/?>(?:<\\/\\1>|)$/i;function D(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):\"string\"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=\":not(\"+e+\")\"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if(\"string\"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(D(this,e||[],!1))},not:function(e){return this.pushStack(D(this,e||[],!0))},is:function(e){return!!D(this,\"string\"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var j,q=/^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||j,\"string\"==typeof e){if(!(r=\"<\"===e[0]&&\">\"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,j=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a=\"string\"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?\"string\"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,\"parentNode\")},parentsUntil:function(e,t,n){return h(e,\"parentNode\",n)},next:function(e){return O(e,\"nextSibling\")},prev:function(e){return O(e,\"previousSibling\")},nextAll:function(e){return h(e,\"nextSibling\")},prevAll:function(e){return h(e,\"previousSibling\")},nextUntil:function(e,t,n){return h(e,\"nextSibling\",n)},prevUntil:function(e,t,n){return h(e,\"previousSibling\",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,\"template\")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return\"Until\"!==r.slice(-5)&&(t=e),t&&\"string\"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\\x20\\t\\r\\n\\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r=\"string\"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:\"\")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&\"string\"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t=\"\",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=\"\"),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[[\"notify\",\"progress\",S.Callbacks(\"memory\"),S.Callbacks(\"memory\"),2],[\"resolve\",\"done\",S.Callbacks(\"once memory\"),S.Callbacks(\"once memory\"),0,\"resolved\"],[\"reject\",\"fail\",S.Callbacks(\"once memory\"),S.Callbacks(\"once memory\"),1,\"rejected\"]],i=\"pending\",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},\"catch\":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+\"With\"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError(\"Thenable self-resolution\");t=e&&(\"object\"==typeof e||\"function\"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+\"With\"](this===s?void 0:this,arguments),this},s[t[0]+\"With\"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),\"pending\"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn(\"jQuery.Deferred exception: \"+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener(\"DOMContentLoaded\",B),C.removeEventListener(\"load\",B),S.ready()}S.fn.ready=function(e){return F.then(e)[\"catch\"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,\"complete\"===E.readyState||\"loading\"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener(\"DOMContentLoaded\",B),C.addEventListener(\"load\",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if(\"object\"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,\"ms-\").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if(\"string\"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&\"string\"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r=\"data-\"+t.replace(K,\"-$&\").toLowerCase(),\"string\"==typeof(n=e.getAttribute(r))){try{n=\"true\"===(i=n)||\"false\"!==i&&(\"null\"===i?null:i===+i+\"\"?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,\"hasDataAttrs\"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf(\"data-\")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,\"hasDataAttrs\",!0)}return i}return\"object\"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||\"fx\")+\"queue\",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||\"fx\";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);\"inprogress\"===i&&(i=n.shift(),r--),i&&(\"fx\"===t&&n.unshift(\"inprogress\"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+\"queueHooks\";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks(\"once memory\").add(function(){Y.remove(e,[t+\"queue\",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return\"string\"!=typeof t&&(n=t,t=\"fx\",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),\"fx\"===t&&\"inprogress\"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||\"fx\",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};\"string\"!=typeof e&&(t=e,e=void 0),e=e||\"fx\";while(a--)(n=Y.get(o[a],e+\"queueHooks\"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/.source,te=new RegExp(\"^(?:([+-])=|)(\"+ee+\")([a-z%]*)$\",\"i\"),ne=[\"Top\",\"Right\",\"Bottom\",\"Left\"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return\"none\"===(e=t||e).style.display||\"\"===e.style.display&&ie(e)&&\"none\"===S.css(e,\"display\")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,\"\")},u=s(),l=n&&n[3]||(S.cssNumber[t]?\"\":\"px\"),c=e.nodeType&&(S.cssNumber[t]||\"px\"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?(\"none\"===n&&(l[c]=Y.get(r,\"display\")||null,l[c]||(r.style.display=\"\")),\"\"===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,\"display\"),o.parentNode.removeChild(o),\"none\"===u&&(u=\"block\"),ue[s]=u)))):\"none\"!==n&&(l[c]=\"none\",Y.set(r,\"display\",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return\"boolean\"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\\/\\0>\\x20\\t\\r\\n\\f]*)/i,he=/^$|^module$|\\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement(\"div\")),(fe=E.createElement(\"input\")).setAttribute(\"type\",\"radio\"),fe.setAttribute(\"checked\",\"checked\"),fe.setAttribute(\"name\",\"t\"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML=\"<textarea>x</textarea>\",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML=\"<option></option>\",y.option=!!ce.lastChild;var ge={thead:[1,\"<table>\",\"</table>\"],col:[2,\"<table><colgroup>\",\"</colgroup></table>\"],tr:[2,\"<table><tbody>\",\"</tbody></table>\"],td:[3,\"<table><tbody><tr>\",\"</tr></tbody></table>\"],_default:[0,\"\",\"\"]};function ve(e,t){var n;return n=\"undefined\"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||\"*\"):\"undefined\"!=typeof e.querySelectorAll?e.querySelectorAll(t||\"*\"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],\"globalEval\",!t||Y.get(t[n],\"globalEval\"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,\"<select multiple='multiple'>\",\"</select>\"]);var me=/<|&#?\\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if(\"object\"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement(\"div\")),s=(de.exec(o)||[\"\",\"\"])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=\"\"}else p.push(t.createTextNode(o));f.textContent=\"\",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),\"script\"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||\"\")&&n.push(o)}return f}var be=/^key/,we=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Te=/^([^.]*)(?:\\.(.+)|)/;function Ce(){return!0}function Ee(){return!1}function Se(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==(\"focus\"===t)}function ke(e,t,n,r,i,o){var a,s;if(\"object\"==typeof t){for(s in\"string\"!=typeof n&&(r=r||n,n=void 0),t)ke(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&(\"string\"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ee;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Ae(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,Ce)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return\"undefined\"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||\"\").match(P)||[\"\"]).length;while(l--)d=g=(s=Te.exec(e[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(\".\")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||\"\").match(P)||[\"\"]).length;while(l--)if(d=g=(s=Te.exec(t[l])||[])[1],h=(s[2]||\"\").split(\".\").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&(\"**\"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,\"handle events\")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,\"events\")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!(\"click\"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(\"click\"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+\" \"]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Ae(t,\"click\",Ce),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Ae(t,\"click\"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,\"input\")&&Y.get(t,\"click\")||A(t,\"a\")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ce:Ee,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Ee,isPropagationStopped:Ee,isImmediatePropagationStopped:Ee,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ce,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ce,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ce,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,\"char\":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&be.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&we.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},S.event.addProp),S.each({focus:\"focusin\",blur:\"focusout\"},function(e,t){S.event.special[e]={setup:function(){return Ae(this,e,Se),!1},trigger:function(){return Ae(this,e),!0},delegateType:t}}),S.each({mouseenter:\"mouseover\",mouseleave:\"mouseout\",pointerenter:\"pointerover\",pointerleave:\"pointerout\"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return ke(this,e,t,n,r)},one:function(e,t,n,r){return ke(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+\".\"+r.namespace:r.origType,r.selector,r.handler),this;if(\"object\"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&\"function\"!=typeof t||(n=t,t=void 0),!1===n&&(n=Ee),this.each(function(){S.event.remove(this,e,n,t)})}});var Ne=/<script|<style|<link/i,De=/checked\\s*(?:[^=]|=\\s*.checked.)/i,je=/^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g;function qe(e,t){return A(e,\"table\")&&A(11!==t.nodeType?t:t.firstChild,\"tr\")&&S(e).children(\"tbody\")[0]||e}function Le(e){return e.type=(null!==e.getAttribute(\"type\"))+\"/\"+e.type,e}function He(e){return\"true/\"===(e.type||\"\").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute(\"type\"),e}function Oe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,\"handle events\"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function Pe(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&\"string\"==typeof d&&!y.checkClone&&De.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Pe(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,\"script\"),Le)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,\"script\"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,He),c=0;c<s;c++)u=a[c],he.test(u.type||\"\")&&!Y.access(u,\"globalEval\")&&S.contains(l,u)&&(u.src&&\"module\"!==(u.type||\"\").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute(\"nonce\")},l):b(u.textContent.replace(je,\"\"),u,l))}return n}function Re(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,\"script\")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,\"input\"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:\"input\"!==l&&\"textarea\"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Oe(o[r],a[r]);else Oe(e,c);return 0<(a=ve(c,\"script\")).length&&ye(a,!f&&ve(e,\"script\")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Re(this,e,!0)},remove:function(e){return Re(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Pe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||qe(this,e).appendChild(e)})},prepend:function(){return Pe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=qe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Pe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent=\"\");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if(\"string\"==typeof e&&!Ne.test(e)&&!ge[(de.exec(e)||[\"\",\"\"])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Pe(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:\"append\",prependTo:\"prepend\",insertBefore:\"before\",insertAfter:\"after\",replaceAll:\"replaceWith\"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Me=new RegExp(\"^(\"+ee+\")(?!px)[a-z%]+$\",\"i\"),Ie=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},We=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Fe=new RegExp(ne.join(\"|\"),\"i\");function Be(e,t,n){var r,i,o,a,s=e.style;return(n=n||Ie(e))&&(\"\"!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Me.test(a)&&Fe.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+\"\":a}function $e(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText=\"position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0\",l.style.cssText=\"position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%\",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n=\"1%\"!==e.top,s=12===t(e.marginLeft),l.style.right=\"60%\",o=36===t(e.right),r=36===t(e.width),l.style.position=\"absolute\",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement(\"div\"),l=E.createElement(\"div\");l.style&&(l.style.backgroundClip=\"content-box\",l.cloneNode(!0).style.backgroundClip=\"\",y.clearCloneStyle=\"content-box\"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement(\"table\"),t=E.createElement(\"tr\"),n=E.createElement(\"div\"),e.style.cssText=\"position:absolute;left:-11111px\",t.style.height=\"1px\",n.style.height=\"9px\",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=3<parseInt(r.height),re.removeChild(e)),a}}))}();var _e=[\"Webkit\",\"Moz\",\"ms\"],ze=E.createElement(\"div\").style,Ue={};function Xe(e){var t=S.cssProps[e]||Ue[e];return t||(e in ze?e:Ue[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=_e.length;while(n--)if((e=_e[n]+t)in ze)return e}(e)||e)}var Ve=/^(none|table(?!-c[ea]).+)/,Ge=/^--/,Ye={position:\"absolute\",visibility:\"hidden\",display:\"block\"},Qe={letterSpacing:\"0\",fontWeight:\"400\"};function Je(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||\"px\"):t}function Ke(e,t,n,r,i,o){var a=\"width\"===t?1:0,s=0,u=0;if(n===(r?\"border\":\"content\"))return 0;for(;a<4;a+=2)\"margin\"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?(\"content\"===n&&(u-=S.css(e,\"padding\"+ne[a],!0,i)),\"margin\"!==n&&(u-=S.css(e,\"border\"+ne[a]+\"Width\",!0,i))):(u+=S.css(e,\"padding\"+ne[a],!0,i),\"padding\"!==n?u+=S.css(e,\"border\"+ne[a]+\"Width\",!0,i):s+=S.css(e,\"border\"+ne[a]+\"Width\",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e[\"offset\"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Ze(e,t,n){var r=Ie(e),i=(!y.boxSizingReliable()||n)&&\"border-box\"===S.css(e,\"boxSizing\",!1,r),o=i,a=Be(e,t,r),s=\"offset\"+t[0].toUpperCase()+t.slice(1);if(Me.test(a)){if(!n)return a;a=\"auto\"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,\"tr\")||\"auto\"===a||!parseFloat(a)&&\"inline\"===S.css(e,\"display\",!1,r))&&e.getClientRects().length&&(i=\"border-box\"===S.css(e,\"boxSizing\",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Ke(e,t,n||(i?\"border\":\"content\"),o,r,a)+\"px\"}function et(e,t,n,r,i){return new et.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Be(e,\"opacity\");return\"\"===n?\"1\":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Ge.test(t),l=e.style;if(u||(t=Xe(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&\"get\"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];\"string\"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o=\"number\"),null!=n&&n==n&&(\"number\"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?\"\":\"px\")),y.clearCloneStyle||\"\"!==n||0!==t.indexOf(\"background\")||(l[t]=\"inherit\"),a&&\"set\"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Ge.test(t)||(t=Xe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&\"get\"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Be(e,t,r)),\"normal\"===i&&t in Qe&&(i=Qe[t]),\"\"===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each([\"height\",\"width\"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ve.test(S.css(e,\"display\"))||e.getClientRects().length&&e.getBoundingClientRect().width?Ze(e,u,n):We(e,Ye,function(){return Ze(e,u,n)})},set:function(e,t,n){var r,i=Ie(e),o=!y.scrollboxSize()&&\"absolute\"===i.position,a=(o||n)&&\"border-box\"===S.css(e,\"boxSizing\",!1,i),s=n?Ke(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e[\"offset\"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Ke(e,u,\"border\",!1,i)-.5)),s&&(r=te.exec(t))&&\"px\"!==(r[3]||\"px\")&&(e.style[u]=t,t=S.css(e,u)),Je(0,t,s)}}}),S.cssHooks.marginLeft=$e(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Be(e,\"marginLeft\"))||e.getBoundingClientRect().left-We(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+\"px\"}),S.each({margin:\"\",padding:\"\",border:\"Width\"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r=\"string\"==typeof e?e.split(\" \"):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},\"margin\"!==i&&(S.cssHooks[i+o].set=Je)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Ie(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=et).prototype={constructor:et,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?\"\":\"px\")},cur:function(){var e=et.propHooks[this.prop];return e&&e.get?e.get(this):et.propHooks._default.get(this)},run:function(e){var t,n=et.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):et.propHooks._default.set(this),this}}).init.prototype=et.prototype,(et.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,\"\"))&&\"auto\"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Xe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=et.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:\"swing\"},S.fx=et.prototype.init,S.fx.step={};var tt,nt,rt,it,ot=/^(?:toggle|show|hide)$/,at=/queueHooks$/;function st(){nt&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(st):C.setTimeout(st,S.fx.interval),S.fx.tick())}function ut(){return C.setTimeout(function(){tt=void 0}),tt=Date.now()}function lt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i[\"margin\"+(n=ne[r])]=i[\"padding\"+n]=e;return t&&(i.opacity=i.width=e),i}function ct(e,t,n){for(var r,i=(ft.tweeners[t]||[]).concat(ft.tweeners[\"*\"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function ft(o,e,t){var n,a,r=0,i=ft.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=tt||ut(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:tt||ut(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&\"expand\"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=ft.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ct,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(ft,{tweeners:{\"*\":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=[\"*\"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],ft.tweeners[n]=ft.tweeners[n]||[],ft.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f=\"width\"in t||\"height\"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,\"fxshow\");for(r in n.queue||(null==(a=S._queueHooks(e,\"fx\")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,\"fx\").length||a.empty.fire()})})),t)if(i=t[r],ot.test(i)){if(delete t[r],o=o||\"toggle\"===i,i===(g?\"hide\":\"show\")){if(\"show\"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,\"display\")),\"none\"===(c=S.css(e,\"display\"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,\"display\"),le([e]))),(\"inline\"===c||\"inline-block\"===c&&null!=l)&&\"none\"===S.css(e,\"float\")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l=\"none\"===c?\"\":c)),h.display=\"inline-block\")),n.overflow&&(h.overflow=\"hidden\",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?\"hidden\"in v&&(g=v.hidden):v=Y.access(e,\"fxshow\",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,\"fxshow\"),d)S.style(e,r,d[r])})),u=ct(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?ft.prefilters.unshift(e):ft.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&\"object\"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:\"number\"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue=\"fx\"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css(\"opacity\",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=ft(this,S.extend({},t),o);(i||Y.get(this,\"finish\"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return\"string\"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||\"fx\",[]),this.each(function(){var e=!0,t=null!=i&&i+\"queueHooks\",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&at.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||\"fx\"),this.each(function(){var e,t=Y.get(this),n=t[a+\"queue\"],r=t[a+\"queueHooks\"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each([\"toggle\",\"show\",\"hide\"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||\"boolean\"==typeof e?i.apply(this,arguments):this.animate(lt(r,!0),e,t,n)}}),S.each({slideDown:lt(\"show\"),slideUp:lt(\"hide\"),slideToggle:lt(\"toggle\"),fadeIn:{opacity:\"show\"},fadeOut:{opacity:\"hide\"},fadeToggle:{opacity:\"toggle\"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(tt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),tt=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){nt||(nt=!0,st())},S.fx.stop=function(){nt=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||\"fx\",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},rt=E.createElement(\"input\"),it=E.createElement(\"select\").appendChild(E.createElement(\"option\")),rt.type=\"checkbox\",y.checkOn=\"\"!==rt.value,y.optSelected=it.selected,(rt=E.createElement(\"input\")).value=\"t\",rt.type=\"radio\",y.radioValue=\"t\"===rt.value;var pt,dt=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return\"undefined\"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?pt:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+\"\"),n):i&&\"get\"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&\"radio\"===t&&A(e,\"input\")){var n=e.value;return e.setAttribute(\"type\",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),pt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\\w+/g),function(e,t){var a=dt[t]||S.find.attr;dt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=dt[o],dt[o]=r,r=null!=a(e,t,n)?o:null,dt[o]=i),r}});var ht=/^(?:input|select|textarea|button)$/i,gt=/^(?:a|area)$/i;function vt(e){return(e.match(P)||[]).join(\" \")}function yt(e){return e.getAttribute&&e.getAttribute(\"class\")||\"\"}function mt(e){return Array.isArray(e)?e:\"string\"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&\"set\"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&\"get\"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,\"tabindex\");return t?parseInt(t,10):ht.test(e.nodeName)||gt.test(e.nodeName)&&e.href?0:-1}}},propFix:{\"for\":\"htmlFor\",\"class\":\"className\"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each([\"tabIndex\",\"readOnly\",\"maxLength\",\"cellSpacing\",\"cellPadding\",\"rowSpan\",\"colSpan\",\"useMap\",\"frameBorder\",\"contentEditable\"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,yt(this)))});if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&\" \"+vt(i)+\" \"){a=0;while(o=e[a++])r.indexOf(\" \"+o+\" \")<0&&(r+=o+\" \");i!==(s=vt(r))&&n.setAttribute(\"class\",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,yt(this)))});if(!arguments.length)return this.attr(\"class\",\"\");if((e=mt(t)).length)while(n=this[u++])if(i=yt(n),r=1===n.nodeType&&\" \"+vt(i)+\" \"){a=0;while(o=e[a++])while(-1<r.indexOf(\" \"+o+\" \"))r=r.replace(\" \"+o+\" \",\" \");i!==(s=vt(r))&&n.setAttribute(\"class\",s)}return this},toggleClass:function(i,t){var o=typeof i,a=\"string\"===o||Array.isArray(i);return\"boolean\"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,yt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=mt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&\"boolean\"!==o||((e=yt(this))&&Y.set(this,\"__className__\",e),this.setAttribute&&this.setAttribute(\"class\",e||!1===i?\"\":Y.get(this,\"__className__\")||\"\"))})},hasClass:function(e){var t,n,r=0;t=\" \"+e+\" \";while(n=this[r++])if(1===n.nodeType&&-1<(\" \"+vt(yt(n))+\" \").indexOf(t))return!0;return!1}});var xt=/\\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t=\"\":\"number\"==typeof t?t+=\"\":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?\"\":e+\"\"})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&\"set\"in r&&void 0!==r.set(this,t,\"value\")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&\"get\"in r&&void 0!==(e=r.get(t,\"value\"))?e:\"string\"==typeof(e=t.value)?e.replace(xt,\"\"):null==e?\"\":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,\"value\");return null!=t?t:vt(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a=\"select-one\"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,\"optgroup\"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each([\"radio\",\"checkbox\"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute(\"value\")?\"on\":e.value})}),y.focusin=\"onfocusin\"in C;var bt=/^(?:focusinfocus|focusoutblur)$/,wt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,\"type\")?e.type:e,h=v.call(e,\"namespace\")?e.namespace.split(\".\"):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!bt.test(d+S.event.triggered)&&(-1<d.indexOf(\".\")&&(d=(h=d.split(\".\")).shift(),h.sort()),u=d.indexOf(\":\")<0&&\"on\"+d,(e=e[S.expando]?e:new S.Event(d,\"object\"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join(\".\"),e.rnamespace=e.namespace?new RegExp(\"(^|\\\\.)\"+h.join(\"\\\\.(?:.*\\\\.|)\")+\"(\\\\.|$)\"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,bt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,\"events\")||Object.create(null))[e.type]&&Y.get(o,\"handle\"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,wt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,wt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:\"focusin\",blur:\"focusout\"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var Tt=C.location,Ct={guid:Date.now()},Et=/\\?/;S.parseXML=function(e){var t;if(!e||\"string\"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,\"text/xml\")}catch(e){t=void 0}return t&&!t.getElementsByTagName(\"parsererror\").length||S.error(\"Invalid XML: \"+e),t};var St=/\\[\\]$/,kt=/\\r?\\n/g,At=/^(?:submit|button|image|reset|file)$/i,Nt=/^(?:input|select|textarea|keygen)/i;function Dt(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||St.test(n)?i(n,t):Dt(n+\"[\"+(\"object\"==typeof t&&null!=t?e:\"\")+\"]\",t,r,i)});else if(r||\"object\"!==w(e))i(n,e);else for(t in e)Dt(n+\"[\"+t+\"]\",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+\"=\"+encodeURIComponent(null==n?\"\":n)};if(null==e)return\"\";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)Dt(n,e[n],t,i);return r.join(\"&\")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,\"elements\");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(\":disabled\")&&Nt.test(this.nodeName)&&!At.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(kt,\"\\r\\n\")}}):{name:t.name,value:n.replace(kt,\"\\r\\n\")}}).get()}});var jt=/%20/g,qt=/#.*$/,Lt=/([?&])_=[^&]*/,Ht=/^(.*?):[ \\t]*([^\\r\\n]*)$/gm,Ot=/^(?:GET|HEAD)$/,Pt=/^\\/\\//,Rt={},Mt={},It=\"*/\".concat(\"*\"),Wt=E.createElement(\"a\");function Ft(o){return function(e,t){\"string\"!=typeof e&&(t=e,e=\"*\");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])\"+\"===n[0]?(n=n.slice(1)||\"*\",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Bt(t,i,o,a){var s={},u=t===Mt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return\"string\"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s[\"*\"]&&l(\"*\")}function $t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Wt.href=Tt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Tt.href,type:\"GET\",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Tt.protocol),global:!0,processData:!0,async:!0,contentType:\"application/x-www-form-urlencoded; charset=UTF-8\",accepts:{\"*\":It,text:\"text/plain\",html:\"text/html\",xml:\"application/xml, text/xml\",json:\"application/json, text/javascript\"},contents:{xml:/\\bxml\\b/,html:/\\bhtml/,json:/\\bjson\\b/},responseFields:{xml:\"responseXML\",text:\"responseText\",json:\"responseJSON\"},converters:{\"* text\":String,\"text html\":!0,\"text json\":JSON.parse,\"text xml\":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?$t($t(e,S.ajaxSettings),t):$t(S.ajaxSettings,e)},ajaxPrefilter:Ft(Rt),ajaxTransport:Ft(Mt),ajax:function(e,t){\"object\"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks(\"once memory\"),w=v.statusCode||{},a={},s={},u=\"canceled\",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Ht.exec(p))n[t[1].toLowerCase()+\" \"]=(n[t[1].toLowerCase()+\" \"]||[]).concat(t[2])}t=n[e.toLowerCase()+\" \"]}return null==t?null:t.join(\", \")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Tt.href)+\"\").replace(Pt,Tt.protocol+\"//\"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||\"*\").toLowerCase().match(P)||[\"\"],null==v.crossDomain){r=E.createElement(\"a\");try{r.href=v.url,r.href=r.href,v.crossDomain=Wt.protocol+\"//\"+Wt.host!=r.protocol+\"//\"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&\"string\"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Bt(Rt,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger(\"ajaxStart\"),v.type=v.type.toUpperCase(),v.hasContent=!Ot.test(v.type),f=v.url.replace(qt,\"\"),v.hasContent?v.data&&v.processData&&0===(v.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&(v.data=v.data.replace(jt,\"+\")):(o=v.url.slice(f.length),v.data&&(v.processData||\"string\"==typeof v.data)&&(f+=(Et.test(f)?\"&\":\"?\")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Lt,\"$1\"),o=(Et.test(f)?\"&\":\"?\")+\"_=\"+Ct.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader(\"If-Modified-Since\",S.lastModified[f]),S.etag[f]&&T.setRequestHeader(\"If-None-Match\",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader(\"Content-Type\",v.contentType),T.setRequestHeader(\"Accept\",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+(\"*\"!==v.dataTypes[0]?\", \"+It+\"; q=0.01\":\"\"):v.accepts[\"*\"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u=\"abort\",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Bt(Mt,v,t,T)){if(T.readyState=1,g&&m.trigger(\"ajaxSend\",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort(\"timeout\")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,\"No Transport\");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||\"\",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while(\"*\"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader(\"Content-Type\"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+\" \"+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray(\"script\",v.dataTypes)&&(v.converters[\"text script\"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if(\"*\"===o)o=u;else if(\"*\"!==u&&u!==o){if(!(a=l[u+\" \"+o]||l[\"* \"+o]))for(i in l)if((s=i.split(\" \"))[1]===o&&(a=l[u+\" \"+s[0]]||l[\"* \"+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e[\"throws\"])t=a(t);else try{t=a(t)}catch(e){return{state:\"parsererror\",error:a?e:\"No conversion from \"+u+\" to \"+o}}}return{state:\"success\",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader(\"Last-Modified\"))&&(S.lastModified[f]=u),(u=T.getResponseHeader(\"etag\"))&&(S.etag[f]=u)),204===e||\"HEAD\"===v.type?l=\"nocontent\":304===e?l=\"notmodified\":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l=\"error\",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+\"\",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?\"ajaxSuccess\":\"ajaxError\",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger(\"ajaxComplete\",[T,v]),--S.active||S.event.trigger(\"ajaxStop\")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,\"json\")},getScript:function(e,t){return S.get(e,void 0,t,\"script\")}}),S.each([\"get\",\"post\"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)\"content-type\"===t.toLowerCase()&&(e.contentType=e.headers[t]||\"\")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:\"GET\",dataType:\"script\",cache:!0,async:!1,global:!1,converters:{\"text script\":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not(\"body\").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var _t={0:200,1223:204},zt=S.ajaxSettings.xhr();y.cors=!!zt&&\"withCredentials\"in zt,y.ajax=zt=!!zt,S.ajaxTransport(function(i){var o,a;if(y.cors||zt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e[\"X-Requested-With\"]||(e[\"X-Requested-With\"]=\"XMLHttpRequest\"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,\"abort\"===e?r.abort():\"error\"===e?\"number\"!=typeof r.status?t(0,\"error\"):t(r.status,r.statusText):t(_t[r.status]||r.status,r.statusText,\"text\"!==(r.responseType||\"text\")||\"string\"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o(\"error\"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o(\"abort\");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:\"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"},contents:{script:/\\b(?:java|ecma)script\\b/},converters:{\"text script\":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter(\"script\",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type=\"GET\")}),S.ajaxTransport(\"script\",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S(\"<script>\").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on(\"load error\",i=function(e){r.remove(),i=null,e&&t(\"error\"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\\?(?=&|$)|\\?\\?/;S.ajaxSetup({jsonp:\"callback\",jsonpCallback:function(){var e=Xt.pop()||S.expando+\"_\"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter(\"json jsonp\",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?\"url\":\"string\"==typeof e.data&&0===(e.contentType||\"\").indexOf(\"application/x-www-form-urlencoded\")&&Vt.test(e.data)&&\"data\");if(a||\"jsonp\"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,\"$1\"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?\"&\":\"?\")+e.jsonp+\"=\"+r),e.converters[\"script json\"]=function(){return o||S.error(r+\" was not called\"),o[0]},e.dataTypes[0]=\"json\",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),\"script\"}),y.createHTMLDocument=((Ut=E.implementation.createHTMLDocument(\"\").body).innerHTML=\"<form></form><form></form>\",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return\"string\"!=typeof e?[]:(\"boolean\"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument(\"\")).createElement(\"base\")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(\" \");return-1<s&&(r=vt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&\"object\"==typeof t&&(i=\"POST\"),0<a.length&&S.ajax({url:e,type:i||\"GET\",dataType:\"html\",data:t}).done(function(e){o=arguments,a.html(r?S(\"<div>\").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,\"position\"),c=S(e),f={};\"static\"===l&&(e.style.position=\"relative\"),s=c.offset(),o=S.css(e,\"top\"),u=S.css(e,\"left\"),(\"absolute\"===l||\"fixed\"===l)&&-1<(o+u).indexOf(\"auto\")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),\"using\"in t?t.using.call(e,f):(\"number\"==typeof f.top&&(f.top+=\"px\"),\"number\"==typeof f.left&&(f.left+=\"px\"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if(\"fixed\"===S.css(r,\"position\"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&\"static\"===S.css(e,\"position\"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,\"borderTopWidth\",!0),i.left+=S.css(e,\"borderLeftWidth\",!0))}return{top:t.top-i.top-S.css(r,\"marginTop\",!0),left:t.left-i.left-S.css(r,\"marginLeft\",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&\"static\"===S.css(e,\"position\"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:\"pageXOffset\",scrollTop:\"pageYOffset\"},function(t,i){var o=\"pageYOffset\"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each([\"top\",\"left\"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+\"px\":t})}),S.each({Height:\"height\",Width:\"width\"},function(a,s){S.each({padding:\"inner\"+a,content:s,\"\":\"outer\"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||\"boolean\"!=typeof e),i=r||(!0===e||!0===t?\"margin\":\"border\");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf(\"outer\")?e[\"inner\"+a]:e.document.documentElement[\"client\"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body[\"scroll\"+a],r[\"scroll\"+a],e.body[\"offset\"+a],r[\"offset\"+a],r[\"client\"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each([\"ajaxStart\",\"ajaxStop\",\"ajaxComplete\",\"ajaxError\",\"ajaxSuccess\",\"ajaxSend\"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,\"**\"):this.off(t,e||\"**\",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each(\"blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu\".split(\" \"),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Gt=/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if(\"string\"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return(\"number\"===t||\"string\"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?\"\":(e+\"\").replace(Gt,\"\")},\"function\"==typeof define&&define.amd&&define(\"jquery\",[],function(){return S});var Yt=C.jQuery,Qt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Qt),e&&C.jQuery===S&&(C.jQuery=Yt),S},\"undefined\"==typeof e&&(C.jQuery=C.$=S),S});\n",
       "// class to convert the standard JSON representation of a gatenlp\n",
       "// document into something we need here and methods to access the data.\n",
       "var gatenlpDocRep = class {\n",
       "    constructor(jsonstring) {\n",
       "            this.sep = \"║\"\n",
       "            this.sname2types = new Map();\n",
       "            this.snameid2ann = new Map();\n",
       "            this.snametype2ids = new Map();\n",
       "            let bdoc = JSON.parse(jsonstring);\n",
       "            this.text = bdoc[\"text\"];\n",
       "            this.features = bdoc[\"features\"];\n",
       "            if (this.text == null) {\n",
       "                this.text = \"[No proper GATENLP document to show]\";\n",
       "                return;\n",
       "            }\n",
       "            let annsets = bdoc[\"annotation_sets\"];\n",
       "            if (annsets == null) {\n",
       "                return;\n",
       "            }\n",
       "            for (let setname in annsets) {\n",
       "                // console.log(\"Processing setname: \" + setname)\n",
       "                let annset = annsets[setname];\n",
       "                let types4annset = new Set();\n",
       "                let anns4set = annset[\"annotations\"];\n",
       "                for (let [idx, element] of anns4set.entries()) {\n",
       "                    // console.log(\"adding ann: \" + idx + \" / \" + element)\n",
       "                    let annid = element[\"id\"].toString();\n",
       "                    let anntype = element[\"type\"];\n",
       "                    types4annset.add(anntype);\n",
       "                    // let snametype = setname + DocRep.sep + anntype;\n",
       "                    let snametype = setname + this.sep + anntype;\n",
       "                    // console.log(\"Created key \" + snametype)\n",
       "                    let ids4type = this.snametype2ids.get(snametype);\n",
       "                    if (ids4type == null) {\n",
       "                        //console.log(\"Adding \" + [annid])\n",
       "                        this.snametype2ids.set(snametype, [annid]);\n",
       "                        // console.log(\"keys now \" + Array.from(this.snametype2ids.keys()))\n",
       "                    } else {\n",
       "                        ids4type.push(annid);\n",
       "                        // console.log(\"snametype2ids for \" + snametype + \" is now \" + ids4type)\n",
       "                    }\n",
       "                    let snameid = setname + this.sep + annid\n",
       "                    let ann4snameid = this.snameid2ann.get(snameid);\n",
       "                    if (ann4snameid == null) {\n",
       "                        this.snameid2ann.set(snameid, element);\n",
       "                    } else {\n",
       "                        // how to handle this odd error?\n",
       "                    }\n",
       "                }\n",
       "                this.sname2types.set(setname, Array.from(types4annset).sort());\n",
       "            }\n",
       "        } // constructor\n",
       "\n",
       "    setnames() {\n",
       "        return Array.from(this.sname2types.keys()).sort();\n",
       "    }\n",
       "\n",
       "    types4setname(setname) {\n",
       "        // return a sorted list of annotation types for a set name\n",
       "        return Array.from(this.sname2types.get(setname)); // already sorted!\n",
       "    }\n",
       "\n",
       "    annids4snametype(setname, anntype) {\n",
       "        // return a list of annotation ids for a setname and annotation type\n",
       "        return this.snametype2ids.get(setname + this.sep + anntype);\n",
       "    }\n",
       "\n",
       "    ann4setnameannid(setname, annid) {\n",
       "        // return the annotation object (map) for a set/id\n",
       "        return this.snameid2ann.get(setname + this.sep + annid)\n",
       "    }\n",
       "\n",
       "    anns4settype(setname, type) {\n",
       "        //console.log(\"Getting anns for \" + setname + \" \" + type)\n",
       "        let annids = this.annids4snametype(setname, type);\n",
       "        let anns = [];\n",
       "        for (let annid of annids) {\n",
       "            anns[anns.length] = this.ann4setnameannid(setname, annid);\n",
       "        }\n",
       "        //console.log(\"Found \" + annids + \" returning \" + anns);\n",
       "        return anns;\n",
       "    }\n",
       "\n",
       "};\n",
       "\n",
       "function docview_annchosen(rep, ev, setname, anntype) {\n",
       "        let checked = $(ev.target).prop(\"checked\");\n",
       "        // this gives us the setname, type and checkbox status of what has been clicked, but for now\n",
       "        // we always get the complete list of selected types here:\n",
       "        let seltypes = [];\n",
       "        let inputs = $(rep.id_chooser).find(\"input\");\n",
       "        inputs.each(function(index) {\n",
       "            let inputel = $(inputs.get(index));\n",
       "            if (inputel.prop(\"checked\")) {\n",
       "                // seltypes.push(([inputel.attr(\"data-setname\"), inputel.attr(\"data-anntype\")]));\n",
       "                seltypes[seltypes.length] = [inputel.attr(\"data-setname\"), inputel.attr(\"data-anntype\")]\n",
       "            }\n",
       "        });\n",
       "        rep.chosen = seltypes;\n",
       "        rep.buildAnns4Offset();\n",
       "        rep.buildContent();\n",
       "    }\n",
       "\n",
       "function docview_annsel(obj, ev, anns) {\n",
       "        if (anns.size > 1) {\n",
       "            // if there are several annotation, show the popup\n",
       "            $(obj.id_popup).empty();\n",
       "            for (let info of anns.values()) {\n",
       "                let fields = info.split(\"║\")\n",
       "                let setname = fields[0]\n",
       "                let annid = fields[2]                \n",
       "                let ann = obj.docrep.ann4setnameannid(setname, annid);\n",
       "                // console.log(\"Looking up setname=\"+setname+\",annid=\"+annid+\" gave: \"+ann)\n",
       "                let feats = ann.features;\n",
       "                let idpopup = obj.id_popup;\n",
       "                $(\"<div class='\" + obj.class_selection + \"'>\" + ann.type + \": id=\" + annid + \" offsets=\" + ann.start + \"..\" + ann.end + \" (\" + (ann.end-ann.start) + \")\" + \"</div>\").on(\"click\", function(x) {\n",
       "                    docview_showAnn(obj, ann);\n",
       "                    $(idpopup).hide();\n",
       "                }).appendTo(obj.id_popup);\n",
       "            }\n",
       "            $(obj.id_popup).show();            \n",
       "        } else if (anns.size == 1) {\n",
       "            // if there is just one annotation, show features immediately, without the popup\n",
       "            let a = anns.values().next()[\"value\"]\n",
       "            let fields = a.split(\"║\")            \n",
       "            let ann = obj.docrep.ann4setnameannid(fields[0], fields[2]);\n",
       "            docview_showAnn(obj, ann);\n",
       "        } else {\n",
       "            console.error(\"EMPTY ANNS???\");\n",
       "        }\n",
       "    }\n",
       "\n",
       "function docview_showFeatures(obj, features) {\n",
       "        let tbl = $(\"<table>\").attr(\"class\", obj.idprefix+\"featuretable\");\n",
       "        for (let fname in features) {\n",
       "            let fval = JSON.stringify(features[fname]);\n",
       "            tbl.append(\"<tr><td class='\" + obj.class_fname + \"'>\" + fname + \"</td><td class='\" + obj.class_fvalue + \"'>\" + fval + \"</td></tr>\");\n",
       "        }\n",
       "        $(obj.id_details).append(tbl);\n",
       "    }\n",
       "\n",
       "function docview_showAnn(obj, ann) {\n",
       "        $(obj.id_details).empty();\n",
       "        $(obj.id_details).append(\"<div class='\" + obj.id_hdr + \"'>Annotation: \" + ann.type + \", id:\" + ann.id + \" offsets:\" + ann.start + \"..\" + ann.end + \" (\" + (ann.end-ann.start) + \")</div>\");\n",
       "        docview_showFeatures(obj, ann.features);\n",
       "    }\n",
       "\n",
       "function docview_showDocFeatures(obj, features) {\n",
       "        $(obj.id_details).empty();\n",
       "        $(obj.id_details).append(\"<div class='\" + obj.id_hdr + \"'>Document features:</div>\");\n",
       "        docview_showFeatures(obj, features);\n",
       "    }\n",
       "\n",
       "\n",
       "\n",
       "// class to build the HTML for viewing the converted document\n",
       "var gatenlpDocView = class {\n",
       "    constructor(docrep, idprefix=\"GATENLPID-\", config=undefined) {\n",
       "        // idprefix: the prefix to add to all ids and classes\n",
       "        this.sep = \"║\"\n",
       "        this.docrep = docrep;\n",
       "        this.idprefix = idprefix;\n",
       "        this.id_text = \"#\" + idprefix + \"text\";\n",
       "        this.id_chooser = \"#\" + idprefix + \"chooser\";\n",
       "        this.id_details = \"#\" + idprefix + \"details\";\n",
       "        this.id_popup = \"#\" + idprefix + \"popup\";\n",
       "        this.id_hdr = \"#\" + idprefix + \"hdr\";\n",
       "        this.id_dochdr = \"#\" + idprefix + \"dochdr\";\n",
       "        this.class_selection = idprefix + \"selection\";\n",
       "        this.class_fname = idprefix + \"fname\";\n",
       "        this.class_fvalue = idprefix + \"fvalue\";\n",
       "        this.class_label = idprefix + \"label\";\n",
       "        this.class_input = idprefix + \"input\";\n",
       "        this.chosen = [];\n",
       "        this.anns4offset = undefined;\n",
       "        // create default config here\n",
       "        this.config = config;\n",
       "        this.palettex = [\n",
       "            // modified from R lib pals: alphabet2\n",
       "            \"#AA6DAA\", \"#3283FE\", \"#85660D\", \"#782AB6\", \"#565656\", \"#1C8356\", \"#16FF32\", \"#F7E1A0\", \"#E2E2E2\", \"#1CBE4F\", \"#C4451C\", \"#DEA0FD\",\n",
       "            \"#FE00FA\", \"#325A9B\", \"#FEAF16\", \"#F8A19F\", \"#90AD1C\", \"#F6222E\", \"#1CFFCE\", \"#2ED9FF\", \"#B10DA1\", \"#C075A6\", \"#FC1CBF\", \"#B00068\",\n",
       "            \"#FBE426\", \"#FA0087\",\n",
       "            // modified from R lib pals: polychrome\n",
       "            \"#5A5156\", \"#E4E1E3\", \"#F6222E\", \"#FE00FA\", \"#16FF32\", \"#3283FE\", \"#FEAF16\", \"#B00068\", \"#1CFFCE\", \"#90AD1C\",\n",
       "            \"#2ED9FF\", \"#DEA0FD\", \"#AA0DFE\", \"#F8A19F\", \"#325A9B\", \"#C4451C\", \"#1C8356\", \"#85660D\", \"#B10DA1\", \"#FBE426\",\n",
       "            \"#1CBE4F\", \"#FA0087\", \"#FC1CBF\", \"#F7E1A0\", \"#C075A6\", \"#782AB6\", \"#AAF400\", \"#BDCDFF\", \"#822E1C\", \"#B5EFB5\",\n",
       "            \"#7ED7D1\", \"#1C7F93\", \"#D85FF7\", \"#683B79\", \"#66B0FF\", \"#3B00FB\"\n",
       "        ]\n",
       "\n",
       "        function hex2rgba(hx) {\n",
       "            return [\n",
       "                parseInt(hx.substring(1, 3), 16),\n",
       "                parseInt(hx.substring(3, 5), 16),\n",
       "                parseInt(hx.substring(5, 7), 16),\n",
       "                1.0\n",
       "            ];\n",
       "        };\n",
       "        this.palette = this.palettex.map(hex2rgba)\n",
       "        this.type2colour = new Map();\n",
       "    }\n",
       "\n",
       "    style4color(col) {\n",
       "        return \"background-color: rgba(\" + col.join(\",\") + \");\"\n",
       "    }\n",
       "\n",
       "    color4types(atypes) {\n",
       "        // atypes is a list of set┼type┼annid strings\n",
       "        let r = 0;\n",
       "        let g = 0;\n",
       "        let b = 0;\n",
       "        let a = 0;\n",
       "        for (let info of atypes.values()) {\n",
       "            let fields = info.split(this.sep)\n",
       "            let typ = fields[0] + this.sep + fields[1];\n",
       "            let col = this.type2colour.get(typ);\n",
       "            // console.log(\"Looked up color for \"+typ+\" got \"+col)\n",
       "            r += col[0];\n",
       "            g += col[1];\n",
       "            b += col[2];\n",
       "            a += col[3];\n",
       "        }\n",
       "        r = Math.floor(r / atypes.size);\n",
       "        g = Math.floor(g / atypes.size);\n",
       "        b = Math.floor(b / atypes.size);\n",
       "        a = a / atypes.size;\n",
       "        // console.log(\"Final colors for len \"+atypes.size+\" r=\"+r+\" g=\"+g)\n",
       "        return [r, g, b, 1.0];\n",
       "    }\n",
       "\n",
       "    init() {\n",
       "        let divcontent = $(this.id_text);\n",
       "        $(divcontent).empty();\n",
       "        let text = this.docrep.text;\n",
       "        let thehtml = $.parseHTML(this.htmlEntities(text));\n",
       "        $(divcontent).append(thehtml);\n",
       "\n",
       "        // First of all, create the annotation chooser\n",
       "        // create a form which contains:\n",
       "        // for each annotation set create an a tag. followed by a div that contains all the checkbox fields\n",
       "        let divchooser = $(this.id_chooser);\n",
       "        $(divchooser).empty();\n",
       "        let formchooser = $(\"<form>\");\n",
       "        for (let setname of this.docrep.setnames()) {\n",
       "            let setname2show = setname;\n",
       "            // TODO: add number of annotations in the set in parentheses\n",
       "            if (setname == \"\") {\n",
       "                setname2show = \"[Default Set]\"\n",
       "            }\n",
       "            // TODO: make what we show here configurable?\n",
       "            $(formchooser).append($(document.createElement('div')).attr(\"class\", this.id_hdr).append(setname2show))\n",
       "            let div4set = document.createElement(\"div\")\n",
       "            // $(div4set).attr(\"id\", setname);\n",
       "            $(div4set).attr(\"style\", \"margin-bottom: 10px;\");\n",
       "            let colidx = 0\n",
       "            for (let anntype of this.docrep.types4setname(setname)) {\n",
       "                //console.log(\"Addingsss type \" + anntype)\n",
       "                let col = this.palette[colidx];\n",
       "                this.type2colour.set(setname + this.sep + anntype, col);\n",
       "                colidx = (colidx + 1) % this.palette.length;\n",
       "                let lbl = $(\"<label>\").attr({ \"style\": this.style4color(col), \"class\": this.class_label });\n",
       "                let object = this\n",
       "                let annhandler = function(ev) { docview_annchosen(object, ev, setname, anntype) }\n",
       "                let inp = $('<input type=\"checkbox\">').attr({ \"type\": \"checkbox\", \"class\": this.class_input, \"data-anntype\": anntype, \"data-setname\": setname}).on(\"click\", annhandler)\n",
       "\n",
       "                $(lbl).append(inp);\n",
       "                $(lbl).append(anntype);\n",
       "                // append the number of annotations in this set \n",
       "                let n = this.docrep.annids4snametype(setname, anntype).length;\n",
       "                $(lbl).append(\" (\" + n + \")\");\n",
       "                $(div4set).append(lbl)\n",
       "                $(div4set).append($(\"<br>\"))\n",
       "                $(divchooser).append(formchooser)\n",
       "            }\n",
       "            $(formchooser).append(div4set)\n",
       "        }\n",
       "\n",
       "        let obj = this;\n",
       "        let feats = this.docrep[\"features\"];\n",
       "        docview_showDocFeatures(obj, feats);\n",
       "        $(this.id_dochdr).text(\"Document:\").on(\"click\", function(ev) { docview_showDocFeatures(obj, feats) });\n",
       "\n",
       "        this.buildAnns4Offset()\n",
       "        this.buildContent()\n",
       "    }\n",
       "\n",
       "        set2list(theset) {\n",
       "            let arr = new Array()\n",
       "            for (var el of theset.values()) {\n",
       "               arr[arr.length] = el\n",
       "            }\n",
       "            return arr\n",
       "        }\n",
       "\n",
       "        setsequal(set1, set2) {\n",
       "            if (set1.size !== set2.size) return false;\n",
       "            for (var el of set1) if (!set2.has(el)) return false;\n",
       "            return true;\n",
       "        }\n",
       "\n",
       "    buildAnns4Offset() {\n",
       "        // console.log(\"Running buildAnns4Offset\")\n",
       "        //this.anns4offset = new Array(this.docrep.text.length + 1);\n",
       "        this.anns4offset = new Array()\n",
       "        \n",
       "        // for all the set/type combinations that have been selected ... \n",
       "        for (let [sname, atype] of this.chosen) {\n",
       "            //console.log(\"sname/type: \" + sname + \"/\" + atype);\n",
       "            // get the list of annotations that match the given Setname and annotation type\n",
       "            let anns = this.docrep.anns4settype(sname, atype);\n",
       "            for (let ann of anns) {\n",
       "                // console.log(\"processing ann: \" + ann + \" start=\" + ann.start + \" end=\" + ann.end + \" type=\" + ann.type)\n",
       "                // store the annotation setname/typename/annid for each offset of each annotation\n",
       "                // to indicate the end of the annotation also store an empty list for the offset after the annotation \n",
       "                // unless we already have something there\n",
       "                \n",
       "                // trick for zero length annotations: show them as length one annotations for now\n",
       "                var endoff = ann.end\n",
       "                if (ann.start == ann.end) endoff = endoff+1\n",
       "                for (let i = ann.start; i <= endoff; i++) { // iterate until one beyond the end of the ann\n",
       "                    let have = this.anns4offset[i]\n",
       "                    if (have == undefined) {                    \n",
       "                      have = { \"offset\": i, \"anns\": new Set()}\n",
       "                      this.anns4offset[i] = have\n",
       "                    }\n",
       "                    if (i < endoff) {\n",
       "                        // append a new set/type tuple to the list of set/types at this offset\n",
       "                        let tmp = this.anns4offset[i][\"anns\"];\n",
       "                        let toadd = sname + this.sep + atype + this.sep + ann.id\n",
       "                        // console.log(\"Trying to add \"+toadd+\" to \"+this.set2list(tmp))\n",
       "                        tmp = tmp.add(toadd); \n",
       "                        //console.log(\"is now \"+this.set2list(tmp))\n",
       "                        //console.log(\"entry for offset \"+i+\" is now \" + this.set2list(this.anns4offset[i][\"anns\"]));\n",
       "                    }\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "        console.log(\"initial anns4Offset:\")\n",
       "        console.log(this.anns4offset)\n",
       "        // now all offsets have a list of set/type and set/annid tuples\n",
       "        // compress the list to only contain anything but undefined where it changes \n",
       "        let last = this.anns4offset[0]\n",
       "        for (let i = 1; i < this.anns4offset.length; i++) {\n",
       "            let cur = this.anns4offset[i]\n",
       "            if (last == undefined && cur == undefined) {\n",
       "                // console.log(\"Offset \"+i+\" both undefined\")\n",
       "                // nothing to do\n",
       "            } else if (last == undefined && cur != undefined) {\n",
       "                // we have a new list of annotations, keep it: nothing to do\n",
       "                //console.log(\"Offset \"+i+\" last undefined, this one not\")\n",
       "            } else if (last != undefined && cur == undefined) {\n",
       "                // we switch from some list of annotations to the empty list: \n",
       "                // add an empty entry\n",
       "                //console.log(\"Offset \"+i+\" last one not undefined, this undefined, inserting empty list\")\n",
       "                this.anns4offset[i] = { \"anns\": new Set(), \"offset\": i}\n",
       "            } else {\n",
       "                // both offsets have annotations, but do the differ? we need to compare the types and annids\n",
       "                // For now we do this by comparing the stringified representations\n",
       "                let s1 = last[\"anns\"]\n",
       "                let s2 = cur[\"anns\"]\n",
       "                // console.log(\"Offset \"+i+\" Cur: \"+this.set2list(s2)+\" last: \"+this.set2list(s1))\n",
       "                if (this.setsequal(s1,s2)) {\n",
       "                   // console.log(\"Detected equal\")\n",
       "                   this.anns4offset[i] = undefined\n",
       "                }\n",
       "            } \n",
       "            last = cur\n",
       "        }\n",
       "        // for debugging: deep copy the anns4offset data structure so we can later show in the debugger\n",
       "\n",
       "        // console.log(\"compressed anns4Offset:\")\n",
       "        // console.log(this.anns4offset)\n",
       "        \n",
       "    }\n",
       "\n",
       "    buildContent() {\n",
       "        //console.log(\"Running buildContent\");\n",
       "        // got through all the offsets and check where the annotations change\n",
       "        // start with the set of annotations in the first offset (empty if undefined) as lastset, calculate color for set\n",
       "        // go through all subsequent offsets\n",
       "        // when we find an entry where the annotations change:\n",
       "        // * get the annotation setname/types \n",
       "        // * from the list of setname/types, determine a colour and store it\n",
       "        // * generate the span from last to here \n",
       "        // after the end, generate the last span\n",
       "        let spans = []\n",
       "        let last = this.anns4offset[0];\n",
       "        if (last == undefined) {\n",
       "            last = { \"anns\": new Set(), \"offset\": 0 };\n",
       "        }\n",
       "        for (let i = 1; i < this.anns4offset.length; i++) {\n",
       "            let info = this.anns4offset[i];\n",
       "            if (info != undefined) {\n",
       "                let txt = this.docrep.text.substring(last[\"offset\"], info[\"offset\"]);\n",
       "                console.log(\"Got text: \"+txt) \n",
       "                let span = undefined;\n",
       "                if (last[\"anns\"].size != 0) {\n",
       "                    let col = this.color4types(last.anns);\n",
       "                    let sty = this.style4color(col);\n",
       "                    span = $('<span>').attr(\"style\", sty);\n",
       "                    let object = this;\n",
       "                    let anns = last.anns;\n",
       "                    let annhandler = function(ev) { docview_annsel(object, ev, anns) }\n",
       "                    span.on(\"click\", annhandler);\n",
       "                    // console.log(\"Adding styled text for \"+col+\"/\"+sty+\" : \"+txt)                    \n",
       "                } else {\n",
       "                    // console.log(\"Adding non-styled text \"+txt)\n",
       "                    span = $('<span>');\n",
       "                }\n",
       "                span.append($.parseHTML(this.htmlEntities(txt)));\n",
       "                spans.push(span);\n",
       "                last = info;\n",
       "            }\n",
       "        }\n",
       "        let txt = this.docrep.text.substring(last[\"offset\"], this.docrep.text.length);\n",
       "        let span = undefined;\n",
       "        // TODO: if we are already at the end, nothing needs to be done (prevent empty span from being added)\n",
       "        if (last[\"anns\"].length != 0) {\n",
       "            let col = this.color4types(last.anns);\n",
       "            let sty = this.style4color(col);\n",
       "            // span = $('<span>').attr(\"style\", sty).attr(\"data-anns\", last.anns.join(\",\"));\n",
       "            span = $('<span>').attr(\"style\", sty)\n",
       "            let object = this;\n",
       "            let anns = last.anns;\n",
       "            let annhandler = function(ev) { docview_annsel(object, ev, anns) }\n",
       "            span.on(\"click\", annhandler);\n",
       "            // console.log(\"Adding styled text for \"+col+\" : \"+txt)\n",
       "        } else {\n",
       "            // console.log(\"Adding non-styled text \"+txt)\n",
       "            span = $('<span>');\n",
       "        }\n",
       "        span.append($.parseHTML(this.htmlEntities(txt)));\n",
       "        spans.push(span);\n",
       "        // TODO: end\n",
       "        // Replace the content\n",
       "        let divcontent = $(this.id_text);\n",
       "        $(divcontent).empty();\n",
       "        $(divcontent).append(spans);\n",
       "    }\n",
       "\n",
       "    htmlEntities(str) {\n",
       "        return str.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('\"', '&quot;').replaceAll(\"\\n\", '<br>');\n",
       "    }\n",
       "};\n",
       "// console.log(\"Classes defined, defining gatenlp_run\");\n",
       "function gatenlp_run(prefix) {\n",
       "    bdocjson = document.getElementById(prefix+\"data\").innerHTML;\n",
       "    new gatenlpDocView(new gatenlpDocRep(bdocjson), prefix).init();\n",
       "}\n",
       "// console.log(\"Function defined\");\n",
       "</script>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<div><style>#EQHSKKCWIK-wrapper { color: black !important; }</style>\n",
       "<div id=\"EQHSKKCWIK-wrapper\">\n",
       "\n",
       "<div>\n",
       "<style>\n",
       "#EQHSKKCWIK-content {\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-row {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    flex-wrap: nowrap;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-col {\n",
       "    border: 1px solid grey;\n",
       "    display: inline-block;\n",
       "    min-width: 200px;\n",
       "    padding: 5px;\n",
       "    /* white-space: normal; */\n",
       "    /* white-space: pre-wrap; */\n",
       "    overflow-y: auto;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-hdr {\n",
       "    font-size: 1.2rem;\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-label {\n",
       "    margin-bottom: -15px;\n",
       "    display: block;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-input {\n",
       "    vertical-align: middle;\n",
       "    position: relative;\n",
       "    *overflow: hidden;\n",
       "}\n",
       "\n",
       "#EQHSKKCWIK-popup {\n",
       "    display: none;\n",
       "    color: black;\n",
       "    position: absolute;\n",
       "    margin-top: 10%;\n",
       "    margin-left: 10%;\n",
       "    background: #aaaaaa;\n",
       "    width: 60%;\n",
       "    height: 60%;\n",
       "    z-index: 50;\n",
       "    padding: 25px 25px 25px;\n",
       "    border: 1px solid black;\n",
       "    overflow: auto;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-selection {\n",
       "    margin-bottom: 5px;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-featuretable {\n",
       "    margin-top: 10px;\n",
       "}\n",
       "\n",
       ".EQHSKKCWIK-fname {\n",
       "    text-align: left !important;\n",
       "    font-weight: bold;\n",
       "    margin-right: 10px;\n",
       "}\n",
       ".EQHSKKCWIK-fvalue {\n",
       "    text-align: left !important;\n",
       "}\n",
       "</style>\n",
       "  <div id=\"EQHSKKCWIK-content\">\n",
       "        <div id=\"EQHSKKCWIK-popup\" style=\"display: none;\">\n",
       "        </div>\n",
       "        <div class=\"EQHSKKCWIK-row\" id=\"EQHSKKCWIK-row1\" style=\"max-height: 20em; min-height:5em;\">\n",
       "            <div id=\"EQHSKKCWIK-text-wrapper\" class=\"EQHSKKCWIK-col\" style=\"width:70%;\">\n",
       "                <div class=\"EQHSKKCWIK-hdr\" id=\"EQHSKKCWIK-dochdr\"></div>\n",
       "                <div id=\"EQHSKKCWIK-text\">\n",
       "                </div>\n",
       "            </div>\n",
       "            <div id=\"EQHSKKCWIK-chooser\" class=\"EQHSKKCWIK-col\" style=\"width:30%; border-left-width: 0px;\"></div>\n",
       "        </div>\n",
       "        <div class=\"EQHSKKCWIK-row\" id=\"EQHSKKCWIK-row2\" style=\"max-height: 14em; min-height: 3em;\">\n",
       "            <div id=\"EQHSKKCWIK-details\" class=\"EQHSKKCWIK-col\" style=\"width:100%; border-top-width: 0px;\">\n",
       "            </div>\n",
       "        </div>\n",
       "    </div>\n",
       "    \n",
       "    <script type=\"application/json\" id=\"EQHSKKCWIK-data\">\n",
       "    {\"annotation_sets\": {}, \"text\": \"This is a test document.\\n\\nIt contains just a few sentences. \\nHere is a sentence that mentions a few named entities like \\nthe persons Barack Obama or Ursula von der Leyen, locations\\nlike New York City, Vienna or Beijing or companies like \\nGoogle, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\\n\\nLets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\\n\\nHere we include a URL https://gatenlp.github.io/python-gatenlp/ \\nand a fake email address john.doe@hiscoolserver.com as well \\nas #some #cool #hastags and a bunch of emojis like \\ud83d\\ude3d (a kissing cat),\\n\\ud83d\\udc69\\u200d\\ud83c\\udfeb (a woman teacher), \\ud83e\\uddec (DNA), \\n\\ud83e\\uddd7 (a person climbing), \\n\\nHere we test a few different scripts, e.g. Hangul \\ud55c\\uae00 or \\nsimplified Hanzi \\u6c49\\u5b57 or Farsi \\u0641\\u0627\\u0631\\u0633\\u06cc and Arabic ,\\u0627\\u064e\\u0644\\u0652\\u0639\\u064e\\u0631\\u064e\\u0628\\u0650\\u064a\\u064e\\u0651\\u0629\\u064f, which goes from right to left.\\n\\n\", \"features\": {}, \"offset_type\": \"j\", \"name\": \"\"}\n",
       "    </script>\n",
       "    <script type=\"text/javascript\">\n",
       "        gatenlp_run(\"EQHSKKCWIK-\");\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "</div></div>"
      ],
      "text/plain": [
       "Document(This is a test document.\n",
       "\n",
       "It contains just a few sentences. \n",
       "Here is a sentence that mentions a few named entities like \n",
       "the persons Barack Obama or Ursula von der Leyen, locations\n",
       "like New York City, Vienna or Beijing or companies like \n",
       "Google, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\n",
       "\n",
       "Lets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\n",
       "\n",
       "Here we include a URL https://gatenlp.github.io/python-gatenlp/ \n",
       "and a fake email address john.doe@hiscoolserver.com as well \n",
       "as #some #cool #hastags and a bunch of emojis like 😽 (a kissing cat),\n",
       "👩‍🏫 (a woman teacher), 🧬 (DNA), \n",
       "🧗 (a person climbing), \n",
       "\n",
       "Here we test a few different scripts, e.g. Hangul 한글 or \n",
       "simplified Hanzi 汉字 or Farsi فارسی and Arabic ,اَلْعَرَبِيَّةُ, which goes from right to left.\n",
       "\n",
       ",features=Features({}),anns={})"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display\n",
    "display(doc)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "###### We got the same view by calling `doc` at the end of the cell (it can be the only code in the cell)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>#BNOVIKGLSM-wrapper { color: black !important; }</style>\n",
       "<div id=\"BNOVIKGLSM-wrapper\">\n",
       "\n",
       "<div>\n",
       "<style>\n",
       "#BNOVIKGLSM-content {\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-row {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    flex-wrap: nowrap;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-col {\n",
       "    border: 1px solid grey;\n",
       "    display: inline-block;\n",
       "    min-width: 200px;\n",
       "    padding: 5px;\n",
       "    /* white-space: normal; */\n",
       "    /* white-space: pre-wrap; */\n",
       "    overflow-y: auto;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-hdr {\n",
       "    font-size: 1.2rem;\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-label {\n",
       "    margin-bottom: -15px;\n",
       "    display: block;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-input {\n",
       "    vertical-align: middle;\n",
       "    position: relative;\n",
       "    *overflow: hidden;\n",
       "}\n",
       "\n",
       "#BNOVIKGLSM-popup {\n",
       "    display: none;\n",
       "    color: black;\n",
       "    position: absolute;\n",
       "    margin-top: 10%;\n",
       "    margin-left: 10%;\n",
       "    background: #aaaaaa;\n",
       "    width: 60%;\n",
       "    height: 60%;\n",
       "    z-index: 50;\n",
       "    padding: 25px 25px 25px;\n",
       "    border: 1px solid black;\n",
       "    overflow: auto;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-selection {\n",
       "    margin-bottom: 5px;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-featuretable {\n",
       "    margin-top: 10px;\n",
       "}\n",
       "\n",
       ".BNOVIKGLSM-fname {\n",
       "    text-align: left !important;\n",
       "    font-weight: bold;\n",
       "    margin-right: 10px;\n",
       "}\n",
       ".BNOVIKGLSM-fvalue {\n",
       "    text-align: left !important;\n",
       "}\n",
       "</style>\n",
       "  <div id=\"BNOVIKGLSM-content\">\n",
       "        <div id=\"BNOVIKGLSM-popup\" style=\"display: none;\">\n",
       "        </div>\n",
       "        <div class=\"BNOVIKGLSM-row\" id=\"BNOVIKGLSM-row1\" style=\"max-height: 20em; min-height:5em;\">\n",
       "            <div id=\"BNOVIKGLSM-text-wrapper\" class=\"BNOVIKGLSM-col\" style=\"width:70%;\">\n",
       "                <div class=\"BNOVIKGLSM-hdr\" id=\"BNOVIKGLSM-dochdr\"></div>\n",
       "                <div id=\"BNOVIKGLSM-text\">\n",
       "                </div>\n",
       "            </div>\n",
       "            <div id=\"BNOVIKGLSM-chooser\" class=\"BNOVIKGLSM-col\" style=\"width:30%; border-left-width: 0px;\"></div>\n",
       "        </div>\n",
       "        <div class=\"BNOVIKGLSM-row\" id=\"BNOVIKGLSM-row2\" style=\"max-height: 14em; min-height: 3em;\">\n",
       "            <div id=\"BNOVIKGLSM-details\" class=\"BNOVIKGLSM-col\" style=\"width:100%; border-top-width: 0px;\">\n",
       "            </div>\n",
       "        </div>\n",
       "    </div>\n",
       "    \n",
       "    <script type=\"application/json\" id=\"BNOVIKGLSM-data\">\n",
       "    {\"annotation_sets\": {}, \"text\": \"This is a test document.\\n\\nIt contains just a few sentences. \\nHere is a sentence that mentions a few named entities like \\nthe persons Barack Obama or Ursula von der Leyen, locations\\nlike New York City, Vienna or Beijing or companies like \\nGoogle, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\\n\\nLets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\\n\\nHere we include a URL https://gatenlp.github.io/python-gatenlp/ \\nand a fake email address john.doe@hiscoolserver.com as well \\nas #some #cool #hastags and a bunch of emojis like \\ud83d\\ude3d (a kissing cat),\\n\\ud83d\\udc69\\u200d\\ud83c\\udfeb (a woman teacher), \\ud83e\\uddec (DNA), \\n\\ud83e\\uddd7 (a person climbing), \\n\\nHere we test a few different scripts, e.g. Hangul \\ud55c\\uae00 or \\nsimplified Hanzi \\u6c49\\u5b57 or Farsi \\u0641\\u0627\\u0631\\u0633\\u06cc and Arabic ,\\u0627\\u064e\\u0644\\u0652\\u0639\\u064e\\u0631\\u064e\\u0628\\u0650\\u064a\\u064e\\u0651\\u0629\\u064f, which goes from right to left.\\n\\n\", \"features\": {}, \"offset_type\": \"j\", \"name\": \"\"}\n",
       "    </script>\n",
       "    <script type=\"text/javascript\">\n",
       "        gatenlp_run(\"BNOVIKGLSM-\");\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "</div></div>"
      ],
      "text/plain": [
       "Document(This is a test document.\n",
       "\n",
       "It contains just a few sentences. \n",
       "Here is a sentence that mentions a few named entities like \n",
       "the persons Barack Obama or Ursula von der Leyen, locations\n",
       "like New York City, Vienna or Beijing or companies like \n",
       "Google, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\n",
       "\n",
       "Lets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\n",
       "\n",
       "Here we include a URL https://gatenlp.github.io/python-gatenlp/ \n",
       "and a fake email address john.doe@hiscoolserver.com as well \n",
       "as #some #cool #hastags and a bunch of emojis like 😽 (a kissing cat),\n",
       "👩‍🏫 (a woman teacher), 🧬 (DNA), \n",
       "🧗 (a person climbing), \n",
       "\n",
       "Here we test a few different scripts, e.g. Hangul 한글 or \n",
       "simplified Hanzi 汉字 or Farsi فارسی and Arabic ,اَلْعَرَبِيَّةُ, which goes from right to left.\n",
       "\n",
       ",features=Features({}),anns={})"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "There are three areas in this layout:\n",
    "- Upper-left contains the **document text**,\n",
    "- Upper-right lists the **annotation sets** and **annotation types**,\n",
    "- Bottom bar lists the document or annotation **features**. Note: The layout currently shows only the `doc`'s text, since we have not added any features to the document or annotations, yet!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Document features\n",
    "\n",
    "Let's add some ***document* features**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "doc.features[\"loaded_from\"] = \"Local file system.\"\n",
    "import datetime\n",
    "doc.features[\"loading_date\"] = str(datetime.datetime.now())\n",
    "doc.features[\"purpose\"] = \"Testing gatenlp.\"\n",
    "doc.features[\"numeric_value\"] = 22\n",
    "doc.features[\"dict_of_objects\"] = {\"dict_key\": \"dict_value\", \"a_list\": [1,2,3,4,5]}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "scrolled": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "The `document features` maps feature **keys** to feature **values**. It behaves like [Python dictionaries](https://docs.python.org/3/tutorial/datastructures.html#dictionaries). The keys have to be string, the values can be anything as long as they **can be serialized with JSON**, e.g., dictionaries, lists, numbers, strings and booleans. (This is needed for exchanging documents with Java GATE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Now view `doc` with features!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>#CFGPUWWTIL-wrapper { color: black !important; }</style>\n",
       "<div id=\"CFGPUWWTIL-wrapper\">\n",
       "\n",
       "<div>\n",
       "<style>\n",
       "#CFGPUWWTIL-content {\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-row {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    flex-wrap: nowrap;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-col {\n",
       "    border: 1px solid grey;\n",
       "    display: inline-block;\n",
       "    min-width: 200px;\n",
       "    padding: 5px;\n",
       "    /* white-space: normal; */\n",
       "    /* white-space: pre-wrap; */\n",
       "    overflow-y: auto;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-hdr {\n",
       "    font-size: 1.2rem;\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-label {\n",
       "    margin-bottom: -15px;\n",
       "    display: block;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-input {\n",
       "    vertical-align: middle;\n",
       "    position: relative;\n",
       "    *overflow: hidden;\n",
       "}\n",
       "\n",
       "#CFGPUWWTIL-popup {\n",
       "    display: none;\n",
       "    color: black;\n",
       "    position: absolute;\n",
       "    margin-top: 10%;\n",
       "    margin-left: 10%;\n",
       "    background: #aaaaaa;\n",
       "    width: 60%;\n",
       "    height: 60%;\n",
       "    z-index: 50;\n",
       "    padding: 25px 25px 25px;\n",
       "    border: 1px solid black;\n",
       "    overflow: auto;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-selection {\n",
       "    margin-bottom: 5px;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-featuretable {\n",
       "    margin-top: 10px;\n",
       "}\n",
       "\n",
       ".CFGPUWWTIL-fname {\n",
       "    text-align: left !important;\n",
       "    font-weight: bold;\n",
       "    margin-right: 10px;\n",
       "}\n",
       ".CFGPUWWTIL-fvalue {\n",
       "    text-align: left !important;\n",
       "}\n",
       "</style>\n",
       "  <div id=\"CFGPUWWTIL-content\">\n",
       "        <div id=\"CFGPUWWTIL-popup\" style=\"display: none;\">\n",
       "        </div>\n",
       "        <div class=\"CFGPUWWTIL-row\" id=\"CFGPUWWTIL-row1\" style=\"max-height: 20em; min-height:5em;\">\n",
       "            <div id=\"CFGPUWWTIL-text-wrapper\" class=\"CFGPUWWTIL-col\" style=\"width:70%;\">\n",
       "                <div class=\"CFGPUWWTIL-hdr\" id=\"CFGPUWWTIL-dochdr\"></div>\n",
       "                <div id=\"CFGPUWWTIL-text\">\n",
       "                </div>\n",
       "            </div>\n",
       "            <div id=\"CFGPUWWTIL-chooser\" class=\"CFGPUWWTIL-col\" style=\"width:30%; border-left-width: 0px;\"></div>\n",
       "        </div>\n",
       "        <div class=\"CFGPUWWTIL-row\" id=\"CFGPUWWTIL-row2\" style=\"max-height: 14em; min-height: 3em;\">\n",
       "            <div id=\"CFGPUWWTIL-details\" class=\"CFGPUWWTIL-col\" style=\"width:100%; border-top-width: 0px;\">\n",
       "            </div>\n",
       "        </div>\n",
       "    </div>\n",
       "    \n",
       "    <script type=\"application/json\" id=\"CFGPUWWTIL-data\">\n",
       "    {\"annotation_sets\": {}, \"text\": \"This is a test document.\\n\\nIt contains just a few sentences. \\nHere is a sentence that mentions a few named entities like \\nthe persons Barack Obama or Ursula von der Leyen, locations\\nlike New York City, Vienna or Beijing or companies like \\nGoogle, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\\n\\nLets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\\n\\nHere we include a URL https://gatenlp.github.io/python-gatenlp/ \\nand a fake email address john.doe@hiscoolserver.com as well \\nas #some #cool #hastags and a bunch of emojis like \\ud83d\\ude3d (a kissing cat),\\n\\ud83d\\udc69\\u200d\\ud83c\\udfeb (a woman teacher), \\ud83e\\uddec (DNA), \\n\\ud83e\\uddd7 (a person climbing), \\n\\nHere we test a few different scripts, e.g. Hangul \\ud55c\\uae00 or \\nsimplified Hanzi \\u6c49\\u5b57 or Farsi \\u0641\\u0627\\u0631\\u0633\\u06cc and Arabic ,\\u0627\\u064e\\u0644\\u0652\\u0639\\u064e\\u0631\\u064e\\u0628\\u0650\\u064a\\u064e\\u0651\\u0629\\u064f, which goes from right to left.\\n\\n\", \"features\": {\"loaded_from\": \"Local file system.\", \"loading_date\": \"2021-01-17 13:19:10.369383\", \"purpose\": \"Testing gatenlp.\", \"numeric_value\": 22, \"dict_of_objects\": {\"dict_key\": \"dict_value\", \"a_list\": [1, 2, 3, 4, 5]}}, \"offset_type\": \"j\", \"name\": \"\"}\n",
       "    </script>\n",
       "    <script type=\"text/javascript\">\n",
       "        gatenlp_run(\"CFGPUWWTIL-\");\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "</div></div>"
      ],
      "text/plain": [
       "Document(This is a test document.\n",
       "\n",
       "It contains just a few sentences. \n",
       "Here is a sentence that mentions a few named entities like \n",
       "the persons Barack Obama or Ursula von der Leyen, locations\n",
       "like New York City, Vienna or Beijing or companies like \n",
       "Google, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\n",
       "\n",
       "Lets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\n",
       "\n",
       "Here we include a URL https://gatenlp.github.io/python-gatenlp/ \n",
       "and a fake email address john.doe@hiscoolserver.com as well \n",
       "as #some #cool #hastags and a bunch of emojis like 😽 (a kissing cat),\n",
       "👩‍🏫 (a woman teacher), 🧬 (DNA), \n",
       "🧗 (a person climbing), \n",
       "\n",
       "Here we test a few different scripts, e.g. Hangul 한글 or \n",
       "simplified Hanzi 汉字 or Farsi فارسی and Arabic ,اَلْعَرَبِيَّةُ, which goes from right to left.\n",
       "\n",
       ",features=Features({'loaded_from': 'Local file system.', 'loading_date': '2021-01-17 13:19:10.369383', 'purpose': 'Testing gatenlp.', 'numeric_value': 22, 'dict_of_objects': {'dict_key': 'dict_value', 'a_list': [1, 2, 3, 4, 5]}}),anns={})"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Retrieve a feature value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Testing gatenlp.'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "doc.features[\"purpose\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "#### If a feature does not exist, None is returned, or a default value, if specified:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "None\n",
      "NA!\n"
     ]
    }
   ],
   "source": [
    "print(doc.features.get(\"doesntexist\"))\n",
    "print(doc.features.get(\"doesntexist\", \"NA!\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Annotations & Annotation Sets\n",
    "---\n",
    "**Annotations** cover a range of characters within the document. Annotations can overlap arbitrarily and can be created as many as needed.\n",
    "\n",
    "Annotations consist of the following parts:\n",
    "- The **start** and **end** offset which is used for associating the text that the annotation covers,\n",
    "- A **type** which is an arbitrary name that identifies what kind of thing the annotation describes, e.g. \"Token\", \"Person\",\n",
    "- **Features**; these are similar to document features, i.e., an arbitrary set of feature key/value\n",
    "  pairs which provide more information about the annotation, e.g. a Token annotation can include lemma, POS tags, orth. features etc...\n",
    " \n",
    "\n",
    "### Annotations are be organized in ***annotation sets***.  Each annotation set:\n",
    " - Holds a collection of Annotations. \n",
    " - Usually, has a name. Only the defaut one does not have one! \n",
    " - They can be created as many as needed."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Let us manually add a few annotations to the document!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Firstly, create an annotation set with the `annset` method"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# create and get an annotation set with the name \"Set1\"\n",
    "annset = doc.annset(\"Set1\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Add an annotation to the set which refers to the first word in the document \"This\". The range of characters\n",
    "for this word starts at offset 0 and the length of the annotation is 4, so the \"start\" offset is 0 and the \"end\" offset is 0+4=4. End offset always points to the offset *after* the last character of the range."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Annotation(0,4,Annot1,features=Features({'feature1_key': 'feature1_value'}),id=0)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#Now, add an annotation\n",
    "annset.add(0,4,\"Annot1\",{\"feature1_key\": \"feature1_value\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "#### Add more"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# Add some more!\n",
    "annset.add(0,4,\"Token\",{\"kind\": \"token1'\"})\n",
    "annset.add(5,7,\"Token\",{\"kind\": \"token2'\"})\n",
    "annset.add(8,9,\"Token\",{\"kind\": \"token3'\"})\n",
    "annset.add(10,14,\"Token\",{\"kind\": \"token4'\"})\n",
    "annset.add(15,24,\"Token\",{\"kind\": \"token5\"})\n",
    "annset.add(0,24,\"Sentence\",{\"what\": \"The first 'sentence' annotation\"});"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [],
   "source": [
    "# doc.remove_annset(\"Set1\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>#XIFMWSKUDJ-wrapper { color: black !important; }</style>\n",
       "<div id=\"XIFMWSKUDJ-wrapper\">\n",
       "\n",
       "<div>\n",
       "<style>\n",
       "#XIFMWSKUDJ-content {\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-row {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    flex-wrap: nowrap;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-col {\n",
       "    border: 1px solid grey;\n",
       "    display: inline-block;\n",
       "    min-width: 200px;\n",
       "    padding: 5px;\n",
       "    /* white-space: normal; */\n",
       "    /* white-space: pre-wrap; */\n",
       "    overflow-y: auto;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-hdr {\n",
       "    font-size: 1.2rem;\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-label {\n",
       "    margin-bottom: -15px;\n",
       "    display: block;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-input {\n",
       "    vertical-align: middle;\n",
       "    position: relative;\n",
       "    *overflow: hidden;\n",
       "}\n",
       "\n",
       "#XIFMWSKUDJ-popup {\n",
       "    display: none;\n",
       "    color: black;\n",
       "    position: absolute;\n",
       "    margin-top: 10%;\n",
       "    margin-left: 10%;\n",
       "    background: #aaaaaa;\n",
       "    width: 60%;\n",
       "    height: 60%;\n",
       "    z-index: 50;\n",
       "    padding: 25px 25px 25px;\n",
       "    border: 1px solid black;\n",
       "    overflow: auto;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-selection {\n",
       "    margin-bottom: 5px;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-featuretable {\n",
       "    margin-top: 10px;\n",
       "}\n",
       "\n",
       ".XIFMWSKUDJ-fname {\n",
       "    text-align: left !important;\n",
       "    font-weight: bold;\n",
       "    margin-right: 10px;\n",
       "}\n",
       ".XIFMWSKUDJ-fvalue {\n",
       "    text-align: left !important;\n",
       "}\n",
       "</style>\n",
       "  <div id=\"XIFMWSKUDJ-content\">\n",
       "        <div id=\"XIFMWSKUDJ-popup\" style=\"display: none;\">\n",
       "        </div>\n",
       "        <div class=\"XIFMWSKUDJ-row\" id=\"XIFMWSKUDJ-row1\" style=\"max-height: 20em; min-height:5em;\">\n",
       "            <div id=\"XIFMWSKUDJ-text-wrapper\" class=\"XIFMWSKUDJ-col\" style=\"width:70%;\">\n",
       "                <div class=\"XIFMWSKUDJ-hdr\" id=\"XIFMWSKUDJ-dochdr\"></div>\n",
       "                <div id=\"XIFMWSKUDJ-text\">\n",
       "                </div>\n",
       "            </div>\n",
       "            <div id=\"XIFMWSKUDJ-chooser\" class=\"XIFMWSKUDJ-col\" style=\"width:30%; border-left-width: 0px;\"></div>\n",
       "        </div>\n",
       "        <div class=\"XIFMWSKUDJ-row\" id=\"XIFMWSKUDJ-row2\" style=\"max-height: 14em; min-height: 3em;\">\n",
       "            <div id=\"XIFMWSKUDJ-details\" class=\"XIFMWSKUDJ-col\" style=\"width:100%; border-top-width: 0px;\">\n",
       "            </div>\n",
       "        </div>\n",
       "    </div>\n",
       "    \n",
       "    <script type=\"application/json\" id=\"XIFMWSKUDJ-data\">\n",
       "    {\"annotation_sets\": {\"Set1\": {\"name\": \"detached-from:Set1\", \"annotations\": [{\"type\": \"Annot1\", \"start\": 0, \"end\": 4, \"id\": 0, \"features\": {\"feature1_key\": \"feature1_value\"}}, {\"type\": \"Token\", \"start\": 0, \"end\": 4, \"id\": 1, \"features\": {\"kind\": \"token1'\"}}, {\"type\": \"Token\", \"start\": 5, \"end\": 7, \"id\": 2, \"features\": {\"kind\": \"token2'\"}}, {\"type\": \"Token\", \"start\": 8, \"end\": 9, \"id\": 3, \"features\": {\"kind\": \"token3'\"}}, {\"type\": \"Token\", \"start\": 10, \"end\": 14, \"id\": 4, \"features\": {\"kind\": \"token4'\"}}, {\"type\": \"Token\", \"start\": 15, \"end\": 24, \"id\": 5, \"features\": {\"kind\": \"token5\"}}, {\"type\": \"Sentence\", \"start\": 0, \"end\": 24, \"id\": 6, \"features\": {\"what\": \"The first 'sentence' annotation\"}}], \"next_annid\": 7}}, \"text\": \"This is a test document.\\n\\nIt contains just a few sentences. \\nHere is a sentence that mentions a few named entities like \\nthe persons Barack Obama or Ursula von der Leyen, locations\\nlike New York City, Vienna or Beijing or companies like \\nGoogle, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\\n\\nLets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\\n\\nHere we include a URL https://gatenlp.github.io/python-gatenlp/ \\nand a fake email address john.doe@hiscoolserver.com as well \\nas #some #cool #hastags and a bunch of emojis like \\ud83d\\ude3d (a kissing cat),\\n\\ud83d\\udc69\\u200d\\ud83c\\udfeb (a woman teacher), \\ud83e\\uddec (DNA), \\n\\ud83e\\uddd7 (a person climbing), \\n\\nHere we test a few different scripts, e.g. Hangul \\ud55c\\uae00 or \\nsimplified Hanzi \\u6c49\\u5b57 or Farsi \\u0641\\u0627\\u0631\\u0633\\u06cc and Arabic ,\\u0627\\u064e\\u0644\\u0652\\u0639\\u064e\\u0631\\u064e\\u0628\\u0650\\u064a\\u064e\\u0651\\u0629\\u064f, which goes from right to left.\\n\\n\", \"features\": {\"loaded_from\": \"Local file system.\", \"loading_date\": \"2021-01-17 13:19:10.369383\", \"purpose\": \"Testing gatenlp.\", \"numeric_value\": 22, \"dict_of_objects\": {\"dict_key\": \"dict_value\", \"a_list\": [1, 2, 3, 4, 5]}}, \"offset_type\": \"j\", \"name\": \"\"}\n",
       "    </script>\n",
       "    <script type=\"text/javascript\">\n",
       "        gatenlp_run(\"XIFMWSKUDJ-\");\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "</div></div>"
      ],
      "text/plain": [
       "Document(This is a test document.\n",
       "\n",
       "It contains just a few sentences. \n",
       "Here is a sentence that mentions a few named entities like \n",
       "the persons Barack Obama or Ursula von der Leyen, locations\n",
       "like New York City, Vienna or Beijing or companies like \n",
       "Google, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\n",
       "\n",
       "Lets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\n",
       "\n",
       "Here we include a URL https://gatenlp.github.io/python-gatenlp/ \n",
       "and a fake email address john.doe@hiscoolserver.com as well \n",
       "as #some #cool #hastags and a bunch of emojis like 😽 (a kissing cat),\n",
       "👩‍🏫 (a woman teacher), 🧬 (DNA), \n",
       "🧗 (a person climbing), \n",
       "\n",
       "Here we test a few different scripts, e.g. Hangul 한글 or \n",
       "simplified Hanzi 汉字 or Farsi فارسی and Arabic ,اَلْعَرَبِيَّةُ, which goes from right to left.\n",
       "\n",
       ",features=Features({'loaded_from': 'Local file system.', 'loading_date': '2021-01-17 13:19:10.369383', 'purpose': 'Testing gatenlp.', 'numeric_value': 22, 'dict_of_objects': {'dict_key': 'dict_value', 'a_list': [1, 2, 3, 4, 5]}}),anns={'Set1': AnnotationSet([Annotation(0,4,Annot1,features=Features({'feature1_key': 'feature1_value'}),id=0), Annotation(0,4,Token,features=Features({'kind': \"token1'\"}),id=1), Annotation(0,24,Sentence,features=Features({'what': \"The first 'sentence' annotation\"}),id=6), Annotation(5,7,Token,features=Features({'kind': \"token2'\"}),id=2), Annotation(8,9,Token,features=Features({'kind': \"token3'\"}),id=3), Annotation(10,14,Token,features=Features({'kind': \"token4'\"}),id=4), Annotation(15,24,Token,features=Features({'kind': 'token5'}),id=5)])})"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Now, Visualise the document.\n",
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "- To show the features of different annotations click on **the coloured text** in the document.\n",
    "- To show the document features, click on the \"***Document***\" title at the top.\n",
    "- Clicking the overlapping annotations will open a dialog which allows selecting the features of the overlapped annotations."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Gazetteers\n",
    "---\n",
    "***Reminder***: Gazetteers allow matching document text against lists of words."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Firstly, Tokenize the Document"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# tokenize with NLTK tokenizer (doesn't create space token by default)\n",
    "from gatenlp.processing.tokenizer import NLTKTokenizer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Pass NLTKWordTokenizer object to NLTKTokenizer, and run the tokenizer. \n",
    "see the **PyToken** annotation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><style>#EDIBYJDYRP-wrapper { color: black !important; }</style>\n",
       "<div id=\"EDIBYJDYRP-wrapper\">\n",
       "\n",
       "<div>\n",
       "<style>\n",
       "#EDIBYJDYRP-content {\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-row {\n",
       "    width: 100%;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    flex-wrap: nowrap;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-col {\n",
       "    border: 1px solid grey;\n",
       "    display: inline-block;\n",
       "    min-width: 200px;\n",
       "    padding: 5px;\n",
       "    /* white-space: normal; */\n",
       "    /* white-space: pre-wrap; */\n",
       "    overflow-y: auto;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-hdr {\n",
       "    font-size: 1.2rem;\n",
       "    font-weight: bold;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-label {\n",
       "    margin-bottom: -15px;\n",
       "    display: block;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-input {\n",
       "    vertical-align: middle;\n",
       "    position: relative;\n",
       "    *overflow: hidden;\n",
       "}\n",
       "\n",
       "#EDIBYJDYRP-popup {\n",
       "    display: none;\n",
       "    color: black;\n",
       "    position: absolute;\n",
       "    margin-top: 10%;\n",
       "    margin-left: 10%;\n",
       "    background: #aaaaaa;\n",
       "    width: 60%;\n",
       "    height: 60%;\n",
       "    z-index: 50;\n",
       "    padding: 25px 25px 25px;\n",
       "    border: 1px solid black;\n",
       "    overflow: auto;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-selection {\n",
       "    margin-bottom: 5px;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-featuretable {\n",
       "    margin-top: 10px;\n",
       "}\n",
       "\n",
       ".EDIBYJDYRP-fname {\n",
       "    text-align: left !important;\n",
       "    font-weight: bold;\n",
       "    margin-right: 10px;\n",
       "}\n",
       ".EDIBYJDYRP-fvalue {\n",
       "    text-align: left !important;\n",
       "}\n",
       "</style>\n",
       "  <div id=\"EDIBYJDYRP-content\">\n",
       "        <div id=\"EDIBYJDYRP-popup\" style=\"display: none;\">\n",
       "        </div>\n",
       "        <div class=\"EDIBYJDYRP-row\" id=\"EDIBYJDYRP-row1\" style=\"max-height: 20em; min-height:5em;\">\n",
       "            <div id=\"EDIBYJDYRP-text-wrapper\" class=\"EDIBYJDYRP-col\" style=\"width:70%;\">\n",
       "                <div class=\"EDIBYJDYRP-hdr\" id=\"EDIBYJDYRP-dochdr\"></div>\n",
       "                <div id=\"EDIBYJDYRP-text\">\n",
       "                </div>\n",
       "            </div>\n",
       "            <div id=\"EDIBYJDYRP-chooser\" class=\"EDIBYJDYRP-col\" style=\"width:30%; border-left-width: 0px;\"></div>\n",
       "        </div>\n",
       "        <div class=\"EDIBYJDYRP-row\" id=\"EDIBYJDYRP-row2\" style=\"max-height: 14em; min-height: 3em;\">\n",
       "            <div id=\"EDIBYJDYRP-details\" class=\"EDIBYJDYRP-col\" style=\"width:100%; border-top-width: 0px;\">\n",
       "            </div>\n",
       "        </div>\n",
       "    </div>\n",
       "    \n",
       "    <script type=\"application/json\" id=\"EDIBYJDYRP-data\">\n",
       "    {\"annotation_sets\": {\"Set1\": {\"name\": \"detached-from:Set1\", \"annotations\": [{\"type\": \"Annot1\", \"start\": 0, \"end\": 4, \"id\": 0, \"features\": {\"feature1_key\": \"feature1_value\"}}, {\"type\": \"Token\", \"start\": 0, \"end\": 4, \"id\": 1, \"features\": {\"kind\": \"token1'\"}}, {\"type\": \"Token\", \"start\": 5, \"end\": 7, \"id\": 2, \"features\": {\"kind\": \"token2'\"}}, {\"type\": \"Token\", \"start\": 8, \"end\": 9, \"id\": 3, \"features\": {\"kind\": \"token3'\"}}, {\"type\": \"Token\", \"start\": 10, \"end\": 14, \"id\": 4, \"features\": {\"kind\": \"token4'\"}}, {\"type\": \"Token\", \"start\": 15, \"end\": 24, \"id\": 5, \"features\": {\"kind\": \"token5\"}}, {\"type\": \"Sentence\", \"start\": 0, \"end\": 24, \"id\": 6, \"features\": {\"what\": \"The first 'sentence' annotation\"}}], \"next_annid\": 7}, \"\": {\"name\": \"detached-from:\", \"annotations\": [{\"type\": \"PyToken\", \"start\": 0, \"end\": 4, \"id\": 0, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 5, \"end\": 7, \"id\": 1, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 8, \"end\": 9, \"id\": 2, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 10, \"end\": 14, \"id\": 3, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 15, \"end\": 24, \"id\": 4, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 26, \"end\": 28, \"id\": 5, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 29, \"end\": 37, \"id\": 6, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 38, \"end\": 42, \"id\": 7, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 43, \"end\": 44, \"id\": 8, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 45, \"end\": 48, \"id\": 9, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 49, \"end\": 59, \"id\": 10, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 61, \"end\": 65, \"id\": 11, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 66, \"end\": 68, \"id\": 12, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 69, \"end\": 70, \"id\": 13, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 71, \"end\": 79, \"id\": 14, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 80, \"end\": 84, \"id\": 15, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 85, \"end\": 93, \"id\": 16, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 94, \"end\": 95, \"id\": 17, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 96, \"end\": 99, \"id\": 18, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 100, \"end\": 105, \"id\": 19, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 106, \"end\": 114, \"id\": 20, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 115, \"end\": 119, \"id\": 21, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 121, \"end\": 124, \"id\": 22, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 125, \"end\": 132, \"id\": 23, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 133, \"end\": 139, \"id\": 24, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 140, \"end\": 145, \"id\": 25, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 146, \"end\": 148, \"id\": 26, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 149, \"end\": 155, \"id\": 27, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 156, \"end\": 159, \"id\": 28, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 160, \"end\": 163, \"id\": 29, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 164, \"end\": 169, \"id\": 30, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 169, \"end\": 170, \"id\": 31, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 171, \"end\": 180, \"id\": 32, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 181, \"end\": 185, \"id\": 33, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 186, \"end\": 189, \"id\": 34, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 190, \"end\": 194, \"id\": 35, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 195, \"end\": 199, \"id\": 36, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 199, \"end\": 200, \"id\": 37, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 201, \"end\": 207, \"id\": 38, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 208, \"end\": 210, \"id\": 39, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 211, \"end\": 218, \"id\": 40, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 219, \"end\": 221, \"id\": 41, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 222, \"end\": 231, \"id\": 42, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 232, \"end\": 236, \"id\": 43, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 238, \"end\": 244, \"id\": 44, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 244, \"end\": 245, \"id\": 45, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 246, \"end\": 255, \"id\": 46, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 256, \"end\": 258, \"id\": 47, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 259, \"end\": 266, \"id\": 48, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 267, \"end\": 270, \"id\": 49, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 271, \"end\": 275, \"id\": 50, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 276, \"end\": 278, \"id\": 51, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 279, \"end\": 285, \"id\": 52, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 286, \"end\": 291, \"id\": 53, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 291, \"end\": 292, \"id\": 54, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 293, \"end\": 295, \"id\": 55, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 296, \"end\": 299, \"id\": 56, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 300, \"end\": 303, \"id\": 57, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 304, \"end\": 306, \"id\": 58, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 307, \"end\": 310, \"id\": 59, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 311, \"end\": 315, \"id\": 60, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 316, \"end\": 319, \"id\": 61, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 320, \"end\": 321, \"id\": 62, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 321, \"end\": 322, \"id\": 63, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 324, \"end\": 328, \"id\": 64, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 329, \"end\": 332, \"id\": 65, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 333, \"end\": 338, \"id\": 66, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 339, \"end\": 346, \"id\": 67, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 347, \"end\": 350, \"id\": 68, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 351, \"end\": 355, \"id\": 69, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 356, \"end\": 362, \"id\": 70, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 363, \"end\": 367, \"id\": 71, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 368, \"end\": 371, \"id\": 72, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 372, \"end\": 384, \"id\": 73, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 385, \"end\": 392, \"id\": 74, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 392, \"end\": 393, \"id\": 75, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 394, \"end\": 399, \"id\": 76, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 400, \"end\": 402, \"id\": 77, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 403, \"end\": 407, \"id\": 78, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 408, \"end\": 410, \"id\": 79, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 411, \"end\": 416, \"id\": 80, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 417, \"end\": 421, \"id\": 81, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 421, \"end\": 422, \"id\": 82, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 424, \"end\": 428, \"id\": 83, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 429, \"end\": 431, \"id\": 84, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 432, \"end\": 439, \"id\": 85, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 440, \"end\": 441, \"id\": 86, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 442, \"end\": 445, \"id\": 87, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 446, \"end\": 451, \"id\": 88, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 451, \"end\": 452, \"id\": 89, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 452, \"end\": 487, \"id\": 90, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 489, \"end\": 492, \"id\": 91, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 493, \"end\": 494, \"id\": 92, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 495, \"end\": 499, \"id\": 93, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 500, \"end\": 505, \"id\": 94, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 506, \"end\": 513, \"id\": 95, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 514, \"end\": 522, \"id\": 96, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 522, \"end\": 523, \"id\": 97, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 523, \"end\": 540, \"id\": 98, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 541, \"end\": 543, \"id\": 99, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 544, \"end\": 548, \"id\": 100, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 550, \"end\": 552, \"id\": 101, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 553, \"end\": 554, \"id\": 102, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 554, \"end\": 558, \"id\": 103, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 559, \"end\": 560, \"id\": 104, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 560, \"end\": 564, \"id\": 105, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 565, \"end\": 566, \"id\": 106, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 566, \"end\": 573, \"id\": 107, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 574, \"end\": 577, \"id\": 108, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 578, \"end\": 579, \"id\": 109, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 580, \"end\": 585, \"id\": 110, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 586, \"end\": 588, \"id\": 111, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 589, \"end\": 595, \"id\": 112, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 596, \"end\": 600, \"id\": 113, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 601, \"end\": 603, \"id\": 114, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 604, \"end\": 605, \"id\": 115, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 605, \"end\": 606, \"id\": 116, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 607, \"end\": 614, \"id\": 117, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 615, \"end\": 618, \"id\": 118, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 618, \"end\": 619, \"id\": 119, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 619, \"end\": 620, \"id\": 120, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 621, \"end\": 626, \"id\": 121, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 627, \"end\": 628, \"id\": 122, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 628, \"end\": 629, \"id\": 123, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 630, \"end\": 635, \"id\": 124, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 636, \"end\": 643, \"id\": 125, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 643, \"end\": 644, \"id\": 126, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 644, \"end\": 645, \"id\": 127, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 646, \"end\": 648, \"id\": 128, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 649, \"end\": 650, \"id\": 129, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 650, \"end\": 653, \"id\": 130, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 653, \"end\": 654, \"id\": 131, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 654, \"end\": 655, \"id\": 132, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 657, \"end\": 659, \"id\": 133, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 660, \"end\": 661, \"id\": 134, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 661, \"end\": 662, \"id\": 135, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 663, \"end\": 669, \"id\": 136, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 670, \"end\": 678, \"id\": 137, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 678, \"end\": 679, \"id\": 138, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 679, \"end\": 680, \"id\": 139, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 683, \"end\": 687, \"id\": 140, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 688, \"end\": 690, \"id\": 141, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 691, \"end\": 695, \"id\": 142, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 696, \"end\": 697, \"id\": 143, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 698, \"end\": 701, \"id\": 144, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 702, \"end\": 711, \"id\": 145, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 712, \"end\": 719, \"id\": 146, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 719, \"end\": 720, \"id\": 147, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 721, \"end\": 725, \"id\": 148, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 726, \"end\": 732, \"id\": 149, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 733, \"end\": 735, \"id\": 150, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 736, \"end\": 738, \"id\": 151, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 740, \"end\": 750, \"id\": 152, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 751, \"end\": 756, \"id\": 153, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 757, \"end\": 759, \"id\": 154, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 760, \"end\": 762, \"id\": 155, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 763, \"end\": 768, \"id\": 156, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 769, \"end\": 774, \"id\": 157, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 775, \"end\": 778, \"id\": 158, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 779, \"end\": 785, \"id\": 159, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 786, \"end\": 787, \"id\": 160, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 787, \"end\": 802, \"id\": 161, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 802, \"end\": 803, \"id\": 162, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 804, \"end\": 809, \"id\": 163, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 810, \"end\": 814, \"id\": 164, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 815, \"end\": 819, \"id\": 165, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 820, \"end\": 825, \"id\": 166, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 826, \"end\": 828, \"id\": 167, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 829, \"end\": 833, \"id\": 168, \"features\": {}}, {\"type\": \"PyToken\", \"start\": 833, \"end\": 834, \"id\": 169, \"features\": {}}], \"next_annid\": 170}}, \"text\": \"This is a test document.\\n\\nIt contains just a few sentences. \\nHere is a sentence that mentions a few named entities like \\nthe persons Barack Obama or Ursula von der Leyen, locations\\nlike New York City, Vienna or Beijing or companies like \\nGoogle, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\\n\\nLets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\\n\\nHere we include a URL https://gatenlp.github.io/python-gatenlp/ \\nand a fake email address john.doe@hiscoolserver.com as well \\nas #some #cool #hastags and a bunch of emojis like \\ud83d\\ude3d (a kissing cat),\\n\\ud83d\\udc69\\u200d\\ud83c\\udfeb (a woman teacher), \\ud83e\\uddec (DNA), \\n\\ud83e\\uddd7 (a person climbing), \\n\\nHere we test a few different scripts, e.g. Hangul \\ud55c\\uae00 or \\nsimplified Hanzi \\u6c49\\u5b57 or Farsi \\u0641\\u0627\\u0631\\u0633\\u06cc and Arabic ,\\u0627\\u064e\\u0644\\u0652\\u0639\\u064e\\u0631\\u064e\\u0628\\u0650\\u064a\\u064e\\u0651\\u0629\\u064f, which goes from right to left.\\n\\n\", \"features\": {\"loaded_from\": \"Local file system.\", \"loading_date\": \"2021-01-17 13:19:10.369383\", \"purpose\": \"Testing gatenlp.\", \"numeric_value\": 22, \"dict_of_objects\": {\"dict_key\": \"dict_value\", \"a_list\": [1, 2, 3, 4, 5]}}, \"offset_type\": \"j\", \"name\": \"\"}\n",
       "    </script>\n",
       "    <script type=\"text/javascript\">\n",
       "        gatenlp_run(\"EDIBYJDYRP-\");\n",
       "    </script>\n",
       "  </div>\n",
       "\n",
       "</div></div>"
      ],
      "text/plain": [
       "Document(This is a test document.\n",
       "\n",
       "It contains just a few sentences. \n",
       "Here is a sentence that mentions a few named entities like \n",
       "the persons Barack Obama or Ursula von der Leyen, locations\n",
       "like New York City, Vienna or Beijing or companies like \n",
       "Google, UniCredit or Huawei. And here is Donald Trump, it may not be the real one :P\n",
       "\n",
       "Lets say Boris Johnson aka Bojo tweets from his BorisJohnson account, would be nice to match them!\n",
       "\n",
       "Here we include a URL https://gatenlp.github.io/python-gatenlp/ \n",
       "and a fake email address john.doe@hiscoolserver.com as well \n",
       "as #some #cool #hastags and a bunch of emojis like 😽 (a kissing cat),\n",
       "👩‍🏫 (a woman teacher), 🧬 (DNA), \n",
       "🧗 (a person climbing), \n",
       "\n",
       "Here we test a few different scripts, e.g. Hangul 한글 or \n",
       "simplified Hanzi 汉字 or Farsi فارسی and Arabic ,اَلْعَرَبِيَّةُ, which goes from right to left.\n",
       "\n",
       ",features=Features({'loaded_from': 'Local file system.', 'loading_date': '2021-01-17 13:19:10.369383', 'purpose': 'Testing gatenlp.', 'numeric_value': 22, 'dict_of_objects': {'dict_key': 'dict_value', 'a_list': [1, 2, 3, 4, 5]}}),anns={'Set1': AnnotationSet([Annotation(0,4,Annot1,features=Features({'feature1_key': 'feature1_value'}),id=0), Annotation(0,4,Token,features=Features({'kind': \"token1'\"}),id=1), Annotation(0,24,Sentence,features=Features({'what': \"The first 'sentence' annotation\"}),id=6), Annotation(5,7,Token,features=Features({'kind': \"token2'\"}),id=2), Annotation(8,9,Token,features=Features({'kind': \"token3'\"}),id=3), Annotation(10,14,Token,features=Features({'kind': \"token4'\"}),id=4), Annotation(15,24,Token,features=Features({'kind': 'token5'}),id=5)]), '': AnnotationSet([Annotation(0,4,PyToken,features=Features({}),id=0), Annotation(5,7,PyToken,features=Features({}),id=1), Annotation(8,9,PyToken,features=Features({}),id=2), Annotation(10,14,PyToken,features=Features({}),id=3), Annotation(15,24,PyToken,features=Features({}),id=4), Annotation(26,28,PyToken,features=Features({}),id=5), Annotation(29,37,PyToken,features=Features({}),id=6), Annotation(38,42,PyToken,features=Features({}),id=7), Annotation(43,44,PyToken,features=Features({}),id=8), Annotation(45,48,PyToken,features=Features({}),id=9), Annotation(49,59,PyToken,features=Features({}),id=10), Annotation(61,65,PyToken,features=Features({}),id=11), Annotation(66,68,PyToken,features=Features({}),id=12), Annotation(69,70,PyToken,features=Features({}),id=13), Annotation(71,79,PyToken,features=Features({}),id=14), Annotation(80,84,PyToken,features=Features({}),id=15), Annotation(85,93,PyToken,features=Features({}),id=16), Annotation(94,95,PyToken,features=Features({}),id=17), Annotation(96,99,PyToken,features=Features({}),id=18), Annotation(100,105,PyToken,features=Features({}),id=19), Annotation(106,114,PyToken,features=Features({}),id=20), Annotation(115,119,PyToken,features=Features({}),id=21), Annotation(121,124,PyToken,features=Features({}),id=22), Annotation(125,132,PyToken,features=Features({}),id=23), Annotation(133,139,PyToken,features=Features({}),id=24), Annotation(140,145,PyToken,features=Features({}),id=25), Annotation(146,148,PyToken,features=Features({}),id=26), Annotation(149,155,PyToken,features=Features({}),id=27), Annotation(156,159,PyToken,features=Features({}),id=28), Annotation(160,163,PyToken,features=Features({}),id=29), Annotation(164,169,PyToken,features=Features({}),id=30), Annotation(169,170,PyToken,features=Features({}),id=31), Annotation(171,180,PyToken,features=Features({}),id=32), Annotation(181,185,PyToken,features=Features({}),id=33), Annotation(186,189,PyToken,features=Features({}),id=34), Annotation(190,194,PyToken,features=Features({}),id=35), Annotation(195,199,PyToken,features=Features({}),id=36), Annotation(199,200,PyToken,features=Features({}),id=37), Annotation(201,207,PyToken,features=Features({}),id=38), Annotation(208,210,PyToken,features=Features({}),id=39), Annotation(211,218,PyToken,features=Features({}),id=40), Annotation(219,221,PyToken,features=Features({}),id=41), Annotation(222,231,PyToken,features=Features({}),id=42), Annotation(232,236,PyToken,features=Features({}),id=43), Annotation(238,244,PyToken,features=Features({}),id=44), Annotation(244,245,PyToken,features=Features({}),id=45), Annotation(246,255,PyToken,features=Features({}),id=46), Annotation(256,258,PyToken,features=Features({}),id=47), Annotation(259,266,PyToken,features=Features({}),id=48), Annotation(267,270,PyToken,features=Features({}),id=49), Annotation(271,275,PyToken,features=Features({}),id=50), Annotation(276,278,PyToken,features=Features({}),id=51), Annotation(279,285,PyToken,features=Features({}),id=52), Annotation(286,291,PyToken,features=Features({}),id=53), Annotation(291,292,PyToken,features=Features({}),id=54), Annotation(293,295,PyToken,features=Features({}),id=55), Annotation(296,299,PyToken,features=Features({}),id=56), Annotation(300,303,PyToken,features=Features({}),id=57), Annotation(304,306,PyToken,features=Features({}),id=58), Annotation(307,310,PyToken,features=Features({}),id=59), Annotation(311,315,PyToken,features=Features({}),id=60), Annotation(316,319,PyToken,features=Features({}),id=61), Annotation(320,321,PyToken,features=Features({}),id=62), Annotation(321,322,PyToken,features=Features({}),id=63), Annotation(324,328,PyToken,features=Features({}),id=64), Annotation(329,332,PyToken,features=Features({}),id=65), Annotation(333,338,PyToken,features=Features({}),id=66), Annotation(339,346,PyToken,features=Features({}),id=67), Annotation(347,350,PyToken,features=Features({}),id=68), Annotation(351,355,PyToken,features=Features({}),id=69), Annotation(356,362,PyToken,features=Features({}),id=70), Annotation(363,367,PyToken,features=Features({}),id=71), Annotation(368,371,PyToken,features=Features({}),id=72), Annotation(372,384,PyToken,features=Features({}),id=73), Annotation(385,392,PyToken,features=Features({}),id=74), Annotation(392,393,PyToken,features=Features({}),id=75), Annotation(394,399,PyToken,features=Features({}),id=76), Annotation(400,402,PyToken,features=Features({}),id=77), Annotation(403,407,PyToken,features=Features({}),id=78), Annotation(408,410,PyToken,features=Features({}),id=79), Annotation(411,416,PyToken,features=Features({}),id=80), Annotation(417,421,PyToken,features=Features({}),id=81), Annotation(421,422,PyToken,features=Features({}),id=82), Annotation(424,428,PyToken,features=Features({}),id=83), Annotation(429,431,PyToken,features=Features({}),id=84), Annotation(432,439,PyToken,features=Features({}),id=85), Annotation(440,441,PyToken,features=Features({}),id=86), Annotation(442,445,PyToken,features=Features({}),id=87), Annotation(446,451,PyToken,features=Features({}),id=88), Annotation(451,452,PyToken,features=Features({}),id=89), Annotation(452,487,PyToken,features=Features({}),id=90), Annotation(489,492,PyToken,features=Features({}),id=91), Annotation(493,494,PyToken,features=Features({}),id=92), Annotation(495,499,PyToken,features=Features({}),id=93), Annotation(500,505,PyToken,features=Features({}),id=94), Annotation(506,513,PyToken,features=Features({}),id=95), Annotation(514,522,PyToken,features=Features({}),id=96), Annotation(522,523,PyToken,features=Features({}),id=97), Annotation(523,540,PyToken,features=Features({}),id=98), Annotation(541,543,PyToken,features=Features({}),id=99), Annotation(544,548,PyToken,features=Features({}),id=100), Annotation(550,552,PyToken,features=Features({}),id=101), Annotation(553,554,PyToken,features=Features({}),id=102), Annotation(554,558,PyToken,features=Features({}),id=103), Annotation(559,560,PyToken,features=Features({}),id=104), Annotation(560,564,PyToken,features=Features({}),id=105), Annotation(565,566,PyToken,features=Features({}),id=106), Annotation(566,573,PyToken,features=Features({}),id=107), Annotation(574,577,PyToken,features=Features({}),id=108), Annotation(578,579,PyToken,features=Features({}),id=109), Annotation(580,585,PyToken,features=Features({}),id=110), Annotation(586,588,PyToken,features=Features({}),id=111), Annotation(589,595,PyToken,features=Features({}),id=112), Annotation(596,600,PyToken,features=Features({}),id=113), Annotation(601,602,PyToken,features=Features({}),id=114), Annotation(603,604,PyToken,features=Features({}),id=115), Annotation(604,605,PyToken,features=Features({}),id=116), Annotation(606,613,PyToken,features=Features({}),id=117), Annotation(614,617,PyToken,features=Features({}),id=118), Annotation(617,618,PyToken,features=Features({}),id=119), Annotation(618,619,PyToken,features=Features({}),id=120), Annotation(620,623,PyToken,features=Features({}),id=121), Annotation(624,625,PyToken,features=Features({}),id=122), Annotation(625,626,PyToken,features=Features({}),id=123), Annotation(627,632,PyToken,features=Features({}),id=124), Annotation(633,640,PyToken,features=Features({}),id=125), Annotation(640,641,PyToken,features=Features({}),id=126), Annotation(641,642,PyToken,features=Features({}),id=127), Annotation(643,644,PyToken,features=Features({}),id=128), Annotation(645,646,PyToken,features=Features({}),id=129), Annotation(646,649,PyToken,features=Features({}),id=130), Annotation(649,650,PyToken,features=Features({}),id=131), Annotation(650,651,PyToken,features=Features({}),id=132), Annotation(653,654,PyToken,features=Features({}),id=133), Annotation(655,656,PyToken,features=Features({}),id=134), Annotation(656,657,PyToken,features=Features({}),id=135), Annotation(658,664,PyToken,features=Features({}),id=136), Annotation(665,673,PyToken,features=Features({}),id=137), Annotation(673,674,PyToken,features=Features({}),id=138), Annotation(674,675,PyToken,features=Features({}),id=139), Annotation(678,682,PyToken,features=Features({}),id=140), Annotation(683,685,PyToken,features=Features({}),id=141), Annotation(686,690,PyToken,features=Features({}),id=142), Annotation(691,692,PyToken,features=Features({}),id=143), Annotation(693,696,PyToken,features=Features({}),id=144), Annotation(697,706,PyToken,features=Features({}),id=145), Annotation(707,714,PyToken,features=Features({}),id=146), Annotation(714,715,PyToken,features=Features({}),id=147), Annotation(716,720,PyToken,features=Features({}),id=148), Annotation(721,727,PyToken,features=Features({}),id=149), Annotation(728,730,PyToken,features=Features({}),id=150), Annotation(731,733,PyToken,features=Features({}),id=151), Annotation(735,745,PyToken,features=Features({}),id=152), Annotation(746,751,PyToken,features=Features({}),id=153), Annotation(752,754,PyToken,features=Features({}),id=154), Annotation(755,757,PyToken,features=Features({}),id=155), Annotation(758,763,PyToken,features=Features({}),id=156), Annotation(764,769,PyToken,features=Features({}),id=157), Annotation(770,773,PyToken,features=Features({}),id=158), Annotation(774,780,PyToken,features=Features({}),id=159), Annotation(781,782,PyToken,features=Features({}),id=160), Annotation(782,797,PyToken,features=Features({}),id=161), Annotation(797,798,PyToken,features=Features({}),id=162), Annotation(799,804,PyToken,features=Features({}),id=163), Annotation(805,809,PyToken,features=Features({}),id=164), Annotation(810,814,PyToken,features=Features({}),id=165), Annotation(815,820,PyToken,features=Features({}),id=166), Annotation(821,823,PyToken,features=Features({}),id=167), Annotation(824,828,PyToken,features=Features({}),id=168), Annotation(828,829,PyToken,features=Features({}),id=169)])})"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Tokenize the document, lets use an NLTK tokenizer\n",
    "from nltk.tokenize.destructive import NLTKWordTokenizer\n",
    "nltk_tokenizer = NLTKTokenizer(nltk_tokenizer=NLTKWordTokenizer(), out_set=\"\", token_type=\"PyToken\")\n",
    "doc = nltk_tokenizer(doc)\n",
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Now we can use the gazetteer module.\n",
    "`gatenlp.processing.gazetteer` module provides Gazetteer classes.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "from gatenlp.processing.gazetteer import TokenGazetteer"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Let's use an existing Java Gate Gazetteers first\n",
    "\n",
    "The `mp_lists.def` available in the gate-hate app\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# you may need to modify this path\n",
    "gazFile = \"./../../gate-hate-cloud-small/hate-resources/gazetteer/politics/mp_lists.def\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "ename": "FileNotFoundError",
     "evalue": "[Errno 2] No such file or directory: './../../gate-hate-cloud-small/hate-resources/gazetteer/politics/mp_lists.def'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mFileNotFoundError\u001b[0m                         Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-19-fe41e7ae2d19>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mgazetteer\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mTokenGazetteer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgazFile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfmt\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"gate-def\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mall\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mskip\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moutset\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtokentype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m\"PyToken\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m;\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0mdoc\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgazetteer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdoc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m;\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0mdoc\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/data/johann/work-git/python-gatenlp/gatenlp/processing/gazetteer.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, source, fmt, source_sep, source_encoding, cache_source, tokenizer, all, skip, outset, outtype, annset, tokentype, feature, septype, splittype, withintype, mapfunc, ignorefunc, getterfunc, listfeatures, listtype)\u001b[0m\n\u001b[1;32m    170\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlogger\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minit_logger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m__name__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    171\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlogger\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msetLevel\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlogging\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mDEBUG\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 172\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfmt\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mfmt\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlistfeatures\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlistfeatures\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlisttype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mlisttype\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    173\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    174\u001b[0m     def append(\n",
      "\u001b[0;32m/data/johann/work-git/python-gatenlp/gatenlp/processing/gazetteer.py\u001b[0m in \u001b[0;36mappend\u001b[0;34m(self, source, fmt, source_sep, source_encoding, listfeatures, listtype)\u001b[0m\n\u001b[1;32m    218\u001b[0m             \u001b[0;32mif\u001b[0m \u001b[0mlisttype\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    219\u001b[0m                 \u001b[0mlisttype\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mouttype\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 220\u001b[0;31m             \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msource\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"rt\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mencoding\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0msource_encoding\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0minfp\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    221\u001b[0m                 \u001b[0;32mfor\u001b[0m \u001b[0mline\u001b[0m \u001b[0;32min\u001b[0m \u001b[0minfp\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    222\u001b[0m                     \u001b[0mline\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mline\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrstrip\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"\\n\\r\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: './../../gate-hate-cloud-small/hate-resources/gazetteer/politics/mp_lists.def'"
     ]
    }
   ],
   "source": [
    "gazetteer = TokenGazetteer(gazFile, fmt=\"gate-def\", all=True, skip=False, outset=\"\", tokentype=\"PyToken\");\n",
    "doc = gazetteer(doc);\n",
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Display the doc\n",
    "Check newly created annotations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "doc = gazetteer(doc);\n",
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    " # Or, we can create new gazetteers from Python lists "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# Create a gazetteer list in a custom format\n",
    "gazlist = [\n",
    "    (\"Barack Obama\", dict(url=\"https://en.wikipedia.org/wiki/Barack_Obama\", kind=\"name_surname\")),\n",
    "    (\"Obama\", dict(url=\"https://en.wikipedia.org/wiki/Barack_Obama\", kind=\"surname\")),\n",
    "    (\"Donald Trump\", dict(url=\"https://en.wikipedia.org/wiki/Donald_Trump\",kind=\"name_surname\"))\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# Tokenize the strings from our gazetteer list as well\n",
    "def text2tokenstrings(text):\n",
    "    tmpdoc = Document(text)\n",
    "    tmpdoc = nltk_tokenizer(tmpdoc)\n",
    "    tokens = list(tmpdoc.annset().with_type(\"PyToken\"))\n",
    "    return [tmpdoc[tok] for tok in tokens]\n",
    "\n",
    "gazlist = [(text2tokenstrings(txt), feats) for txt, feats in gazlist]\n",
    "gazlist"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Ready to apply the python list as gazetteer to the document"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "gazetteer = TokenGazetteer(gazlist, fmt=\"gazlist\", all=True, skip=False, outset=\"\", outtype=\"PyLookup\",\n",
    "                          annset=\"\", tokentype=\"PyToken\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Display the doc\n",
    " Check ***PyLookup*** annotation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "doc = gazetteer(doc)\n",
    "doc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Loading and saving using various document "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Documents can also be convert to and from a Python-only representation using the methods `doc.to_dict()` and `Document.from_dict(thedict)` which can be used to convert the document for other tools."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# Convert the document to a dictionary representation:\n",
    "as_dict = doc.to_dict()\n",
    "as_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "# Get a copy by creating a new Document from the dictionary representation\n",
    "doc_copy = Document.from_dict(as_dict)\n",
    "doc_copy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Store the document for Java GATE use"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# Save the document in bdocjs format\n",
    "doc.save(\"./data/docPy2Java.bdocjs\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Exhanging annotated files between Python and Java Gate NLP\n",
    "1. Now start Java Gate\n",
    "    - Load BDoc plugin\n",
    "2. Load the `docPy2Java.bdocjs`\n",
    "3. View the annotations\n",
    "4. Add new annotations, you can run Annie (do not forget disable Document Reset)\n",
    "5. Store the modified document, name it to `docJava2Py.bdocjs`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Load the `docJava2Py.bdocjs` document into Python GateNLP"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "jDoc = Document.load(\"./data/docJava2Py.bdocjs\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "jDoc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# GATE and PYTHON\n",
    "---\n",
    "Currently, GATE and Python can, somehow, interact in three ways!\n",
    "\n",
    "1. **Python GateNLP :** COMPLETED!\n",
    "2. **GATE Slave :** A module that enables running almost anything in Java GATE from Python.\n",
    "3. **GATE Python Plugin :** It is GATE a Processing Resource that allows the editing and running python code within the Java GATE."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Part-2 GATE Slave\n",
    "- Allows running the Java GATE process from Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "1. Java and Python interact via a socket connection. \n",
    "2. The Python side sends requests to Java, Java executes the request via Gate NLP then sends the results back to Python.\n",
    "\n",
    "![Dirty Hands](./img/python-gate-interaction_mod.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# import `gateslave` module, also import `json` for loading tweet files."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "import json\n",
    "from gatenlp.gateslave import GateSlaveAnnotator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Create a corpus"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "corpus = []\n",
    "with open(\"./data/tweetGateHate2GateSlave.jsonl\", \"rt\") as infp:\n",
    "    for line in infp:\n",
    "        tweet = json.loads(line)\n",
    "        text=tweet[\"text\"]\n",
    "        if \"full_text\" in tweet:\n",
    "            text= tweet[\"full_text\"]\n",
    "        doc = Document(text)\n",
    "        for fname in [\"id\", \"lang\", \"reply_count\", \"retweet_count\", \"quoted_status_id\"]:\n",
    "            doc.features[fname] = tweet[fname]\n",
    "        corpus.append(doc)\n",
    "print(\"Corpus created, number of documents:\", len(corpus))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "# Show a loaded document, not annotated!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "corpus[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Create a Gate slave object!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "gs_app = GateSlaveAnnotator(pipeline=\"./../../gate-hate-cloud-small/application.xgapp\", \n",
    "                           gatehome=\"/home/memin/gate_developer/GATE_Developer_8.6.1\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "1. `pipeline` parameter should point the location of a Gate **application**\n",
    "2. `gatehome` points the Gate installation folder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "# Send documents to the Java Gate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "gs_app.start()\n",
    "for idx, doc in enumerate(corpus):\n",
    "    doc = gs_app(doc)\n",
    "    corpus[idx] = doc\n",
    "gs_app.finish()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Display the annotated documents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "outputs": [],
   "source": [
    "corpus[0]\n",
    "corpus[1]\n",
    "# corpus[2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# To dig into greater details;\n",
    "visit https://gatenlp.github.io/python-gatenlp/gateslave"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# GATE and PYTHON\n",
    "---\n",
    "Currently, GATE and Python can, somehow, interact in three ways!\n",
    "\n",
    "1. **Python GateNLP :** COMPLETED!\n",
    "2. **GATE Slave :** COMPLETED!\n",
    "3. **GATE Python Plugin :** It is GATE a Processing Resource that allows the editing and running python code within the Java GATE."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Part-3 GATE Python Plugin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "1. GATE Python Plugin is a GATE(Java) processing resource, \n",
    "2. It is called `PythonPr` which allows the editing and running of python code within the GATE. \n",
    "3. The Python API for processing documents is the Python gatenlp package.\n",
    "    - The plugin provides its own copy of a specific version of the gatenlp package which is used by default, but it is possible to instead use whatever version of the gatenlp package is installed on the system.\n",
    "    \n",
    "For more: http://gatenlp.github.io/gateplugin-Python/PythonPr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Requirements:\n",
    "Install a Python version 3.6 or later (3.7 or later highly recommended!), and `sortedcontainers`package.\n",
    "\n",
    "If you haven’t created yet!\n",
    "- First create an environment: `conda create -n gatenlp python=3.9`\n",
    "- To activate it, run: `conda activate gatenlp`\n",
    "- Then install sortedcontainers: `conda install -c conda-forge sortedcontainers`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Loading Python Plugin to the Gate GUI (Gate Developer)\n",
    "-   Requires GATE 8.6.1 or later\n",
    "-   In the CREOLE plugin manager, click the “+” button then enter the following Maven coordinates\n",
    "    - Group: uk.ac.gate.plugins\n",
    "    - Artifact: python\n",
    "    - Version: 2.4-SNAPSHOT"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Now Run the following codes in the Java GATE\n",
    "1. Create an empty python file somewhere.\n",
    "2. Try the codes written below.\n",
    "### PythonPr Init Parameters\n",
    "Parameters that have to get set when the processing resource is created:\n",
    "`pythonProgram` (ResourceReference, default: empty): locate the python source code that you want to run. Use the file selection dialog."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "When a pipeline that contains the  `PythonPr`  processing resource is run, the following main steps are involved:\n",
    "-  The Python program runs in a separate process. \n",
    "- The Python program must:\n",
    "    -   implement a function or callable class that uses the  `@gatenlp.GateNlpPr`  decorator\n",
    "    -   invoke the  `gatenlp.interact()`  function (see examples below)\n",
    "-  The processing resource sends each document to the Python program\n",
    "-  The implemented  `@GateNlpPr`  function or the  `__call__`  method of the implemented  `@GateNlpPr`  class is invoked and the document is passed to that function. \n",
    "- The function can use the  `gatenlp`  API to modify the document. All the changes are recorded.\n",
    "- The recorded changes are sent back to the  `PythonPr`  which applies the changes to the documents in Java GATE."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "Here is a simple example Python program which splits the document into white-space separated tokens using a simple regular expression and creates an annotation with the type “Token” in the default annotation set for each token. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "<code>\n",
    "import re\n",
    "from gatenlp import GateNlpPr, interact\n",
    "\n",
    "@GateNlpPr\n",
    "def run(doc, **kwargs):\n",
    "    set1 = doc.annset()\n",
    "    set1.clear()\n",
    "    text = doc.text\n",
    "    whitespaces = [m for m in re.finditer(r\"[\\s,.!?]+|^[\\s,.!?]*|[\\s,.!?]*$\", text)]\n",
    "    for k in range(len(whitespaces) - 1):\n",
    "        fromoff = whitespaces[k].end()\n",
    "        tooff = whitespaces[k + 1].start()\n",
    "        set1.add(fromoff, tooff, \"Token\", {\"tokennr\": k})\n",
    "    doc.features[\"nr_tokens\"] = len(whitespaces) - 1\n",
    "\n",
    "\n",
    "*interact()* # must be called\n",
    "</code>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "\n",
    "Instead of a function, a callable **class** can be implemented with the `@GateNlpPr`  decorator.\n",
    "- The class must implement the  `__call__`  method, but in addition can also implement the  `start`,  `finish`,  `reduce`  and  `result`  methods. \n",
    "- The following example implements the same tokenizer as above in a class but also counts and prints out the total number of tokens over all documents. Again the  `interact()`  call must be placed at the end of the Python script."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "<code>\n",
    "import re\n",
    "from gatenlp import GateNlpPr, interact, logger\n",
    "\n",
    "@GateNlpPr\n",
    "class MyProcessor:\n",
    "    def __init__(self):\n",
    "        self.tokens_total = 0\n",
    "\n",
    "    def start(self, **kwargs):\n",
    "        self.tokens_total = 0\n",
    "\n",
    "    def finish(self, **kwargs):\n",
    "        logger.info(\"Total number of tokens: {}\".format(self.tokens_total))\n",
    "\n",
    "    def __call__(self, doc, **kwargs):\n",
    "        set1 = doc.annset()\n",
    "        set1.clear()\n",
    "        text = doc.text\n",
    "        whitespaces = [m for m in re.finditer(r\"[\\s,.!?]+|^[\\s,.!?]*|[\\s,.!?]*$\", text)]\n",
    "        nrtokens = len(whitespaces) - 1\n",
    "        for k in range(nrtokens):\n",
    "            fromoff = whitespaces[k].end()\n",
    "            tooff = whitespaces[k + 1].start()\n",
    "            set1.add(fromoff, tooff, \"Token\", {\"tokennr\": k})\n",
    "        doc.features[\"nr_tokens\"] = nrtokens\n",
    "        self.tokens_total += nrtokens\n",
    "\n",
    "interact()\n",
    "</code>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# GATE and PYTHON\n",
    "---\n",
    "Currently, GATE and Python can, somehow, interact in three ways!\n",
    "\n",
    "1. **Python GateNLP :** COMPLETED!\n",
    "2. **GATE Slave :** COMPLETED!\n",
    "3. **GATE Python Plugin :** COMPLETED!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# THANK YOU\n",
    "\n",
    "Now you can dig into https://gatenlp.github.io/python-gatenlp/ to learn more!"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Slideshow",
  "kernelspec": {
   "display_name": "Python (gatenlp-36)",
   "language": "python",
   "name": "gatenlp-36"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.12"
  },
  "rise": {
   "enable_chalkboard": true,
   "rise": {
    "scroll": true
   }
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
